1. 程式人生 > >學習Linux-4.12核心網路協議棧(3.1)——網路層的收包處理

學習Linux-4.12核心網路協議棧(3.1)——網路層的收包處理

現在我們將進入傳輸層的分析:

在前面我們知道,資料包到達介面層的時候,它會根據ptype_base來查詢包的型別,並根據包的型別交給不同的網路層函式處理,比如ip_recv,icmp_recv等,現在我們就來看看網路層是怎麼處理不同型別的包的:


1. IP私有資訊控制塊

 40 struct inet_skb_parm {
 41     int         iif;
 42     struct ip_options   opt;        /* Compiled IP options      */ IP頭部的選項都存放在這裡
 43     u16         flags;
 44
 45 #define IPSKB_FORWARDED     BIT(0)
 46 #define IPSKB_XFRM_TUNNEL_SIZE  BIT(1)
 47 #define IPSKB_XFRM_TRANSFORMED  BIT(2)
 48 #define IPSKB_FRAG_COMPLETE BIT(3)
 49 #define IPSKB_REROUTED      BIT(4)
 50 #define IPSKB_DOREDIRECT    BIT(5)
 51 #define IPSKB_FRAG_PMTU     BIT(6)
 52 #define IPSKB_L3SLAVE       BIT(7)
 53
 54     u16         frag_max_size;
 55 };

2. ip_rcv

404 /*
405  *  Main IP Receive routine.
406  */
407 int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
408 {
409     const struct iphdr *iph; //用於操作IP頭部
410     struct net *net;
411     u32 len;
412
413     /* When the interface is in promisc. mode, drop all the crap
414      * that it receives, do not try to analyse it.
415      */
416     if (skb->pkt_type == PACKET_OTHERHOST) //丟掉不是去往本地的包,比如在抓包模式下有很多包不是到本地的
417         goto drop;
418
419
420     net = dev_net(dev);//獲取網路空間
421     __IP_UPD_PO_STATS(net, IPSTATS_MIB_IN, skb->len);
422
423     skb = skb_share_check(skb, GFP_ATOMIC); //如果資料包是一個共享資料包,則需要複製一個備份在作進一步處理,以免在處理過程中資料被修改
424     if (!skb) {
425         __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS);
426         goto out;
427     }
428
429     if (!pskb_may_pull(skb, sizeof(struct iphdr)))//通過資料包長度判斷資料包是否有效,不能小於IP首部長度
430         goto inhdr_error;
431
432     iph = ip_hdr(skb); //獲取IP首部
434     /*
435      *  RFC1122: 3.2.1.2 MUST silently discard any IP frame that fails the checksum.
436      *
437      *  Is the datagram acceptable?
438      *
439      *  1.  Length at least the size of an ip header
440      *  2.  Version of 4
441      *  3.  Checksums correctly. [Speed optimisation for later, skip loopback checksums]
442      *  4.  Doesn't have a bogus length
443      */
444
445     if (iph->ihl < 5 || iph->version != 4) //IP首部至少20個bit,也就是說至少要2的5次方32才能放下,如果小於5說明頭部不對;協議版本號是IPV4
446         goto inhdr_error;
447
448     BUILD_BUG_ON(IPSTATS_MIB_ECT1PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_1);
449     BUILD_BUG_ON(IPSTATS_MIB_ECT0PKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_ECT_0);
450     BUILD_BUG_ON(IPSTATS_MIB_CEPKTS != IPSTATS_MIB_NOECTPKTS + INET_ECN_CE);
451     __IP_ADD_STATS(net,
452                IPSTATS_MIB_NOECTPKTS + (iph->tos & INET_ECN_MASK),
453                max_t(unsigned short, 1, skb_shinfo(skb)->gso_segs));
454
455     if (!pskb_may_pull(skb, iph->ihl*4)) //根據首部長度檢測資料包是否有效
456         goto inhdr_error;
457
458     iph = ip_hdr(skb);
459
460     if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))//檢測首部的校驗和是否有效
461         goto csum_error;
463     len = ntohs(iph->tot_len);
464     if (skb->len < len) {  //根據IP頭部的總長度檢測資料包是否有效
465         __IP_INC_STATS(net, IPSTATS_MIB_INTRUNCATEDPKTS);
466         goto drop;
467     } else if (len < (iph->ihl*4))
468         goto inhdr_error;
469
470     /* Our transport medium may have padded the buffer out. Now we know it
471      * is IP we can trim to the true length of the frame.
472      * Note this now means skb->len holds ntohs(iph->tot_len).
473      */
474     if (pskb_trim_rcsum(skb, len)) {  //根據IP資料首部的總長度重新設定skb的長度
475         __IP_INC_STATS(net, IPSTATS_MIB_INDISCARDS);
476         goto drop;
477     }
478
479     skb->transport_header = skb->network_header + iph->ihl*4;
480
481     /* Remove any debris in the socket control block */
482     memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
483     IPCB(skb)->iif = skb->skb_iif;//將skb中的IP控制塊清0,以便後續對IP選項的處理
484
485     /* Must drop socket now because of tproxy. */
486     skb_orphan(skb);
/*
首先呼叫skb_orphan把skb孤立,使它跟傳送socket和協議棧不再有任何聯絡,也即對本機來說, **這個skb的資料內容已經發送出去了,而skb相當於已經被釋放掉了。對於環回裝置介面來說, **資料的傳送工作至此已經全部完成,接下來,只要把這個實際上還未被釋放的skb傳回給協議棧 **的接收函式即可。 487 488     return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, //通過netfilter處理函式呼叫ip_rcv_finish 489                net, NULL, skb, dev, NULL, 490                ip_rcv_finish); 491 492 csum_error: 493     __IP_INC_STATS(net, IPSTATS_MIB_CSUMERRORS); 494 inhdr_error: 495     __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS); 496 drop: 497     kfree_skb(skb); 498 out: 499     return NET_RX_DROP; 500 }

3. ip_rcv_finish
311 static int ip_rcv_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
312 {
313     const struct iphdr *iph = ip_hdr(skb); //獲取IP頭部
314     struct rtable *rt; //管理路由表
315     struct net_device *dev = skb->dev;  //獲取網路裝置資訊
316     void (*edemux)(struct sk_buff *skb); 
317
318     /* if ingress device is enslaved to an L3 master device pass the
319      * skb to its handler for processing
320      */
321     skb = l3mdev_ip_rcv(skb); //如果這個包隸屬於第三層主裝置,則交給第三層,並且將SKB設成NULL
322     if (!skb) //如果交給了第三層,則return
323         return NET_RX_SUCCESS;
324
325     if (net->ipv4.sysctl_ip_early_demux &&
326         !skb_dst(skb) &&
327         !skb->sk &&
328         !ip_is_fragment(iph)) {
329         const struct net_protocol *ipprot; //獲取協議型別
330         int protocol = iph->protocol;
331
332         ipprot = rcu_dereference(inet_protos[protocol]);
333         if (ipprot && (edemux = READ_ONCE(ipprot->early_demux))) {
334             edemux(skb);
335             /* must reload iph, skb->head might have changed */
336             iph = ip_hdr(skb);
337         }
338     }
340     /*
341      *  Initialise the virtual path cache for the packet. It describes
342      *  how the packet travels inside Linux networking.
343      */
344     if (!skb_valid_dst(skb)) { //如果還沒為該資料查詢路由快取,則呼叫下列函式為其查詢,如果查詢失敗則丟棄該報文
345         int err = ip_route_input_noref(skb, iph->daddr, iph->saddr,
346                            iph->tos, dev);
347         if (unlikely(err)) {
348             if (err == -EXDEV)
349                 __NET_INC_STATS(net, LINUX_MIB_IPRPFILTER);
350             goto drop;
351         }
352     }
353
354 #ifdef CONFIG_IP_ROUTE_CLASSID  //與路由表classifier相關
355     if (unlikely(skb_dst(skb)->tclassid)) {
356         struct ip_rt_acct *st = this_cpu_ptr(ip_rt_acct);
357         u32 idx = skb_dst(skb)->tclassid;
358         st[idx&0xFF].o_packets++;
359         st[idx&0xFF].o_bytes += skb->len;
360         st[(idx>>16)&0xFF].i_packets++;
361         st[(idx>>16)&0xFF].i_bytes += skb->len;
362     }
363 #endif
364
365     if (iph->ihl > 5 && ip_rcv_options(skb))//判斷IP首部是否有option,如果有則呼叫option處理函式
366         goto drop;
367
368     rt = skb_rtable(skb);
369     if (rt->rt_type == RTN_MULTICAST) {
370         __IP_UPD_PO_STATS(net, IPSTATS_MIB_INMCAST, skb->len);
371     } else if (rt->rt_type == RTN_BROADCAST) {
372         __IP_UPD_PO_STATS(net, IPSTATS_MIB_INBCAST, skb->len);
373     } else if (skb->pkt_type == PACKET_BROADCAST ||
374            skb->pkt_type == PACKET_MULTICAST) {
375         struct in_device *in_dev = __in_dev_get_rcu(dev);
376
377         /* RFC 1122 3.3.6:
378          *
379          *   When a host sends a datagram to a link-layer broadcast
380          *   address, the IP destination address MUST be a legal IP
381          *   broadcast or IP multicast address.
382          *
383          *   A host SHOULD silently discard a datagram that is received
384          *   via a link-layer broadcast (see Section 2.4) but does not
385          *   specify an IP multicast or broadcast destination address.
386          *
387          * This doesn't explicitly say L2 *broadcast*, but broadcast is
388          * in a way a form of multicast and the most common use case for
389          * this is 802.11 protecting against cross-station spoofing (the
390          * so-called "hole-196" attack) so do it for both.
391          */
392         if (in_dev &&
393             IN_DEV_ORCONF(in_dev, DROP_UNICAST_IN_L2_MULTICAST))
394             goto drop;
395     }
396
397     return dst_input(skb); //根據路由快取將資料包交給本地處理還是轉發出去,本地處理將呼叫ip_local_deliver,如果要轉發出去則呼叫ip_forward
399 drop:
400     kfree_skb(skb);
401     return NET_RX_DROP;
402 }

4. ip_local_deliver
242 /*
243  *  Deliver IP Packets to the higher protocol layers.
244  */
245 int ip_local_deliver(struct sk_buff *skb)
246 {
247     /*
248      *  Reassemble IP fragments.
249      */
250     struct net *net = dev_net(skb->dev); //獲取網路空間
251
252     if (ip_is_fragment(ip_hdr(skb))) { //如果收到的是分片包,則呼叫ip_defrag進行重組,對應的標示是IP_DEFRAG_LOCAL_DELIVER
253         if (ip_defrag(net, skb, IP_DEFRAG_LOCAL_DELIVER)) 
254             return 0;  //如果返回0表示分片尚未到齊,重組沒有完成
255     }
256
257     return NF_HOOK(NFPROTO_IPV4, NF_INET_LOCAL_IN,
258                net, NULL, skb, skb->dev, NULL,
259                ip_local_deliver_finish);  //如果重組完成,則呼叫ip_local_deliver_finish將組裝完成的資料包交給傳輸層處理
260 }

5. ip_local_deliver_finish

呼叫這個函式後,資料包的處理結果有三種:交給raw套接字處理,交給傳輸層處理,因異常而被丟棄

192 static int ip_local_deliver_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
193 {
194     __skb_pull(skb, skb_network_header_len(skb));  //在交給傳輸層之前先去掉IP頭部
195
196     rcu_read_lock();
197     { 
198         int protocol = ip_hdr(skb)->protocol; //獲取傳輸層協議號,用於計算雜湊值
199         const struct net_protocol *ipprot;
200         int raw;
201
202     resubmit:
203         raw = raw_local_deliver(skb, protocol); //根據protocol得到雜湊值,然後檢視raw_v4_htable散列表中以該值為關鍵字
 的雜湊桶是否為空。如果不為空,則說明建立了RAW套介面,複製該資料包的副本輸入到註冊該桶中的所有套介面
205         ipprot = rcu_dereference(inet_protos[protocol]);//查詢inet_protos陣列中是否註冊了與IP首部中傳輸層協議號一致的
傳輸層協議。如果查詢命中則呼叫對應的傳輸層接收函式
 206         if (ipprot) {
207             int ret;
208
209             if (!ipprot->no_policy) {
210                 if (!xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) { //資料包安全策略檢測,與ipsec相關
211                     kfree_skb(skb);
212                     goto out;
213                 }
214                 nf_reset(skb);
215             }
216             ret = ipprot->handler(skb); //這個是傳輸層的接收函式,包括tcp_protocol, udp_protocol, icmp_protocol
217             if (ret < 0) {
218                 protocol = -ret;
219                 goto resubmit;
220             }
221             __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);
222         } else {
223             if (!raw) {
224                 if (xfrm4_policy_check(NULL, XFRM_POLICY_IN, skb)) {
225                     __IP_INC_STATS(net, IPSTATS_MIB_INUNKNOWNPROTOS);
226                     icmp_send(skb, ICMP_DEST_UNREACH,   //如果raw套接字沒有接收或者接收異常,則傳送一個協議不可達的報文給對方
227                           ICMP_PROT_UNREACH, 0);
228                 }
229                 kfree_skb(skb); //釋放該報文。
230             } else {
231                 __IP_INC_STATS(net, IPSTATS_MIB_INDELIVERS);
232                 consume_skb(skb);  //如果沒有相應的傳輸層協議接收該報文,則釋放該報文。
233             }
234         }
235     }
236  out:
237     rcu_read_unlock();
238
239     return 0;
240 }

 

6. ip_forward

現在來了解一下資料包被轉發出去的情況,執行的是ip_forward:


 77 int ip_forward(struct sk_buff *skb)
 78 {
 79     u32 mtu;
 80     struct iphdr *iph;  /* Our header */
 81     struct rtable *rt;  /* Route we use */
 82     struct ip_options *opt  = &(IPCB(skb)->opt); //獲取資料包中IP的option
 83     struct net *net;
 84
 85     /* that should never happen */
 86     if (skb->pkt_type != PACKET_HOST)  //不是發往本機的包丟棄
 87         goto drop;
 88
 89     if (unlikely(skb->sk)) 
 90         goto drop;
 91
 92     if (skb_warn_if_lro(skb)) //與GSO相關
 93         goto drop;
 94
 95     if (!xfrm4_policy_check(NULL, XFRM_POLICY_FWD, skb)) //查詢IPsec資料庫,如果查詢失敗則丟包
 96         goto drop;
 97
 98     if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb)) //如果IP option中存在警告選項,則呼叫ip_call_ra_chain將資料包輸入給對路由警告選項感興趣的用
戶程序。如果成功則不再轉發該資料包
99         return NET_RX_SUCCESS;
100
101     skb_forward_csum(skb);  //在轉發過程中可能會修改IP首部,則呼叫該函式skb->ip_summed = CHECKSUM_NONE,後面輸出時要計算新的校驗和
102     net = dev_net(skb->dev);
103
104     /*
105      *  According to the RFC, we must first decrease the TTL field. If
106      *  that reaches zero, we must reply an ICMP control message telling
107      *  that the packet's lifetime expired.
108      */
109     if (ip_hdr(skb)->ttl <= 1)  //如果跳數小於或等於1,則不轉發,並跳轉到傳送ICMP報文
110         goto too_many_hops;
111
112     if (!xfrm4_route_forward(skb))  //進行IPsec的路由選擇和轉發,如果失敗則丟包
113         goto drop;
114
115     rt = skb_rtable(skb); //獲取路由
116
117     if (opt->is_strictroute && rt->rt_uses_gateway) //如果資料包啟動嚴格路由選項,且路由的下一跳不是閘道器,則傳送超時ICMP報文到傳送方
118         goto sr_failed;
119
120     IPCB(skb)->flags |= IPSKB_FORWARDED;  //設定IP管理塊中的flag為FORWORD
121     mtu = ip_dst_mtu_maybe_forward(&rt->dst, true);  //獲取當前系統的最小MTU
122     if (ip_exceeds_mtu(skb, mtu)) {  //如果該包的大小超過了最新MTU,則傳送ICMP給傳送端,並且停止轉發
123         IP_INC_STATS(net, IPSTATS_MIB_FRAGFAILS);
124         icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED,
125               htonl(mtu));
126         goto drop;
127     }
128
129     /* We are about to mangle packet. Copy it! */
130     if (skb_cow(skb, LL_RESERVED_SPACE(rt->dst.dev)+rt->dst.header_len)) //確保SKB有指定長度的headroom,當他的headroom小於指定長度或者克隆SKB時,
會新建SKB緩衝,並且釋放對原包的引用
131         goto drop;
132     iph = ip_hdr(skb);  //獲取IP頭部
134     /* Decrease ttl after skb cow done */
135     ip_decrease_ttl(iph);  //將TTL減1
136
137     /*
138      *  We now generate an ICMP HOST REDIRECT giving the route
139      *  we calculated.
140      */
141     if (IPCB(skb)->flags & IPSKB_DOREDIRECT && !opt->srr && //如果該資料包的輸出路由存在重定向標誌,且該資料報中不存在源路由選項,則向傳送端傳送
142         !skb_sec_path(skb))      //重定向ICMP報文
143         ip_rt_send_redirect(skb);
144
145     skb->priority = rt_tos2priority(iph->tos); 
146
147     return NF_HOOK(NFPROTO_IPV4, NF_INET_FORWARD,
148                net, NULL, skb, skb->dev, rt->dst.dev,
149                ip_forward_finish);   //經過netfilter處理後,呼叫ip_forward_finish進一步處理
150
151 sr_failed:
152     /*
153      *  Strict routing permits no gatewaying
154      */
155      icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0);
156      goto drop;
157
158 too_many_hops:
159     /* Tell the sender its packet died... */
160     __IP_INC_STATS(net, IPSTATS_MIB_INHDRERRORS);
161     icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0);
162 drop:
163     kfree_skb(skb);
164     return NET_RX_DROP;
165 }


 

7. ip_forward_finish
 64 static int ip_forward_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
 65 {
 66     struct ip_options *opt  = &(IPCB(skb)->opt); 
 67
 68     __IP_INC_STATS(net, IPSTATS_MIB_OUTFORWDATAGRAMS);
 69     __IP_ADD_STATS(net, IPSTATS_MIB_OUTOCTETS, skb->len);
 70
 71     if (unlikely(opt->optlen)) //如果option的長度不為0
 72         ip_forward_options(skb); //處理轉發IP資料報中的IP選項,包括記錄路由選項和時間戳選項
 73
 74     return dst_output(net, sk, skb); //通過路由快取將資料包輸出,最終會呼叫單播的輸出函式ip_output或組播的輸出函式ip_mc_output
 75 }

8. ip_output

 395 int ip_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 396 {
 397     struct net_device *dev = skb_dst(skb)->dev;
 398
 399     IP_UPD_PO_STATS(net, IPSTATS_MIB_OUT, skb->len);
 400
 401     skb->dev = dev; //設定資料包的輸出網路裝置
 402     skb->protocol = htons(ETH_P_IP);  //設定資料包網路層協議型別
 403
 404     return NF_HOOK_COND(NFPROTO_IPV4, NF_INET_POST_ROUTING,
 405                 net, sk, skb, NULL, dev,
 406                 ip_finish_output,
 407                 !(IPCB(skb)->flags & IPSKB_REROUTED)); //呼叫ip_finish_output繼續IP包的輸出
 408 }

9. ip_finish_output
 291 static int ip_finish_output(struct net *net, struct sock *sk, struct sk_buff *skb)
 292 {
 293     unsigned int mtu;
 294     int ret;
 295
 296     ret = BPF_CGROUP_RUN_PROG_INET_EGRESS(sk, skb); 
 297     if (ret) {
 298         kfree_skb(skb);
 299         return ret;
 300     }
 301
 302 #if defined(CONFIG_NETFILTER) && defined(CONFIG_XFRM)
 303     /* Policy lookup after SNAT yielded a new policy */
 304     if (skb_dst(skb)->xfrm) {
 305         IPCB(skb)->flags |= IPSKB_REROUTED;
 306         return dst_output(net, sk, skb); //根據安全策略需要重傳
 307     }
 308 #endif
 309     mtu = ip_skb_dst_mtu(sk, skb); //獲取最小MTU的大小
 310     if (skb_is_gso(skb))
 311         return ip_finish_output_gso(net, sk, skb, mtu);  //如果需要支援GSO特性,則進行GSO的組裝,關於GSO的特性我們後面分開講
 312
 313     if (skb->len > mtu || (IPCB(skb)->flags & IPSKB_FRAG_PMTU))
 314         return ip_fragment(net, sk, skb, mtu, ip_finish_output2); //如果長度不滿足要求則進行IP包的分段
 315
 316     return ip_finish_output2(net, sk, skb); //呼叫該函式繼續處理
 317 }

10. ip_finish_output2
 183 static int ip_finish_output2(struct net *net, struct sock *sk, struct sk_buff *skb)
 184 {
 185     struct dst_entry *dst = skb_dst(skb); 
 186     struct rtable *rt = (struct rtable *)dst;
 187     struct net_device *dev = dst->dev;
 188     unsigned int hh_len = LL_RESERVED_SPACE(dev);
 189     struct neighbour *neigh;
 190     u32 nexthop;
 191
 192     if (rt->rt_type == RTN_MULTICAST) {
 193         IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTMCAST, skb->len);
 194     } else if (rt->rt_type == RTN_BROADCAST)
 195         IP_UPD_PO_STATS(net, IPSTATS_MIB_OUTBCAST, skb->len);
 196
 197     /* Be paranoid, rather than too clever. */
 198     if (unlikely(skb_headroom(skb) < hh_len && dev->header_ops)) { //檢測skb頭部空間是否還有空間存放鏈路層首部,如果不夠,則重新分配更大的儲存空間,
 199         struct sk_buff *skb2;     //並釋放原來的SKB
 200
 201         skb2 = skb_realloc_headroom(skb, LL_RESERVED_SPACE(dev));
 202         if (!skb2) {
 203             kfree_skb(skb);
 204             return -ENOMEM;
 205         }
 206         if (skb->sk)
 207             skb_set_owner_w(skb2, skb->sk);
 208         consume_skb(skb);
 209         skb = skb2;
 210     }
 211
 212     if (lwtunnel_xmit_redirect(dst->lwtstate)) {
 213         int res = lwtunnel_xmit(skb);
 214
 215         if (res < 0 || res == LWTUNNEL_XMIT_DONE)
 216             return res;
 217     }
 219     rcu_read_lock_bh();
 220     nexthop = (__force u32) rt_nexthop(rt, ip_hdr(skb)->daddr); //獲取下一跳路由
 221     neigh = __ipv4_neigh_lookup_noref(dev, nexthop); //查詢鄰居子系統
 222     if (unlikely(!neigh))
 223         neigh = __neigh_create(&arp_tbl, &nexthop, dev, false); //如果沒有查到,則根據下一跳路由建立一跳新的記錄
 224     if (!IS_ERR(neigh)) { //如果建立成功
 225         int res;
 226
 227         sock_confirm_neigh(skb, neigh); //確認路由,如果不能確認則設定對應的標識
 228         res = neigh_output(neigh, skb); //呼叫該函式交給鄰居子系統
 229
 230         rcu_read_unlock_bh();
 231         return res;
 232     }
 233     rcu_read_unlock_bh();
 234
 235     net_dbg_ratelimited("%s: No header cache and no neighbour!\n",
 236                 __func__);
 237     kfree_skb(skb);
 238     return -EINVAL;
 239 }
 
472 static inline int neigh_output(struct neighbour *n, struct sk_buff *skb)
473 {
474     const struct hh_cache *hh = &n->hh;
475
476     if ((n->nud_state & NUD_CONNECTED) && hh->hh_len) //如果快取了鏈路層的首部,則呼叫neigh_hh_output,否則呼叫鄰居項的輸出方法輸出
477         return neigh_hh_output(hh, skb); //呼叫該函式輸出資料包
478     else
479         return n->output(n, skb); //使用鄰居項的輸出方法
480 }

450 static inline int neigh_hh_output(const struct hh_cache *hh, struct sk_buff *skb)
451 {
452     unsigned int seq;
453     unsigned int hh_len;
454
455     do {
456         seq = read_seqbegin(&hh->hh_lock);
457         hh_len = hh->hh_len;
458         if (likely(hh_len <= HH_DATA_MOD)) {
459             /* this is inlined by gcc */
460             memcpy(skb->data - HH_DATA_MOD, hh->hh_data, HH_DATA_MOD);
461         } else {
462             unsigned int hh_alen = HH_DATA_ALIGN(hh_len);
463
464             memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
465         }
466     } while (read_seqretry(&hh->hh_lock, seq));
467
468     skb_push(skb, hh_len);
469     return dev_queue_xmit(skb); //到這裡將包從網路層傳送給介面層
470 }