Internet 网络协议族
1、linux目前支持多種協(xié)議族,每個(gè)協(xié)議族用一個(gè)net_porto_family結(jié)構(gòu)實(shí)例來(lái)表示,在初始化時(shí),會(huì)調(diào)用sock_register()函數(shù)初始化注冊(cè)到net_families[NPROTO]中去;
同時(shí)出現(xiàn)了一個(gè)地址族的概念,目前協(xié)議族和地址族是一 一 對(duì)應(yīng)關(guān)系。歷史上曾經(jīng)有一個(gè)協(xié)議族支持多個(gè)地址族,實(shí)際上從未實(shí)現(xiàn)過(guò)。在socket.h文件中PF_XX和AF_XX 值一樣
2、由于不同協(xié)議族的結(jié)構(gòu)差別很大,為了封裝統(tǒng)一,以便在初始化時(shí),可以統(tǒng)一接口,于是就有了net_proto_family。其用sock_register統(tǒng)一注冊(cè),初始化鉤子,具體初始化,其實(shí)現(xiàn)見鉤子實(shí)現(xiàn),類似于VFS 的實(shí)現(xiàn)方式。一種很好的設(shè)計(jì)思想。
?
/*ops->create在應(yīng)用程序創(chuàng)建套接字的時(shí)候,引起系統(tǒng)調(diào)用,從而在函數(shù)__sock_create中執(zhí)行ops->create netlink為netlink_family_ops 應(yīng)用層創(chuàng)建套接字的時(shí)候,內(nèi)核系統(tǒng)調(diào)用sock_create,然后執(zhí)行該函數(shù) pf_inet的net_families[]為inet_family_ops,對(duì)應(yīng)的套接口層ops參考inetsw_array中的inet_stream_ops inet_dgram_ops inet_sockraw_ops, 傳輸層操作集分別為tcp_prot udp_prot raw_prot netlink的net_families[]netlink_family_ops,對(duì)應(yīng)的套接口層ops為netlink_ops family協(xié)議族通過(guò)sock_register注冊(cè) 傳輸層接口tcp_prot udp_prot netlink_prot等通過(guò)proto_register注冊(cè) IP層接口通過(guò)inet_add_protocol(&icmp_protocol等注冊(cè) ,這些組成過(guò)程參考inet_init函數(shù)*/ struct net_proto_family {//操作集參考inetsw_arrayint family;int (*create)(struct net *net, struct socket *sock,int protocol, int kern);協(xié)議族的套接字創(chuàng)建函數(shù)指針,每個(gè)協(xié)議族實(shí)現(xiàn)都不同struct module *owner; };?
Internet 協(xié)議族的net_proto_family結(jié)構(gòu)實(shí)例為inet_family_ops,創(chuàng)建套接字socket時(shí),其調(diào)用接口為inet_create().
2、inet_protosw 結(jié)構(gòu)
?
/* This is used to register socket interfaces for IP protocols. */ struct inet_protosw {struct list_head list;/* 初始化時(shí)將相同的type的inet_protosw散列在同一個(gè)鏈表*//* These two fields form the lookup key. */unsigned short type; /* This is the 2nd argument to socket(2). 表示套接口字的類型,對(duì)于Internet 協(xié)議族有三種類型 SOCK_STREAM SOCK_DGRAM SOCK_RAW 對(duì)于與應(yīng)用層socket函數(shù)的第二個(gè)參數(shù)type*/unsigned short protocol; /* This is the L4 protocol number. */struct proto *prot; /*套接口網(wǎng)絡(luò)層口,tcp為tcp_port udp為udp_port 原始套接字為raw_port*/const struct proto_ops *ops;/* 套接口傳輸層接口,tcp為inet_stream_ops,udp 為inet_dgram_ops,原始套接字為inet_sockraw_ops*/unsigned char flags; /* See INET_PROTOSW_* below. */ }; #define INET_PROTOSW_REUSE 0x01 /* Are ports automatically reusable? 端口重用*/ #define INET_PROTOSW_PERMANENT 0x02 /* Permanent protocols are unremovable. 協(xié)議不能被替換卸載*/ #define INET_PROTOSW_ICSK 0x04 /* Is this an inet_connection_sock? 是不是為連接類型的接口*/ View Code?
?tcp 不能被替換卸載切為連接型套接字,udp 不能被替換和卸載,rawsocket端口可以重用。
/* Upon startup we insert all the elements in inetsw_array[] into* the linked list inetsw.在初始化的時(shí)候我們會(huì)將上面數(shù)組中的的元素按套接字類型插入static struct list_head inetsw[SOCK_MAX];鏈表數(shù)組中*/ /* * inetsw_array數(shù)組包含三個(gè)inet_protosw結(jié)構(gòu)的實(shí)例,分別對(duì)應(yīng)* TCP、UDP和原始套接字。在Internet協(xié)議族初始化函數(shù)inet_init()中* 調(diào)用inet_register_protosw()將inetsw_array數(shù)組中* 的inet_protosw結(jié)構(gòu)實(shí)例,以其type值為key組織到散列表inetsw中,* 也就是說(shuō)各協(xié)議族中type值相同而protocol值不同的inet_protosw結(jié)構(gòu)* 實(shí)例,在inetsw散列表中以type為關(guān)鍵字連接成鏈表,通過(guò)inetsw* 散列表可以找到所有協(xié)議族的inet_protosw結(jié)構(gòu)實(shí)例。*/ //ipv4_specific是TCP傳輸層到網(wǎng)絡(luò)層數(shù)據(jù)發(fā)送以及TCP建立過(guò)程的真正OPS,在tcp_prot->init中被賦值給inet_connection_sock->icsk_af_ops static struct inet_protosw inetsw_array[] = //這個(gè)和應(yīng)用層創(chuàng)建套接字相關(guān),個(gè)人我理解是屬于套接口層,為了把套接口層和傳輸層銜接起來(lái)(tcp_protocol udp_protol icmp_protocol) {{ .type = SOCK_STREAM, //在inet_create的時(shí)候,用它做為關(guān)鍵字,把下面這幾個(gè)成員聯(lián)系在一起.protocol = IPPROTO_TCP,//tcp_prot udp proto raw_proto頭添加到的proto_list中,通過(guò)遍歷該鏈表就可以知道有哪些傳輸層協(xié)議添加到該鏈表中 //協(xié)議最終都是通過(guò)inet_init中的proto_register添加到proto_list鏈表中的。family協(xié)議族通過(guò)sock_register注冊(cè) //傳輸層接口tcp_prot udp_prot netlink_prot等通過(guò)proto_register注冊(cè) //IP層接口通過(guò)inet_add_protocol(&icmp_protocol等注冊(cè) ,這些組成過(guò)程參考inet_init函數(shù).prot = &tcp_prot,//傳輸層操作集 在inet_create中的sk_alloc中賦值 // 先執(zhí)行ops中的函數(shù),然后執(zhí)行prot中對(duì)應(yīng)的函數(shù) proto結(jié)構(gòu)為網(wǎng)絡(luò)接口層, //結(jié)構(gòu)中的操作實(shí)現(xiàn)傳輸層的操作和從傳輸層到網(wǎng)絡(luò)層調(diào)用的跳轉(zhuǎn), //在proto結(jié)構(gòu)中的某些成員跟proto_ops結(jié)構(gòu)中的成員對(duì)應(yīng),比如connect()等.ops = &inet_stream_ops,//套接口層操作集,也就是協(xié)議族操作集 // 用來(lái)區(qū)分協(xié)議族(netlink family(ops為netlink_ops)或者 inet family) // ops在創(chuàng)建套接字的時(shí)候被賦值,例如netlink賦值的地方在__netlink_create pf_net賦值的地方在inet_create中.no_check = 0, //為0表示始終進(jìn)行校驗(yàn)和操作.flags = INET_PROTOSW_PERMANENT |INET_PROTOSW_ICSK,},{.type = SOCK_DGRAM,.protocol = IPPROTO_UDP,.prot = &udp_prot,//傳輸層操作集 在inet_create中的sk_alloc中賦值 先執(zhí)行ops中的函數(shù),然后執(zhí)行prot中對(duì)應(yīng)的函數(shù).ops = &inet_dgram_ops,//套接口層操作集 用來(lái)區(qū)分協(xié)議族(netlink family(ops為netlink_ops)或者 inet family) // ops在創(chuàng)建套接字的時(shí)候被賦值,例如netlink賦值的地方在__netlink_create pf_net賦值的地方在inet_create中.no_check = UDP_CSUM_DEFAULT,.flags = INET_PROTOSW_PERMANENT,},{.type = SOCK_RAW, //原始套接口.protocol = IPPROTO_IP, /* wild card */.prot = &raw_prot,//傳輸層操作集 在inet_create中的sk_alloc中賦值 先執(zhí)行ops中的函數(shù),然后執(zhí)行prot中對(duì)應(yīng)的函數(shù).ops = &inet_sockraw_ops,//套接口層操作集 //用來(lái)區(qū)分協(xié)議族(netlink family(ops為netlink_ops)或者 inet family) ops在創(chuàng)建套接字的時(shí)候被賦值, //例如netlink賦值的地方在__netlink_create pf_net賦值的地方在inet_create中.no_check = UDP_CSUM_DEFAULT,.flags = INET_PROTOSW_REUSE,} };?
?
?
3、net_protocol 結(jié)構(gòu)
net_protocol 結(jié)構(gòu)定義了傳輸層協(xié)議(包含icmp igmp協(xié)議)以及傳輸層的報(bào)文接收例程,此結(jié)構(gòu)是網(wǎng)絡(luò)層和傳輸層之間的橋梁。
/* * inet_add_protocol函數(shù)用于將上述結(jié)構(gòu)的實(shí)例(指針)* 存儲(chǔ)到inet_protos 數(shù)組中* update:* net_protocol是一個(gè)非常重要的結(jié)構(gòu),定義了協(xié)議族中支持的傳輸層協(xié)議以及傳輸層的報(bào)文接收實(shí)例。此結(jié)構(gòu)是網(wǎng)絡(luò)層和 傳輸層之間的橋梁,當(dāng)網(wǎng)絡(luò)數(shù)據(jù)包從網(wǎng)絡(luò)層流向傳輸層時(shí),* 會(huì)調(diào)用此結(jié)構(gòu)中的傳輸層協(xié)議數(shù)據(jù)時(shí),會(huì)調(diào)用此結(jié)構(gòu)中的傳輸層協(xié)議數(shù)據(jù)報(bào)接收處理函數(shù)。** 內(nèi)核中為Internet協(xié)議族定義了4個(gè)net_protocol結(jié)構(gòu)實(shí)例---* icmp_protocol、udp_protocol、tcp_protocol和igmp_protocol* ,分別與ICMP、UDP、TCP和IGMP協(xié)議一一對(duì)應(yīng)。在Internet協(xié)議族* 初始化時(shí),調(diào)用inet_add_protocol()將它們注冊(cè)到net_protocol* 結(jié)構(gòu)指針數(shù)組inet_protos[MAX_INET_PROTOS]中。在系統(tǒng)運(yùn)行* 過(guò)程中,隨時(shí)可以用內(nèi)核模塊加載/卸載方式,調(diào)用函數(shù)inet_add_protocol()* /inet_del_protocol()將net_protocol結(jié)構(gòu)實(shí)例注冊(cè)到inet_protos[]數(shù)組中,* 或從中刪除。*///ops = rcu_dereference(inet_protos[proto]);通過(guò)該函數(shù)獲取對(duì)應(yīng)的協(xié)議ops /* This is used to register protocols. */ struct net_protocol {void (*early_demux)(struct sk_buff *skb);/* 分組將傳遞到該函數(shù)進(jìn)行進(jìn)一步處理*//** 傳輸層協(xié)議數(shù)據(jù)包接收處理函數(shù)指針,當(dāng)網(wǎng)絡(luò)層接收IP數(shù)據(jù)包* 之后,根據(jù)IP數(shù)據(jù)包所指示傳輸層協(xié)議,調(diào)用對(duì)應(yīng)傳輸層* net_protocol結(jié)構(gòu)的該例程接收?qǐng)?bào)文。* TCP協(xié)議的接收函數(shù)為tcp_v4_rcv(),UDP協(xié)議的接收函數(shù)為* udp_rcv(),IGMP協(xié)議為igmp_rcv(),ICMP協(xié)議為icmp_rcv()。*/int (*handler)(struct sk_buff *skb);/* * 在接收到ICMP錯(cuò)誤信息并需要傳遞到更高層時(shí),* 調(diào)用該函數(shù)*//** 在ICMP模塊中接收到差錯(cuò)報(bào)文后,會(huì)解析差錯(cuò)報(bào)文,并根據(jù)* 差錯(cuò)報(bào)文中原始的IP首部,調(diào)用對(duì)應(yīng)傳輸層的異常處理* 函數(shù)err_handler。TCP協(xié)議為tcp_v4_err(),UDP為* udp_err(),IGMP則無(wú)。*/void (*err_handler)(struct sk_buff *skb, u32 info);/** no_policy標(biāo)識(shí)在路由時(shí)是否進(jìn)行策略路由。TCP和UDP默認(rèn)不進(jìn)行* 策略路由。*/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; };?初始化后的inet_protos 如下:
?
4、Internet協(xié)議族的初始化
Internet協(xié)議初始化函數(shù)為inet_init ,通過(guò)fs_initcall調(diào)用,加載到內(nèi)核中;
/設(shè)備物理層的初始化net_dev_init
?TCP/IP協(xié)議棧初始化inet_init? 傳輸層的協(xié)議初始化也在這里面
?傳輸層初始化proto_init? 只是為了顯示各種協(xié)議用的
?套接口層初始化sock_init? netfilter_init在套接口層初始化的時(shí)候也初始化了
??????? 由 icmp_init函數(shù)完成。它為每個(gè)CPU都創(chuàng)建一個(gè)icmp_socket,創(chuàng)建工作由sock_create_kern函數(shù)完成,創(chuàng)建流程跟應(yīng)用層 創(chuàng)建socket完全一致。*/if (icmp_init() < 0)panic("Failed to create the ICMP control socket.\n");/** Initialise the multicast router*/ #if defined(CONFIG_IP_MROUTE)if (ip_mr_init())pr_crit("%s: Cannot init ipv4 mroute\n", __func__); #endifif (init_inet_pernet_ops())pr_crit("%s: Cannot init ipv4 inet pernet ops\n", __func__);/** Initialise per-cpu ipv4 mibs*/if (init_ipv4_mibs())pr_crit("%s: Cannot init ipv4 mibs\n", __func__);ipv4_proc_init();ipfrag_init();dev_add_pack(&ip_packet_type);ip_tunnel_core_init();rc = 0; out:return rc; out_unregister_raw_proto:proto_unregister(&raw_prot); out_unregister_udp_proto:proto_unregister(&udp_prot); out_unregister_tcp_proto:proto_unregister(&tcp_prot);goto out; }fs_initcall(inet_init);
?
轉(zhuǎn)載于:https://www.cnblogs.com/codestack/p/9193533.html
總結(jié)
以上是生活随笔為你收集整理的Internet 网络协议族的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 堆排序相关
- 下一篇: 微信小程序的线程架构