IP层转发

来源:互联网 发布:2k16科比捏脸数据 编辑:程序博客网 时间:2024/06/04 08:20
//在inet_init时,已经使用dev_add_pack(&ip_packet_type)向ptype_base中注册二层负载//IPv4报文处理回调,当netif_receive_skb进行二层包处理时,会遍历所有ptype_base列//表,找到对应的三层协议,并调用回调进行处理。这里ip_rcv就是IPV4的接收处理回调ip_rcv//如果目地MAC不是自身,则将包丢弃,不是自身通常都是从二层桥转发。if (skb->pkt_type == PACKET_OTHERHOST)goto drop;//如果skb是共享的,则先复制一份,复制失败则丢弃。if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);goto out;//检测当前skb的头部是否有ip头大小的有效空间。if (!pskb_may_pull(skb, sizeof(struct iphdr)))goto inhdr_error;iph = skb->nh.iph;//检测ip头长度是否小于最少20字节,或者不是ipv4版本if (iph->ihl < 5 || iph->version != 4)goto inhdr_error;//检测当前skb的头部是否有ip整个头(可能含ip选项)的有效空间。if (!pskb_may_pull(skb, iph->ihl*4))goto inhdr_error;iph = skb->nh.iph;//进行ip校验和检测if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))goto inhdr_error;//检测整个报文是否小于ip头记载的总长度,或者总长度小于IP头长度len = ntohs(iph->tot_len);if (skb->len < len || len < (iph->ihl*4))goto inhdr_error;//在二层传输时,很可能为了适应二层媒介(比如以太网帧最小必须是64字节)而//填充无效信息。这里检测是否含有填充信息,如果含有则修正skb的tail指向有效//数据的位置,跳过无效的填充。if (pskb_trim_rcsum(skb, len))IP_INC_STATS_BH(IPSTATS_MIB_INDISCARDS);goto drop;//将sky的cb成员清空。memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));//进行netfileter的PRE_ROUTING链处理,这里不分析netfileter,假设没有被//netfilter拦截,则会触发ip_rcv_finish调用。NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,ip_rcv_finish);--------------------------------------------------------------------------------------------------------------------ip_rcv_finish//没有目地对象,先进行路由模块查询,这里暂时先不去了解路由模块的处理机制//仅需要知道,如果路由模块判断出当前报文是单播报文,则将设置接收、发送//回调分别为dst.input= ip_forward//dst.output = ip_outputif (skb->dst == NULL)ip_route_input(skb, iph->daddr, iph->saddr, iph->tos,skb->dev);//如果ip头长度大于20字节,则表示有ip选项,则进行ip选项处理。if (iph->ihl > 5 && ip_rcv_options(skb))goto drop;//调用skb->dst->input回调进行转发处理,这个回调就是在上面ip_route_input中//设置的。如果回调函数的返回值为NET_XMIT_BYPASS,则循环接收处理。dst_input(skb);for (;;)err = skb->dst->input(skb);if (likely(err == 0))return err;if (unlikely(err != NET_XMIT_BYPASS))return err;----------------------------------------------------------------------------------------------------------------------ip_forwardip_options * opt= &(IPCB(skb)->opt);//进行安全策略处理,当前暂不分析if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))goto drop;//如果当前ip报头含有ALTER选项,同时在路由告警链中有对应的条目,则将报文//交给该套接口进行处理,处理成功,则直接返回。if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))return NET_RX_SUCCESS;//目的MAC非自身,则丢弃。if (skb->pkt_type != PACKET_HOST)goto drop;//标记没有进行校验和处理skb->ip_summed = CHECKSUM_NONE;//TTL字段值已经不能再减了,该报文不能再传递了,丢弃。if (skb->nh.iph->ttl <= 1)goto too_many_hops;//安全处理,暂不分析。if (!xfrm4_route_forward(skb))goto drop;rt = (struct rtable*)skb->dst;//当前含有严格源路由选项,但当前目的地和当前出口网关不同,则丢弃。if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway)goto sr_failed;//检测skb从head到data剩余的空间是否还能容纳下二层头加扩展头的长度,如果//不能容下,或者该skb是共享了数据部分,则需要对该skb进行复制扩冲if (skb_cow(skb, LL_RESERVED_SPACE(rt->u.dst.dev)+rt->u.dst.header_len))goto drop;iph = skb->nh.iph;//递减TTL字段ip_decrease_ttl(iph);//如果路由模块处理时标记了有最优路由,同时ip选项中不含严格路由的选项。//则发送重定向的ICMP报文。if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr)ip_rt_send_redirect(skb);//根据报文的TOS字段设置优先级skb->priority = rt_tos2priority(iph->tos);//进行netfileter的FORWARD链处理,这里不分析netfileter,假设没有被//netfilter拦截,则会触发ip_forward_finish调用。NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, rt->u.dst.dev,ip_forward_finish);----------------------------------------------------------------------------------------------------------------------ip_forward_finishopt= &(IPCB(skb)->opt);//有ip选项,则进行转发相关的ip选项处理。if (unlikely(opt->optlen))ip_forward_options(skb);//将报文进行输出处理,当前output回调函数是在ip_route_input中设置。该回调函数//为ip_output,IP层输出后面单独分析。dst_output(skb);skb->dst->output(skb);

0 0