转发步骤:
- 处理IP选项。这可能会涉及记录本地IP地址以及时间戳(如果IP报头中的选项需要这两项信息)
- 确定封包可以被转发(根据IP报头字段)
- 递减IP报头的TTL字段,然后,如果TTL字段变为零,就丢弃该封包
- 根据路径相关MTU,必要时处理分段工作
- 把封包传送至外出设备
如果封包因为某种原因而无法转发,源主机就必须受到ICMP消息,来说明碰到的问题。即使封包会被转发,但是封包绕送时使用的是次佳路径,因而触发了重导向事件时,ICMP消息也会送出,来作为通知。
ip_forward函数:
1: int ip_forward(struct sk_buff *skb)
2: {
3: struct iphdr *iph; /* Our header */
4: struct rtable *rt; /* Route we use */
5: struct ip_options * opt = &(IPCB(skb)->opt);
6:
7: if (skb_warn_if_lro(skb))
8: goto drop;
9:
10: if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb))
11: goto drop;
12:
13: if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb))
14: return NET_RX_SUCCESS;
15:
16: if (skb->pkt_type != PACKET_HOST)
17: goto drop;
18:
19: skb_forward_csum(skb);
20:
21: /*
22: * According to the RFC, we must first decrease the TTL field. If
23: * that reaches zero, we must reply an ICMP control message telling
24: * that the packet's lifetime expired.
25: */
26: if (ip_hdr(skb)->ttl <= 1)
27: goto too_many_hops;
28:
29: if (!xfrm4_route_forward(skb))
30: goto drop;
31:
32: rt = skb_rtable(skb);
33:
34: if (opt->is_strictroute && opt->nexthop != rt->rt_gateway)
35: goto sr_failed;
36:
37: if (unlikely(skb->len > dst_mtu(&rt->dst) && !skb_is_gso(skb) &&
38: (ip_hdr(skb)->frag_off & htons(IP_DF))) && !skb->local_df) {
39: IP_INC_STATS(dev_net(rt->dst.dev), IPSTATS_MIB_FRAGFAILS);
40: icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
41: htonl(dst_mtu(&rt->dst)));
42: goto drop;
43: }
44:
45: /* We are about to mangle packet. Copy it! */
46: if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+rt->dst.header_len))
47: goto drop;
48: iph = ip_hdr(skb);
49:
50: /* Decrease ttl after skb cow done */
51: ip_decrease_ttl(iph);
52:
53: /*
54: * We now generate an ICMP HOST REDIRECT giving the route
55: * we calculated.
56: */
57: if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr && !skb_sec_path(skb))
58: ip_rt_send_redirect(skb);
59:
60: skb->priority = rt_tos2priority(iph->tos);
61:
62: return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD, skb, skb->dev,
63: rt->dst.dev, ip_forward_finish);
64:
65: sr_failed:
66: /*
67: * Strict routing permits no gatewaying
68: */
69: icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);
70: goto drop;
71:
72: too_many_hops:
73: /* Tell the sender its packet died... */
74: IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_INHDRERRORS);
75: icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
76: drop:
77: kfree_skb(skb);
78: return NET_RX_DROP;
79: }
ip_forward_finish函数:
1: static int ip_forward_finish(struct sk_buff *skb)
2: {
3: struct ip_options * opt = &(IPCB(skb)->opt);
4:
5: IP_INC_STATS_BH(dev_net(skb_dst(skb)->dev), IPSTATS_MIB_OUTFORWDATAGRAMS);
6:
7: if (unlikely(opt->optlen))
8: ip_forward_options(skb);
9:
10: return dst_output(skb);
11: }