深入理解Linux网络技术内幕——IPv4 报文的接收(转发与本地传递)

我们知道,报文经过网卡驱动处理后,调用net_receive_skb传递给具体的协议处理函数,对于IPv4报文来说,其协议处理函数就是ip_rcv了,ip_rcv在进行一些健康检查等操作后,会调用ip_rcv_finish来处理报文。这也是IPv4协议对报文接收处理的开始。

我们先看下ip_rcv_finish源代码:

ip_rcv_finish:

//ip数据报文的主要处理程序(ip_rcv仅仅只是对ip数据报做一些健康性检查)
//ip_rcv_finish 其实是进行路由表查询,,决定报文经过IP层处理后,是继续向上传递,还是进行转发,还是丢弃。
//1.决定报文在本地传递或者转发,如果是转发还需要找到出口设备和下一跳节点
//2.分析和处理一些选项
static int ip_rcv_finish(struct sk_buff *skb)
{
	const struct iphdr *iph = ip_hdr(skb);
	struct rtable *rt;


	/*
	 *	Initialise the virtual path cache for the packet. It describe
	 *	how the packet travels inside Linux networking.
	 *  刚开始没有进行路由表查询,所以还没有相应的路由表项:skb_dst(skb) == NULL。
	 *  则在路由表中查找ip_route_input(),关于内核的路由表
	 */
	if (skb_dst(skb) == NULL) {
		int err = ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,
					 skb->dev); //这里面进行了一些初始化操作,比较重要,与ip报文接下来的走向有关
		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
	//更新traffic cotrol(qos层)所使用的统计数据
	if (unlikely(skb_dst(skb)->tclassid)) {
		struct ip_rt_acct *st = per_cpu_ptr(ip_rt_acct, smp_processor_id());
		u32 idx = skb_dst(skb)->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(skb);  /* skb->dst包含路由信息。根据路由类型更新SNMP统计数据 */
	if (rt->rt_type == RTN_MULTICAST) {
		IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INMCAST,
				skb->len);
	} else if (rt->rt_type == RTN_BROADCAST)
		IP_UPD_PO_STATS_BH(dev_net(rt->u.dst.dev), IPSTATS_MIB_INBCAST,
				skb->len);


	/* 
     * dst_input实际上会调用skb->dst->input(skb).input函数会根据路由信息设置为合适的
     * 函数指针,如果是递交到本地的则为ip_local_deliver,若是转发则为ip_forward.
     * 暂时仅先考虑ip_local_deliver。
     */
	return dst_input(skb);


drop:
	kfree_skb(skb);
	return NET_RX_DROP;
}


ip_route_input会进行路由表查询,该函数直接或间接决定了报文之后要往何处传递。是进行本地传递还是转发。

我们可以看到如果报文没有被drop掉,那么报文最终会被dst_input(skb)处理。dst_input(skb)实际上执行的是skb->dst->input(skb)。而这里的input函数其实就是由ip_route_input决定的。

对于应该本地传递的报文,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值