IP 层收发报文简要剖析6--ip_forward 报文转发
阅读原文时间:2023年07月09日阅读:1

//在函数ip_route_input_slow->ip_mkroute_input注册,
/*
* IP数据包的转发是由ip_forward()处理,该函数在ip_rcv_finish()
* 通过输入路由缓存被调用。
*/
int ip_forward(struct sk_buff *skb)
{
u32 mtu;
struct iphdr *iph; /* Our header */
struct rtable *rt; /* Route we use */
struct ip_options *opt = &(IPCB(skb)->opt);
struct net *net;

/\* that should never happen \*/  
if (skb->pkt\_type != PACKET\_HOST)  
    goto drop;

if (unlikely(skb->sk))  
    goto drop;

if (skb\_warn\_if\_lro(skb))  
    goto drop;

if (!xfrm4\_policy\_check(NULL, XFRM\_POLICY\_FWD, skb))/\*查找ipsec 策略路由\*/  
    goto drop;

if (IPCB(skb)->opt.router\_alert && ip\_call\_ra\_chain(skb))//存在路由警告选项  
    return NET\_RX\_SUCCESS;

skb\_forward\_csum(skb);  
net = dev\_net(skb->dev);

/\*  
 \* According to the RFC, we must first decrease the TTL field. If  
 \* that reaches zero, we must reply an ICMP control message telling  
 \* that the packet's lifetime expired.  
 \*/  
if (ip\_hdr(skb)->ttl <= 1)//ttl 减少了  
    goto too\_many\_hops;

if (!xfrm4\_route\_forward(skb))//ipsec 策略路由转发处理  
    goto drop;

rt = skb\_rtable(skb);

if (opt->is\_strictroute && rt->rt\_uses\_gateway)//如果数据包启用了严格路由处理,且下一跳不是网关  
    goto sr\_failed;//发送ICMP\_SR\_FAILED icmp

IPCB(skb)->flags |= IPSKB\_FORWARDED;  
mtu = ip\_dst\_mtu\_maybe\_forward(&rt->dst, true);  
if (ip\_exceeds\_mtu(skb, mtu)) {  
    IP\_INC\_STATS(net, IPSTATS\_MIB\_FRAGFAILS);  
    icmp\_send(skb, ICMP\_DEST\_UNREACH, ICMP\_FRAG\_NEEDED,  
          htonl(mtu));  
    goto drop;  
}

/\* We are about to mangle packet. Copy it! 确保空间足够\*/  
if (skb\_cow(skb, LL\_RESERVED\_SPACE(rt->dst.dev)+rt->dst.header\_len))  
    goto drop;  
iph = ip\_hdr(skb);

/\* Decrease ttl after skb cow done \*/  
ip\_decrease\_ttl(iph);

/\*  
 \* We now generate an ICMP HOST REDIRECT giving the route  
 \* we calculated.  
 \*/  
if (IPCB(skb)->flags & IPSKB\_DOREDIRECT && !opt->srr &&  
    !skb\_sec\_path(skb))  
    ip\_rt\_send\_redirect(skb);//数据报文输出路由存在重定向标志,且该数据报中不存在源路由选项,就发送重定向icmp报文

skb->priority = rt\_tos2priority(iph->tos);

return NF\_HOOK(NFPROTO\_IPV4, NF\_INET\_FORWARD,  
           net, NULL, skb, skb->dev, rt->dst.dev,  
           ip\_forward\_finish);

sr_failed:
/*
* Strict routing permits no gatewaying
*/
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);
goto drop;

too_many_hops:
/* Tell the sender its packet died… */
__IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
drop:
kfree_skb(skb);
return NET_RX_DROP;
}
static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{
struct ip_options *opt = &(IPCB(skb)->opt);

\_\_IP\_INC\_STATS(net, IPSTATS\_MIB\_OUTFORWDATAGRAMS);  
\_\_IP\_ADD\_STATS(net, IPSTATS\_MIB\_OUTOCTETS, skb->len);

if (unlikely(opt->optlen))  
    ip\_forward\_options(skb);//IP数据报文选项 记录路由选项 时间戳等

return dst\_output(net, sk, skb);//指向ip\_output ip\_mc\_output  

}

ip_forward

手机扫一扫

移动阅读更方便

阿里云服务器
腾讯云服务器
七牛云服务器