Linux协议栈(7)——网络层实现
網(wǎng)絡(luò)層具體就是IP協(xié)議層,處理發(fā)送和接收數(shù)據(jù)外,還需要進(jìn)行轉(zhuǎn)發(fā)和路由分組。在查找最佳路由并選擇適當(dāng)網(wǎng)卡的時(shí)候也會(huì)涉及對(duì)底層地址族的處理,例如MAC地址。
ip頭數(shù)據(jù)結(jié)構(gòu)定義在:include/uapi/linux/ip.h。
struct iphdr {
#if defined(__LITTLE_ENDIAN_BITFIELD)
??? ????__u8??? ihl:4,
??????????????? version:4;
#elif defined (__BIG_ENDIAN_BITFIELD)
??????? __u8??? version:4,
??????????????? ihl:4;
#else
#error? "Please fix <asm/byteorder.h>"
#endif
??????? __u8??? tos;
??????? __be16? tot_len;
??????? __be16? id;
??? ????__be16? frag_off;
??????? __u8??? ttl;
??????? __u8??? protocol;
??????? __sum16 check;
??????? __be32? saddr;
??????? __be32? daddr;
??????? /*The options start here. */
};
1.1.1.1? 接收
??????????? ipv4數(shù)據(jù)包的主接收方法是ip_rcv()函數(shù),會(huì)檢測(cè)報(bào)到類似如果是PACKET_OTHERHOST(定義在include/uapi/linux/if_packet.h文件中)則直接丟棄。檢查是否是共享的包,如果是分享的包則克隆它。獲取ip頭數(shù)據(jù)結(jié)構(gòu),來操作相關(guān)協(xié)議事務(wù)。然后調(diào)用NK_HOOK,NF_HOOK定義在include/linux/netfilter.h文件中。
static inline int
NF_HOOK(uint8_t pf, unsigned int hook, struct net *net, struct sock *sk, struct sk_buff *skb,
??????? struct net_device *in, struct net_device *out,
??????? int (*okfn)(struct net *, struct sock *, struct sk_buff *))
??????????? 它是netfilter鉤子函數(shù),如果允許包傳遞則返回1。如果返回其他值說明這個(gè)包被hook給消耗掉了。
??????????? 其中hook為NF_INET_PRE_ROUTING(定義在
include/uapi/linux/netfilter.h)
okfn指向ip_rcv_finish()函數(shù)。ip_rcv_finish()也定義在:net/ipv4/ip_input.c
??????????? 在ip網(wǎng)絡(luò)層中需要分段、重組的實(shí)現(xiàn)。須在路由選在子系統(tǒng)中查找,確定是發(fā)給當(dāng)前主機(jī)還是轉(zhuǎn)發(fā)。
??????????? 如果是當(dāng)前主機(jī)則依次調(diào)用方法ip_local_deliver()和ip_local_deliver_finish()函數(shù)。如果需要轉(zhuǎn)發(fā)則調(diào)用ip_forward()函數(shù)。
1.1.1.1.1????????? 分片合并
IP分組可能是分片的,可以通過ip_defrag重新組合分片分組的各個(gè)部分。代碼流程如下圖(圖摘自《深入linux內(nèi)核架構(gòu)》):
??????????? 內(nèi)核在獨(dú)立的緩存中管理原本屬于一個(gè)分組的各個(gè)分片,該緩存稱為分片緩存(fragment cache)。屬于同一個(gè)分組的各個(gè)分片保存在一個(gè)獨(dú)立的等待隊(duì)列中,直至該分組的所有分片到達(dá)。
??????????? ip_frag_reasm將各個(gè)分片重新組合起來。
1.1.1.1.2????????? 交付到傳輸層
如果數(shù)據(jù)是給本機(jī)的,那么返回到ip_local_deliver。調(diào)用netfilter掛鉤NF_IP_LOCAL_IN恢復(fù)在ip_local_deliver_finish函數(shù)中的處理。
??????????? 分組的協(xié)議標(biāo)識(shí)符確定一個(gè)傳輸層的函數(shù),分組將傳遞給該函數(shù)。每個(gè)協(xié)議都有一個(gè)net_protocol結(jié)構(gòu)的實(shí)例。定義在:
include/net/protocol.h文件中
struct net_protocol {???
??????? int???????????????????? (*early_demux)(struct sk_buff *skb);
??????? int???????????????????? (*early_demux_handler)(struct sk_buff *skb);
??????? int???????????????????? (*handler)(struct sk_buff *skb);
??????? void??????????????????? (*err_handler)(struct sk_buff *skb, u32 info);?????????????????????????????????????
??????? unsigned int??????????? no_policy:1,?????????????
? ??????????????????????????????netns_ok:1,??????????????
??????????????????????????????? /* does the protocol do more stringent
???????????????????????????????? * icmp tag validation than simple
???????????????????????????????? * socket lookup?
?????????? ??????????????????????*/??????????????????????
??????????????????????????????? icmp_strict_tag_validation:1;??????????????????????????????????????????????????????
};
1.1.1.1.3????????? 分組轉(zhuǎn)發(fā)
ip分組也可能轉(zhuǎn)發(fā)到另一臺(tái)計(jì)算機(jī)。這就需要調(diào)用ip_forward函數(shù)。
??????????? ip_forward使用NF_HOOK掛鉤函數(shù),掛鉤編號(hào)為NF_INET_FORWARD,回調(diào)函數(shù)為ip_forward_finish。
1.1.1.2? 發(fā)送
由ip_queue_xmit函數(shù)將數(shù)據(jù)包從L4移到L3
網(wǎng)絡(luò)層要選擇合適的網(wǎng)間路由和交換結(jié)點(diǎn),確保數(shù)據(jù)及時(shí)傳送。其主要任務(wù)包括 (1)路由處理,即選擇下一跳 (2)添加 IP header(3)計(jì)算 IP header checksum,用于檢測(cè) IP 報(bào)文頭部在傳播過程中是否出錯(cuò) (4)可能的話,進(jìn)行 IP 分片(5)處理完畢,獲取下一跳的 MAC 地址,設(shè)置鏈路層報(bào)文頭,然后轉(zhuǎn)入鏈路層處理。
??????????? 發(fā)送和接收操作的流程并不總是分離的,如果分組只通過當(dāng)前計(jì)算機(jī)轉(zhuǎn)發(fā),那么發(fā)送和接收操作是交織的。總結(jié)
以上是生活随笔為你收集整理的Linux协议栈(7)——网络层实现的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: js中如何优雅的解析数据
- 下一篇: 面向对象先导课程——PART3