Linux内核分析 - 网络[十一]:ICMP模块
副标题[/!--empirenews.page--]
内核版本:2.6.34 ICMP模块比较简单,要注意的是icmp的速率限制策略,向IP层传输数据ip_append_data()和 ip_push_pending_frames()。 在net/ipv4/af_inet.c中的inet_init()注册icmp协议,从这里也可以看出,ICMP模块是绑 定在IP模块之上的。inet_add_protocol()会将icmp_protocol加入到全局量inet_protos中。 if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) printk(KERN_CRIT "inet_init: Cannot add ICMP protocoln"); icmp_protocol定义如下: static const struct net_protocol icmp_protocol = { .handler = icmp_rcv, .no_policy = 1, .netns_ok = 1, }; 除了注册icmp协议,还要对icmp模块初始化,这部分由icmp_init()完成。 if (icmp_init() < 0) panic("Failed to create the ICMP control socket.n"); icmp_init()函数做的事很简单,register_pernet_subsys(&icmp_sk_ops),而注册icmp网络子系统过程中会调用 icmp_sk_ops.init(即icmp_sk_init函数)来完成它的初始化,下面具体看icmp_sk_init()函数。 首先为net为配CPU数目 (nr_cpu_ids)个struct sock结构体空间,这里的net是全局的网络名,一般是init_inet。 每个CPU i,它的sock结构体位于net中的icmp_sk[i]。于每 个CPU i,初始化刚刚分配的icmp_sk[i]: -第一步,inet_ctl_sock_create()创建sk,并在net->ipv4.icmp_sk[i] = sk中将其赋值给icmp_sk[i]。 -第二步:ICMP发送缓存区大小sk_sndbuf设置为128K for_each_possible_cpu(i) { struct sock *sk; err = inet_ctl_sock_create(&sk, PF_INET, SOCK_RAW, IPPROTO_ICMP, net); if (err < 0) goto fail; net->ipv4.icmp_sk[i] = sk; sk->sk_sndbuf = (2 * ((64 * 1024) + sizeof(struct sk_buff))); sock_set_flag(sk, SOCK_USE_WRITE_QUEUE); inet_sk(sk)->pmtudisc = IP_PMTUDISC_DONT; } 忽略发往广播地址的icmp echo报文;忽略发往广播地址的错误的响应报文; net- >ipv4.sysctl_icmp_echo_ignore_all = 0; net->ipv4.sysctl_icmp_echo_ignore_broadcasts = 1; net->ipv4.sysctl_icmp_ignore_bogus_error_responses = 1; 设置icmp处理速率,这里的ratelimit和ratemask参 数在后面限速处理时会具体用到。 net->ipv4.sysctl_icmp_ratelimit = 1 * HZ; net->ipv4.sysctl_icmp_ratemask = 0x1818; net->ipv4.sysctl_icmp_errors_use_inbound_ifaddr = 0; 初始化工作完成后,还是从icmp的接收开始,icmp_rcv 完成icmp报文的处理。 icmph = icmp_hdr(skb); 根据icmp的类型type交由不同的处理函数去完成。 icmp_pointers[icmph->type].handler(skb); icmp_pointers是在icmp.c中定义的全局量,部分如下: static const struct icmp_control icmp_pointers[NR_ICMP_TYPES + 1] = { [ICMP_ECHOREPLY] = { .handler = icmp_discard, }, [1] = { .handler = icmp_discard, .error = 1, }, …… } 比如对于收到的icmp报文type为0或1(响应答复或目的不可达),协议栈要做的就是丢弃掉它 – icmp_discard()。下 面以icmp echo和icmp timestamp为例说明。 收到icmp echo报文执行icmp_echo() icmp_param是回复时信息,它直接 拷贝了echo的ICMP报头icmp_hdr(skb),仅仅改变了报头的type = ICMP_ECHO_REPLY,然后调用icmp_reply()处理发送。 struct icmp_bxm icmp_param; icmp_param.data.icmph = *icmp_hdr(skb); icmp_param.data.icmph.type = ICMP_ECHOREPLY; icmp_param.skb = skb; icmp_param.offset = 0; icmp_param.data_len = skb->len; icmp_param.head_len = sizeof(struct icmphdr); icmp_reply(&icmp_param, skb); 收到icmp timestamp报文后执行icmp_timestamp() (编辑:应用网_丽江站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |