本文共 5659 字,大约阅读时间需要 18 分钟。
首先来看校验相关的一些结构: 1 net_device结构: 包含一个features的域,这个表示设备的一些特性(比如控制校验),下面的几个flag就是用来控制校验: - #define NETIF_F_IP_CSUM 2
- #define NETIF_F_NO_CSUM 4
- #define NETIF_F_HW_CSUM 8
- #define NETIF_F_IPV6_CSUM 16
每个flags的介绍,注释里面都写得很清楚,这里就不一一解释了。这里要注意的是NETIF_F_HW_CSUM,他其实表示在硬件上为所有协议校验。 2 sk_buff: skb->csum和skb->ip_summed这两个域也是与校验相关的,这两个域的含义依赖于skb表示的是一个输入包还是一个输出帧。 当数据包是一个输入包时,skb->csum表示的是当前数据包的4层的checksum值,skb->ip_summed表示的是四层校验的状态,下面的几个宏定义表示了设备驱动传递给4层的一些信息(通过ip_sumed),这里要注意,一旦当四层接受了这个包,他可能会改变ip_summed的值。 -
- #define CHECKSUM_NONE 0
- #define CHECKSUM_UNNECESSARY 1
- #define CHECKSUM_COMPLETE 2
CHECKSUM_NONE表示csum域中的校验值是错误的,也就是校验失败。这里要注意的是,一般来说当2层的校验失败后,驱动会直接丢掉这个包,可是如果输入帧是要被forward的,那么路由器不应该由于一个四层的校验失败而丢掉这个包(路由器不建议查看四层的校验值),它将会将这位置为CHECKSUM_NONE,然后将包发向目的地址,交由目的地址的主机来进行处理。 CHECKSUM_UNNECESSARY表示网卡已经计算和验证了四层的头和校验值。也就是计算了tcp udp的伪头。还有一种情况就是回环,因为在回环中错误发生的概率太低了,因此就不需要计算校验来节省cpu事件。 CHECKSUM_COMPLETE表示nic已经计算了4层头的校验,并且csum已经被赋值,此时4层的接收者只需要加伪头并验证校验结果。 接下来我们来看当数据包是输出包时的情况,此时csum表示为一个指针,它表示硬件网卡存放将要计算的校验值的地址。这个域在输出包时使用,只在校验值在硬件计算的情况下。比如NAT,它会修改ip头,此时就需要重新计算4层的校验值,也就是从4层传递下来的4层校验值需要在底层进行修改。当修改后,我们在底层就可以通过csum来存取这个校验值。 而此时ip_summed可以被设置的值有下面两种: - #define CHECKSUM_NONE 0
- #define CHECKSUM_COMPLETE 2
这时含义就完全不一样了。第一个表示已经计算好了校验值,设备不需要做任何事。 第二个表示4层的伪头的校验已经完毕,并且已经加入到ip头中,此时只需要设备计算整个头4层头的校验值。 主要来看一下ip输入数据包的处理,也就是ip协议处理函数。 具体的协议注册什么的,可以看我前面的blog,这里我们知道处理ip输入的函数是ip_rcv. 先来看下当执行ip_rcv执行之前,sk_buff的结构: - int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
- {
- struct iphdr *iph;
- u32 len;
-
-
- if (skb->pkt_type == PACKET_OTHERHOST)
- goto drop;
-
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INRECEIVES);
-
-
- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
- goto out;
- }
-
-
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
- goto inhdr_error;
-
- iph = ip_hdr(skb);
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (iph->ihl < 5 || iph->version != 4)
- goto inhdr_error;
-
-
- if (!pskb_may_pull(skb, iph->ihl*4))
- goto inhdr_error;
-
- iph = ip_hdr(skb);
-
-
- if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
- goto inhdr_error;
-
- len = ntohs(iph->tot_len);
-
- if (skb->len < len) {
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INTRUNCATEDPKTS);
- goto drop;
- } else if (len < (iph->ihl*4))
-
- goto inhdr_error;
-
-
-
-
-
-
- if (pskb_trim_rcsum(skb, len)) {
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INDISCARDS);
- goto drop;
- }
-
-
- memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
-
-
- return NF_HOOK(PF_INET, NF_INET_PRE_ROUTING, skb, dev, NULL,
- ip_rcv_finish);
-
- inhdr_error:
- IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_INHDRERRORS);
- drop:
- kfree_skb(skb);
- out:
- return NET_RX_DROP;
- }
我们这里先不详细介绍net filter,这里我们只需要知道,在NF_HOOK中,会检测每个包(通过用户空间设置的规则)然后来决定要不要这个数据包通过。最后如果允许的话,就会调用 ip_rcv_finish函数。所以这里我们详细看下 ip_rcv_finish函数: 它主要会做两件事: 1 决定这个包是被传递给高层,还是被forward。 2 解析并执行一些ip option。 - static int ip_rcv_finish(struct sk_buff *skb)
- {
- const struct iphdr *iph = ip_hdr(skb);
- struct rtable *rt;
-
-
-
-
-
-
-
- if (skb->dst == NULL) {
-
- int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
- skb->dev);
- if (unlikely(err)) {
- if (err == -EHOSTUNREACH)
- IP_INC_STATS_BH(dev_net(skb->dev),
- IPSTATS_MIB_INADDRERRORS);
- else if (err == -ENETUNREACH)
- IP_INC_STATS_BH(dev_net(skb->dev),
- IPSTATS_MIB_INNOROUTES);
- goto drop;
- }
- }
-
-
- #ifdef CONFIG_NET_CLS_ROUTE
- if (unlikely(skb->dst->tclassid)) {
- struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
- u32 idx = skb->dst->tclassid;
- st[idx&0xFF].o_packets++;
- st[idx&0xFF].o_bytes+=skb->len;
- st[(idx>>16)&0xFF].i_packets++;
- st[(idx>>16)&0xFF].i_bytes+=skb->len;
- }
- #endif
-
-
-
- if (iph->ihl > 5 && ip_rcv_options(skb))
- goto drop;
- rt = skb->rtable;
- if (rt->rt_type == RTN_MULTICAST)
- IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCASTPKTS);
- else if (rt->rt_type == RTN_BROADCAST)
- IP_INC_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCASTPKTS);
-
-
- return dst_input(skb);
-
- drop:
- kfree_skb(skb);
- return NET_RX_DROP;
- }
转载地址:http://dmobi.baihongyu.com/