加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 服务器 > 搭建环境 > Linux > 正文

Linux内核分析 - 网络[十一]:ICMP模块

发布时间:2016-10-16 06:06:59 所属栏目:Linux 来源:站长网
导读:副标题#e# 内核版本:2.6.34 ICMP模块比较简单,要注意的是icmp的速率限制策略,向IP层传输数据ip_append_data()和 ip_push_pending_frames()。 在net/ipv4/af_inet.c中的inet_init()注册icmp协议,从这里也可以看出,ICMP模块是绑 定在IP模块之上的。inet_

通过ip_route_output_key()查找路由信息,存放在rt中。路由项在这里有两个作用:一是限速是 针对每个路由项的,在icmpv4_xrlim_allow()中会用到;二是将报文传递给IP层需要用到rt。仔细观察流程可以发现,报文在协 议栈传递过程中,在IP层会  查找一次路由表获取到了rt,而在这里又查找了一次路由表,似乎是重复了。其实不是,IP层查 找是在报文接收阶段,这里的查找是在报文的发送阶段。

{     
 struct flowi fl = { .nl_u = { .ip4_u =     
    { .daddr = daddr,     
    .saddr = rt->rt_spec_dst,     
    .tos = RT_TOS(ip_hdr(skb)->tos) } },     
    .proto = IPPROTO_ICMP };     
 security_skb_classify_flow(skb, &fl);     
 if (ip_route_output_key(net, &rt, &fl))     
  goto out_unlock;     
}

协议栈对于部分ICMP报文进行了限速,但这种限速不是整体的,而是针对每个路由项的,即限制每个地址发送ICMP报 文的限率。icmpv4_xrlim_allow()判断该icmp报文是否需要被限速,如果能接收,则调用icmp_puash_reply()发送响应。

if (icmpv4_xrlim_allow(net, rt, icmp_param->data.icmph.type,     
      icmp_param->data.icmph.code))     
 icmp_push_reply(icmp_param, &ipc, &rt);

icmpv4_xrlim_allow() -> xrlim_allow() 限速处理

速 率有关的参数是在icmp_init() -> icmp_sk_init()创建ICMP的sock时设置的,ratelimit是限制的速率,即TBF代码段中的 timeout,可以理解成一个令牌;ratemask是被限制速率的ICMP的报文类型,(1 << type & retemask) == 1判断是否 限速,type即ICMP类型,可见默认情况下[3]dest unreachable, [4]source quench, [11]time exceeded, [12]parameter problem才会被限速。

net->ipv4.sysctl_icmp_ratelimit = 1 * HZ;     
net->ipv4.sysctl_icmp_ratemask = 0x1818;

限速使用了Token Bucket Filter(令牌环过滤器)思想,大致是每个 到来的令牌从数据队列中收集一个数据包,然后从桶中删除。令牌被耗尽时,数据包将停止发送一段时间。

ICMP的限速使用 的就是这种思想,不过时间作为令牌,它的增长是连续的;每来一个报文,拿走一个令牌,则是一个时间段timeout,令牌也限 定了最大数目是XRLIM_BURST_FACTOR为6;简单来讲就是每过timeout时间,令牌数就加1,当令牌数达到6时不再增加;而来一 个报文,令牌数就减一,当令牌数为空时,不再减少,该报文也被丢弃;在这种情况下,在过timeout时间,才会处理下一个报 文。实现的代码段如下:

#define XRLIM_BURST_FACTOR 6     
int xrlim_allow(struct dst_entry *dst, int timeout)     
{     
 unsigned long now, token = dst->rate_tokens;     
 int rc = 0;     
         
 now = jiffies;     
 token += now - dst->rate_last;     
 dst->rate_last = now;     
 if (token > XRLIM_BURST_FACTOR * timeout)     
  token = XRLIM_BURST_FACTOR * timeout;     
 if (token >= timeout) {     
  token -= timeout;     
  rc = 1;     
 }     
 dst->rate_tokens = token;     
 return rc;     
}

dst->rate_tokens记录上一次的令牌,dst->rate_last记录上一次访问时间,now – dst->rate_last为经 过的时间即增加的令牌数;当token>=timeout时即至少还有一个令牌,反回rc=1表示仍有令牌,不用限速;否则返回rc=0, 限速。

Linux内核分析 - 网络[十一]:ICMP模块

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

热点阅读