【Linux内核剖析】深入分析inet_init的处理机制

inet_init 是 Linux 内核中用于初始化 TCP/IP 协议栈的函数。它在内核启动时被调用,完成各种协议和数据结构的注册和初始化。
主要功能:

  • 注册 TCP、UDP、ICMP 等协议。
  • 初始化 ARP、IP 和其他网络协议模块。
  • 设置 socket 操作和协议处理。

前后调用关系链:

start_kernel()└── rest_init()└── kernel_init()└── do_basic_setup()└── do_initcalls()└── inet_init()├── proto_register(&tcp_prot, 1)├── proto_register(&udp_prot, 1)├── proto_register(&raw_prot, 1)├── proto_register(&ping_prot, 1)├── sock_register(&inet_family_ops)├── inet_add_protocol(&icmp_protocol, IPPROTO_ICMP)├── inet_add_protocol(&udp_protocol, IPPROTO_UDP)├── inet_add_protocol(&tcp_protocol, IPPROTO_TCP)├── arp_init()├── ip_init()├── tcp_v4_init()├── udp_init()├── ping_init()├── icmp_init()└── init_ipv4_mibs()


再来看源代码:

static int __init inet_init(void)
{struct sk_buff *dummy_skb;struct inet_protosw *q;struct list_head *r;int rc = -EINVAL;BUILD_BUG_ON(sizeof(struct inet_skb_parm) > sizeof(dummy_skb->cb));sysctl_local_reserved_ports = kzalloc(65536 / 8, GFP_KERNEL);if (!sysctl_local_reserved_ports)goto out;rc = proto_register(&tcp_prot, 1);if (rc)goto out_free_reserved_ports;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);#ifdef CONFIG_SYSCTLip_static_sysctl_init();
#endif/**	Add all the base protocols.*/if (inet_add_protocol(&icmp_protocol, IPPROTO_ICMP) < 0)printk(KERN_CRIT "inet_init: Cannot add ICMP protocol\n");if (inet_add_protocol(&udp_protocol, IPPROTO_UDP) < 0)printk(KERN_CRIT "inet_init: Cannot add UDP protocol\n");if (inet_add_protocol(&tcp_protocol, IPPROTO_TCP) < 0)printk(KERN_CRIT "inet_init: Cannot add TCP protocol\n");
#ifdef CONFIG_IP_MULTICASTif (inet_add_protocol(&igmp_protocol, IPPROTO_IGMP) < 0)printk(KERN_CRIT "inet_init: Cannot add IGMP protocol\n");
#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)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())printk(KERN_CRIT "inet_init: Cannot init ipv4 mroute\n");
#endif/**	Initialise per-cpu ipv4 mibs*/if (init_ipv4_mibs())printk(KERN_CRIT "inet_init: Cannot init ipv4 mibs\n");ipv4_proc_init();ipfrag_init();dev_add_pack(&ip_packet_type);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);
out_free_reserved_ports:kfree(sysctl_local_reserved_ports);goto out;
}fs_initcall(inet_init);

调用路径

  • start_kernel():内核的入口函数,位于 init/main.c 中,完成内核的基本初始化工作。
  • rest_init():在 start_kernel() 中被调用,创建内核初始化线程 kernel_init。
  • kernel_init():内核初始化线程的主函数,负责内核的后续初始化工作。
  • do_basic_setup():在 kernel_init() 中被调用,执行所有的初始化调用(initcall)。
  • do_initcalls():在 do_basic_setup() 中被调用,遍历所有的 initcall 函数,并依次执行它们。
  • inet_init():作为一个 __initcall 函数被调用,用于初始化 TCP/IP 协议栈。

proto_register():用于注册不同的协议(TCP、UDP、RAW、PING),将它们添加到协议列表中,以便后续处理。
sock_register():注册 socket 操作,包括创建和管理 socket 的方法。
inet_add_protocol():将各个传输层协议(如 ICMP、UDP、TCP)添加到网络层,以便接收和处理数据包。
模块初始化函数(如 arp_init(), ip_init(), tcp_v4_init(), 等):这些函数负责初始化各个网络模块,为后续的数据传输做好准备。



在看最后一行的处理函数

/***	dev_add_pack - add packet handler*	@pt: packet type declaration**	Add a protocol handler to the networking stack. The passed &packet_type*	is linked into kernel lists and may not be freed until it has been*	removed from the kernel lists.**	This call does not sleep therefore it can not*	guarantee all CPU's that are in middle of receiving packets*	will see the new packet type (until the next received packet).*/void dev_add_pack(struct packet_type *pt)
{struct list_head *head = ptype_head(pt);spin_lock(&ptype_lock);list_add_rcu(&pt->list, head);spin_unlock(&ptype_lock);
}
EXPORT_SYMBOL(dev_add_pack);

dev_add_pack 是 Linux 内核中用于添加数据包处理程序的函数。它将一个协议处理程序(packet handler)注册到网络栈中,以便在接收到特定类型的数据包时能够正确处理这些数据包。

具体来说:

  • 添加协议处理程序:将传入的 packet_type 结构体链接到内核的链表中,允许内核在接收到相应类型的数据包时调用相应的处理程序。
    struct packet_type {__be16			type;	/* This is really htons(ether_type). */struct net_device	*dev;	/* NULL is wildcarded here	     */int			(*func) (struct sk_buff *,struct net_device *,struct packet_type *,struct net_device *);struct sk_buff		*(*gso_segment)(struct sk_buff *skb,u32 features);int			(*gso_send_check)(struct sk_buff *skb);struct sk_buff		**(*gro_receive)(struct sk_buff **head,struct sk_buff *skb);int			(*gro_complete)(struct sk_buff *skb);void			*af_packet_priv;struct list_head	list;
    };
  • 非阻塞操作:该函数在执行过程中不会导致线程睡眠,这意味着它可以在任何上下文中被调用,包括中断上下文。

这么做有什么好处呢?

  • 网络协议处理:当网络设备接收到数据包时,内核会检查数据包类型,并调用相应的处理程序。通过 dev_add_pack() 注册的数据包处理程序会在接收到匹配的数据包时被触发。
  • 动态协议支持:可以在运行时动态地添加新的协议处理程序,而不需要重启内核或修改内核代码。这使得内核能够灵活地支持多种网络协议和功能。

那么,它如何如何根据数据包的类型来找到对应的链表头呢?

/*******************************************************************************Protocol management and registration routines*******************************************************************************//**	Add a protocol ID to the list. Now that the input handler is*	smarter we can dispense with all the messy stuff that used to be*	here.**	BEWARE!!! Protocol handlers, mangling input packets,*	MUST BE last in hash buckets and checking protocol handlers*	MUST start from promiscuous ptype_all chain in net_bh.*	It is true now, do not change it.*	Explanation follows: if protocol handler, mangling packet, will*	be the first on list, it is not able to sense, that packet*	is cloned and should be copied-on-write, so that it will*	change it and subsequent readers will get broken packet.*							--ANK (980803)*/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];
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/61470.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

使用 .NET 创建新的 WPF 应用

本教程介绍如何使用 Visual Studio 创建新的 Windows Presentation Foundation &#xff08;WPF&#xff09; 应用。 使用 Visual Studio&#xff0c;可以向窗口添加控件以设计应用的 UI&#xff0c;并处理这些控件中的输入事件以与用户交互。 在本教程结束时&#xff0c;你有一…

【机器学习chp3】判别式分类器:线性判别函数、线性分类器、广义线性分类器、分段线性分类器

前言&#xff1a; 本文遗留问题&#xff1a;&#xff08;1&#xff09;对最小平方误差分类器的理解不清晰.&#xff08;2&#xff09;分段线性判别函数的局部训练法理解不清晰。 推荐文章1&#xff0c;其中有关于感知机的分析 【王木头从感知机到神经网络】-CSDN博客 推荐文…

聚焦 NLP 和生成式 AI 的创新与未来 基础前置知识点

给学生们讲解的技术内容可以根据他们的背景、兴趣和教学目标来规划。以下是一些适合不同阶段和领域的技术主题建议&#xff0c;尤其是与大语言模型&#xff08;如 ChatGPT&#xff09;相关的内容&#xff1a; 1. 自然语言处理&#xff08;NLP&#xff09;基础 适合对 NLP 了解…

python3 Flask应用 使用 Flask-SQLAlchemy操作MySQL数据库

一、环境搭建 下载命令&#xff1a; pip install flask flask-sqlalchemy pymysql 二、创建项目结构 yourProjectFolder/ |—— app.py |—— config.py |—— models.py |__ mydb.py 三、基本使用 3.1 config.py 进行数据库连接配置 import osbasedir os.path.abspat…

深度学习:神经网络中线性层的使用

深度学习&#xff1a;神经网络中线性层的使用 在神经网络中&#xff0c;线性层&#xff08;也称为全连接层或密集层&#xff09;是基础组件之一&#xff0c;用于执行输入数据的线性变换。通过这种变换&#xff0c;线性层可以重新组合输入数据的特征&#xff0c;并将其映射到新…

Android中常见内存泄漏的场景和解决方案

本文讲解Android 开发中常见内存泄漏场景及其解决方案&#xff0c;内容包括代码示例、原因分析以及最佳实践建议。 1. 静态变量导致的内存泄漏 静态变量的生命周期与应用进程一致&#xff0c;如果静态变量持有了对 Activity 或其他大对象的引用&#xff0c;就可能导致内存泄漏…

docker-compose 安装 pgsql (postgres)

docker-compose-pg.yml 文件内容 version: 3 services:iepms-gateway:image: postgres:14.13container_name: postgresql-14.13restart: alwaysprivileged: trueenvironment:- POSTGRES_PASSWORD: test2024ports:- 15432:5432volumes:- /home/iepms/data/pgsql/data:/var/lib/…

Python 小高考篇(4)循环语句

目录 for 循环一个参数两个参数三个参数 while 循环break和continue语句break语句自测总结结尾 本文由Jzwalliser原创&#xff0c;发布在CSDN平台上&#xff0c;遵循CC 4.0 BY-SA协议。 因此&#xff0c;若需转载/引用本文&#xff0c;请注明作者并附原文链接&#xff0c;且禁止…

小程序20-样式:自适应尺寸单位 rpx

手机设备的宽度逐渐多元化&#xff0c;也就需要开发者开发过程中&#xff0c;去适配不同屏幕宽度的手机&#xff0c;为了解决屏幕适配问题&#xff0c;微信小程序推出了 rpx 单位 rpx&#xff1a;小程序新增的自适应单位&#xff0c;可以根据不同设备的屏幕宽度进行自适应缩放 …

网络安全,文明上网(1)享科技,提素养

前言 在这个信息化飞速发展的时代&#xff0c;科技的快速进步极大地丰富了我们的生活&#xff0c;并为我们提供了无限的可能性。然而&#xff0c;随着网络世界的不断扩张&#xff0c;增强我们的网络素养成为了一个迫切需要解决的问题。 与科技同行&#xff0c;培育网络素养 技术…

豆瓣书摘 | 爬虫 | Python

获取豆瓣书摘&#xff0c;存入MongoDB中。 import logging import timeimport requests from bs4 import BeautifulSoup from pymongo import MongoClientheaders {accept: text/html,application/xhtmlxml,application/xml;q0.9,image/avif,image/webp,image/apng,*/*;q0.8,…

JVM垃圾回收算法详解

在Java开发中&#xff0c;JVM&#xff08;Java虚拟机&#xff09;的垃圾回收机制是自动管理内存的关键部分。垃圾回收器&#xff08;Garbage Collector, GC&#xff09;通过一系列算法判断哪些对象可以被回收&#xff0c;从而释放内存空间供新对象使用。本文将深入探讨JVM中的垃…

Linux设置开机自动执行脚本 rc-local

使用/etc/rc.local 1、启动rc-local服务 首先授予执行权限 chmod x /etc/rc.d/rc.local设置开启自启并启动 sudo systemctl enable rc-local sudo systemctl start rc-local查看状态 sudo systemctl status rc-local2、编写要执行的脚本 vim /home/start.sh #!/bin/bash…

关于Redis单线程模型以及IO多路复用的理解

IO多路复用 -> redis主线程 -> 事件队列 -> 事件处理器 1.IO多路复用机制的作用&#xff1a; 操作系统的多路复用机制&#xff08;如 epoll、select&#xff09;负责监听多个文件描述符&#xff08;如客户端连接&#xff09;上的事件。 当某个文件描述符上的事件就绪…

针对AI增强图像大规模鲁棒性测试的数据集

Semi-Truths 是一个大规模的AI增强图像数据集&#xff0c;旨在评估和提升AI生成图像检测器的鲁棒性。该数据集包含了27,600张真实图像和1,472,700张通过多种增强技术生成的AI增强图像&#xff0c;这些图像覆盖了不同的扰动级别和数据分布。 Semi-Truths 的特点在于其详细的元数…

2. Django中的URL调度器 (自定义路径转换器)

在 Django 中&#xff0c;URL 路由通常使用路径转换器&#xff08;path converters&#xff09;来匹配和捕获 URL 中的特定模式&#xff0c;例如整数、字符串或 slug 等。默认情况下&#xff0c;Django 提供了一些内置的路径转换器&#xff0c;如 <int>、<str>、&l…

控制反转和依赖注入

控制反转 简称IOC。对象的创建控制权由程序自身转移到外部&#xff08;容器&#xff09;&#xff0c;这种思想称为控制反转。 使用Component注解去将其他层的实现类&#xff0c;交给IOC容器进行管理 依赖注入 简称DI。IOC容器为应用程序提供运行时&#xff0c;所依赖的资源…

Shell编程-5

声明&#xff1a;学习视频来自b站up主 泷羽sec&#xff0c;如涉及侵权马上删除文章 感谢泷羽sec 团队的教学 视频地址&#xff1a;shell&#xff08;5&#xff09;字符串运算符和逻辑运算符_哔哩哔哩_bilibili 一、字符串的比较 在Shell编程中&#xff0c;字符串比较是一个常见…

Python运算符列表

运算符 描述 xy&#xff0c;x—y 加、减,“"号可重载为连接符 x*y,x*&#xff0a;y&#xff0c;x/y,x&#xff05;y 相乘、求平方、相除、求余&#xff0c;“*”号可重载为重复&#xff0c;“&#xff05;"号可重载为格式化 <&#xff0c;<&#xff0c;&…

Tomcat和Nginx原理说明

Tomcat Tomcat 是一个开源的 Java 应用服务器&#xff0c;它由多个关键组件组成。这些组件共同协作&#xff0c;实现了 Servlet 容器的功能。以下是 Tomcat 的核心组件说明及其逻辑架构的示意图。 1. Tomcat 核心组件说明 (1) Server 描述&#xff1a;Tomcat 的顶级组件&…