日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux数据报文接收发送总结6

發布時間:2025/4/5 linux 20 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux数据报文接收发送总结6 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

2.3 協議棧注冊

內核實現了網絡層的ip協議,也實現了傳輸層的tcp協議和udp協議。這些協議對應的實現函數分別是ip_rcv(),tcp_v4_rcv()和udp_rcv()。和我們平時寫代碼的方式不一樣的是,內核是通過注冊的方式來實現的。Linux內核中的fs_initcall和subsys_initcall類似,也是初始化模塊的入口。fs_initcall調用inet_init后開始網絡協議棧注冊。通過inet_init,將這些函數注冊到了inet_protos(傳輸層協議)和ptype_base(網絡/鏈路層協議)數據結構中了。如下圖:

相關代碼如下

//file: net/ipv4/af_inet.cstatic const struct net_proto_family inet_family_ops = {.family = PF_INET,.create = inet_create,.owner = THIS_MODULE, };/* Upon startup we insert all the elements in inetsw_array[] into* the linked list inetsw.*/ static struct inet_protosw inetsw_array[] = {{.type = SOCK_STREAM,.protocol = IPPROTO_TCP,.prot = &tcp_prot,.ops = &inet_stream_ops,.flags = INET_PROTOSW_PERMANENT |INET_PROTOSW_ICSK,},{.type = SOCK_DGRAM,.protocol = IPPROTO_UDP,.prot = &udp_prot,.ops = &inet_dgram_ops,.flags = INET_PROTOSW_PERMANENT,},{.type = SOCK_DGRAM,.protocol = IPPROTO_ICMP,.prot = &ping_prot,.ops = &inet_sockraw_ops,.flags = INET_PROTOSW_REUSE,},{.type = SOCK_RAW,.protocol = IPPROTO_IP, /* wild card */.prot = &raw_prot,.ops = &inet_sockraw_ops,.flags = INET_PROTOSW_REUSE,} };static struct packet_type ip_packet_type __read_mostly = {.type = cpu_to_be16(ETH_P_IP),.func = ip_rcv, };static const struct net_protocol tcp_protocol = {.early_demux = tcp_v4_early_demux,.handler = tcp_v4_rcv,.err_handler = tcp_v4_err,.no_policy = 1,.netns_ok = 1,.icmp_strict_tag_validation = 1, };static const struct net_protocol udp_protocol = {.early_demux = udp_v4_early_demux,.handler = udp_rcv,.err_handler = udp_err,.no_policy = 1,.netns_ok = 1, };static const struct net_protocol icmp_protocol = {.handler = icmp_rcv,.err_handler = icmp_err,.no_policy = 1,.netns_ok = 1, };static int __init inet_init(void) {struct inet_protosw *q;struct list_head *r;int rc = -EINVAL;sock_skb_cb_check_size(sizeof(struct inet_skb_parm));rc = proto_register(&tcp_prot, 1);if (rc)goto out;rc = proto_register(&udp_prot, 1);if (rc)goto out_unregister_tcp_proto;rc = proto_register(&raw_prot, 1);if (rc)goto out_unregister_udp_proto;rc = proto_register(&ping_prot, 1);if (rc)goto out_unregister_raw_proto;/** Tell SOCKET that we are alive...*/(void)sock_register(&inet_family_ops); // 協議族注冊, socket函數的第一個參數#ifdef CONFIG_SYSCTLip_static_sysctl_init(); #endif/** Add all the base protocols.*/if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0) //協議注冊,ip層協議解析后,再向上解析傳輸層調用 pr_crit("%s: Cannot add ICMP protocol\n", __func__);if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)pr_crit("%s: Cannot add UDP protocol\n", __func__);if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)pr_crit("%s: Cannot add TCP protocol\n", __func__); #ifdef CONFIG_IP_MULTICASTif (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)pr_crit("%s: Cannot add IGMP protocol\n", __func__); #endif/* Register the socket-side information for inet_create. */for (r = &inetsw[0]; r < &inetsw[SOCK_MAX]; ++r)INIT_LIST_HEAD(r);for (q = inetsw_array; q < &inetsw_array[INETSW_ARRAY_LEN]; ++q) // 類型注冊,對應socket中的第二個參數inet_register_protosw(q);/** Set the ARP module up*/arp_init();/** Set the IP module up*/ip_init();tcp_v4_init();/* Setup TCP slab cache for open requests. */tcp_init();/* Setup UDP memory threshold */udp_init();/* Add UDP-Lite (RFC 3828) */udplite4_register();ping_init();/** Set the ICMP layer up*/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); // 注冊到ptype_base, 接收報文時,根據協議進行相應的處理函數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);

proto_register注冊函數,將對應協議加到proto_list鏈表中。proto_list是一個全局的靜態鏈表,inet域支持的所有協議全部在這個鏈表中,但這個鏈表在協議棧中并沒有太大用途,它只是用于在/proc/net/protocols文件中輸出當前系統所支持的所有協議。

inet_register_protosw注冊函數,將對協議加到 inetsw 數組中,在socket函數系統調用時選擇具體的協議時會用到,發送報文時會用到。

int proto_register(struct proto *prot, int alloc_slab) {if (alloc_slab) {......}mutex_lock(&proto_list_mutex);list_add(&prot->node, &proto_list);assign_proto_idx(prot);mutex_unlock(&proto_list_mutex);return 0; } EXPORT_SYMBOL(proto_register);void inet_register_protosw(struct inet_protosw *p) {struct list_head *lh;struct inet_protosw *answer;int protocol = p->protocol;struct list_head *last_perm;spin_lock_bh(&inetsw_lock);if (p->type >= SOCK_MAX)goto out_illegal;/* If we are trying to override a permanent protocol, bail. */last_perm = &inetsw[p->type];list_for_each(lh, &inetsw[p->type]) {answer = list_entry(lh, struct inet_protosw, list);/* Check only the non-wild match. */if ((INET_PROTOSW_PERMANENT & answer->flags) == 0)break;if (protocol == answer->protocol)goto out_permanent;last_perm = lh;}/* Add the new entry after the last permanent entry if any, so that* the new entry does not override a permanent entry when matched with* a wild-card protocol. But it is allowed to override any existing* non-permanent entry. This means that when we remove this entry, the* system automatically returns to the old behavior.*/list_add_rcu(&p->list, last_perm); out:spin_unlock_bh(&inetsw_lock);return;...... }

上面的代碼中我們可以看到,udp_protocol結構體中的handler是udp_rcv,tcp_protocol結構體中的handler是tcp_v4_rcv,通過inet_add_protocol被初始化了進來。

int inet_add_protocol(const struct net_protocol *prot, unsigned char protocol){if (!prot->netns_ok) {pr_err("Protocol %u is not namespace aware, cannot register.\n",protocol);return -EINVAL;}return !cmpxchg((const struct net_protocol **)&inet_protos[protocol],NULL, prot) ? 0 : -1; }

inet_add_protocol函數將tcp和udp對應的處理函數都注冊到了 inet_protos (接收報文時,解析傳輸層應用)數組中了。

再看dev_add_pack(&ip_packet_type);這一行,ip_packet_type結構體中的type是協議名,func是ip_rcv函數,在dev_add_pack中會被注冊到ptype_base(接收報文時,解析網絡層使用)哈希表中。(上面在net_dev_init時,最多支持16個協議)

//file: net/core/dev.c void dev_add_pack(struct packet_type *pt){struct list_head *head = ptype_head(pt);...... } static inline struct list_head *ptype_head(const struct packet_type *pt){if (pt->type == htons(ETH_P_ALL))return &ptype_all;elsereturn &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK]; }

這里我們需要記住inet_protos記錄著udp,tcp的處理函數地址,ptype_base存儲著ip_rcv()函數的處理地址。后面我們會看到軟中斷中會通過ptype_base找到ip_rcv函數地址,進而將ip包正確地送到ip_rcv()中執行。在ip_rcv中將會通過inet_protos找到tcp或者udp的處理函數,再而把包轉發給udp_rcv()或tcp_v4_rcv()函數。

擴展一下,如果看一下ip_rcv和udp_rcv等函數的代碼能看到很多協議的處理過程。例如,ip_rcv中會處理netfilter和iptable過濾,如果你有很多或者很復雜的 netfilter 或 iptables 規則,這些規則都是在軟中斷的上下文中執行的,會加大網絡延遲。再例如,udp_rcv中會判斷socket接收隊列是否滿了。對應的相關內核參數是net.core.rmem_max和net.core.rmem_default。如果有興趣,建議大家好好讀一下inet_init這個函數的代碼。

總結

以上是生活随笔為你收集整理的Linux数据报文接收发送总结6的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 插插看看| 久久久一二三区 | 秋霞精品一区二区三区 | 成人gav| 精品国产一区二区三区四区精华 | 69视频一区| 亚洲乱码一区二区三区在线观看 | 歪歪6080 | 天天干天天摸 | 亚洲小说专区 | 精品av一区二区 | 久久久久久97 | 一级黄色性生活视频 | 欧美少妇15p| 国产麻豆成人精品av | 国产乱真实合集 | 免费观看av网站 | 国产精品一二三区 | 精品久久久久久久久久久国产字幕 | 在线看的av| 欧美精品一区二区免费看 | 精品乱码久久久久久中文字幕 | 亚洲高清毛片一区二区 | 亚洲一区免费 | 日本成人久久 | 亚洲乱码国产乱码精品精剪 | 欧美特一级片 | 性一交一黄一片 | 日韩精品在线视频观看 | 久久99热精品 | 成人看片在线 | 啪啪免费网 | 久久久免费在线观看 | 美国免费黄色片 | 欧美福利视频在线 | 午夜精品久久久久 | 污污视频在线观看免费 | 久久精品国产亚洲AV高清综合 | 91丝袜一区在线观看 | 91精品国产综合久久久蜜臀图片 | 刘亦菲一区二区三区免费看 | 69视频入口 | 九九色播 | 免费在线你懂的 | 国产精品中文久久久久久 | 国产精品视频亚洲 | 亚洲av综合色区无码二区爱av | 另类专区成人 | 成人一区二区在线观看 | 青青草成人av | 毛片精品 | 中国国产毛片 | 国产簧片 | 麻豆精品视频在线观看 | 欧美熟妇精品一区二区蜜桃视频 | 一级成人黄色片 | a级网站在线观看 | 青青毛片 | 99视频一区二区 | 国产99久久久国产精品 | 久久久久久久国产精品毛片 | 男人的网站在线观看 | 国产麻豆一精品一男同 | 午夜一级黄色片 | 国产成人综合一区二区三区 | 91伊人久久 | 视频免费观看在线 | 美女扒开腿让人桶爽 | 性福宝av | 亚洲电影一区二区三区 | 中文字幕欧美在线 | 免费看黄20分钟 | 欧美一级网站 | 少妇扒开粉嫩小泬视频 | 欧美伦理一区二区三区 | 日韩精品一区二区三区不卡 | 日韩欧美中文字幕在线播放 | 欧美日韩在线播放三区四区 | 日韩成人精品一区 | 波多野结衣视频免费观看 | 大桥未久在线视频 | 国产专区自拍 | 伊人色婷婷 | 99在线观看免费 | 激情久久久久 | 亚洲v欧美v另类v综合v日韩v | 国产一区精品视频 | 免费看黄色一级片 | 亚洲午夜在线播放 | 牛牛精品一区 | 国产91精品看黄网站在线观看 | 欧美乱淫 | 欧美性猛交一区二区三区精品 | 乳揉みま痴汉4在线播放 | 国产做受高潮 | 日韩一区二区三区在线免费观看 | 视频一区二区三区在线 | 欧美乱插 | 亚洲成人一 |