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

news2024/11/18 9:13:09

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_SYSCTL
	ip_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_MULTICAST
	if (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;
	else
		return &ptype_base[ntohs(pt->type) & PTYPE_HASH_MASK];
}

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

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

相关文章

【插件】多断言 插件pytest-assume

背景 assert 断言一旦失败&#xff0c;后续的断言不能被执行 有个插件&#xff0c;pytest-assume的插件&#xff0c;可以提供多断言的方式 安装 pip3 install pytest-assume用法 pytest.assume(表达式,f’提示message’) pytest.assume(表达式,f‘提示message’) pytest.ass…

虾皮:LLM注意力机制的下沉现象分析

&#x1f4d6;标题&#xff1a;When Attention Sink Emerges in Language Models: An Empirical View &#x1f310;来源&#xff1a;arXiv, 2410.10781 &#x1f31f;摘要 &#x1f538;语言模型&#xff08;LM&#xff09;将大量注意力分配给第一个标记&#xff0c;即使它在…

MyBatis的select标签的resultType属性

在MyBatis框架中&#xff0c;映射文件中select标签的resultType属性&#xff0c;用于指定从数据库查询返回结果集需要映射的Java类型&#xff0c;即Mapper接口中方法返回值类型(或集合中的泛型类型)&#xff0c;可以是基本数据类型、基本数据类型的包装类型、自定义的PO类型、集…

ubuntu20.04如何升级python3.8到python3.10

主要参考了这两个链接&#xff1a; 如何在Ubuntu 20.04安装Python 3.10 | myfreaxhttps://www.myfreax.com/how-to-install-python-3-10-on-ubuntu-20-04/#:~:text%E5%9C%A8%E8%B0%83%E8%AF%95%E5%92%8C%E5%85%B6%E4%BB%96%E5%B7%A5%E5%85%B7%E4%B8%AD%E4%BD%BF%E7%94%A8%E7%B…

AWTK-WIDGET-WEB-VIEW 发布

awtk-widget-web-view 是通过 webview 提供的接口&#xff0c;实现的 AWTK 自定义控件&#xff0c;使得 AWTK 可以方便的显示 web 页面。 项目网址&#xff1a; https://gitee.com/zlgopen/awtk-widget-web-view webview 提供了一个跨平台的 webview 接口&#xff0c;是一个非…

丹摩征文活动|FLUX.1+ComfyUI部署与使用

丹摩征文活动&#xff5c;FLUX.1ComfyUI部署与使用 1.引言 在人工智能飞速发展的今天&#xff0c;丹摩智算平台&#xff08;DAMODEL&#xff09;以其卓越的AI算力服务脱颖而出&#xff0c;为开发者提供了一个简化AI开发流程的强大工具。通过租赁GPU资源&#xff0c;丹摩智算平…

性能高于Transformer模型1.7-2倍,彩云科技发布基于DCFormer架构通用大模型云锦天章

2017年&#xff0c;谷歌发布《Attention Is All You Need》论文&#xff0c;首次提出Transformer架构&#xff0c;掀开了人工智能自然语言处理&#xff08;NLP&#xff09;领域发展的全新篇章。Transformer架构作为神经网络学习中最重要的架构&#xff0c;成为后来席卷全球的一…

【异常解决】Linux shell报错:-bash: [: ==: 期待一元表达式 解决方法

博主介绍&#xff1a;✌全网粉丝21W&#xff0c;CSDN博客专家、Java领域优质创作者&#xff0c;掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域✌ 技术范围&#xff1a;SpringBoot、SpringCloud、Vue、SSM、HTML、Nodejs、Python、MySQL、PostgreSQL、大数据、物…

Linux解决普通用户无法使用sudo指令的问题

问题描述&#xff1a; Linux解决普通用户无法使用sudo指令的问题 sudo 指令是允许 普通用户 临时 以 超级用户 root 的权限运行。 普通用户如果没有配置而直接使用 sudo 指令&#xff1a;系统会提示没有权限&#xff08;如下图&#xff09; 使用sudo时系统提示&#xff08;当前…

9.1 使用haarcascade_frontalface_default.xml分类器对静态图像进行人脸检测。

1&#xff09;程序代码&#xff1a; # 1. 使用haarcascade_frontalface_default.xml分类器对静态图像进行人脸检测。 import cv2 import numpy as np # 构造级联分类器对象face_cascade cv2.CascadeClassifier(./data/haarcascades/haarcascade_frontalface_default.xml# ./…

【Mysql】Mysql函数----字符串函数

1、字符串函数 函数 描述 示例 CHAR_LENGTH(S) 返回字符串S的字符个数 返回字符串runoob的字符个数&…

(干货)Jenkins使用kubernetes插件连接k8s的认证方式

#Kubernetes插件简介 Kubernetes 插件的目的是能够使用 Kubernetes 配合&#xff0c;实现动态配置 Jenkins 代理&#xff08;使用 Kubernetes 调度机制来优化负载&#xff09;&#xff0c;在执行 Jenkins Job 构建时&#xff0c;Jenkins Master 会在 kubernetes 中创建一个 Sla…

微积分第五版课后习题答案详解PDF电子版 赵树嫄

(一) 习题解答与注释 该部分基本上对《微积分》(第五版) 中的习题给出了解答&#xff0c; 并结合教与学作了大量注释。通过这些注释&#xff0c; 读者可以深刻领会教材中基本概念的准确含义&#xff0c; 开阔解题思路&#xff0c; 掌握解题方法&#xff0c; 避免在容易发生错误…

【Linux庖丁解牛】—权限!

目录 1、shell命令以及运行原理 2、Linux中的用户及用户切换 3、sudo指令 ​编辑 4、角色与目标属性 5、修改权限 5.1修改文件属性(chmod) 5.2修改文件角色(chown/chgrp) 6、rwx对目录意味着什么 7、Linux中多用户之间的相互“隔离” 8、Linux中的缺省权限 ​编辑 9…

uniapp对接极光推送,实现消息推送功能

通过集成JG-JPush和JG-JCore插件&#xff0c;可以在应用中添加消息推送功能&#xff0c;向用户发送通知、消息等。这对于提升用户体验、增加用户粘性非常有帮助‌。 效果图&#xff1a; 一、登录极光官网 官网链接&#xff1a;portalhttps://www.jiguang.cn/console/#/home点…

【3D Slicer】的小白入门使用指南八

3D Slicer DMRI(Diffusion MRI)-扩散磁共振认识和使用 0、简介 大脑解剖 ● 白质约占大脑的 45% ● 有髓神经纤维(大约10微米轴突直径) 白质探索 朱尔斯约瑟夫德杰林(Jules Joseph Dejerine,《神经中心解剖学》(巴黎,1890-1901):基于髓磷脂染色标本的神经解剖图谱)…

IP数据云 识别和分析tor、proxy等各类型代理

在网络上使用代理&#xff08;tor、proxy、relay等&#xff09;进行访问的目的是为了规避网络的限制、隐藏真实身份或进行其他的不正当行为。 对代理进行识别和分析可以防止恶意攻击、监控和防御僵尸网络和提高防火墙效率等&#xff0c;同时也可以对用户行为进行分析&#xff…

GPU分布式通信技术-PCle、NVLink、NVSwitch深度解析

GPU分布式通信技术-PCle、NVLink、NVSwitch 大模型时代已到来&#xff0c;成为AI核心驱动力。然而&#xff0c;训练大模型却面临巨大挑战&#xff1a;庞大的GPU资源需求和漫长的学习过程。 要实现跨多个 GPU 的模型训练&#xff0c;需要使用分布式通信和 NVLink。此外&#xf…

基于 PyTorch 从零手搓一个GPT Transformer 对话大模型

一、从零手实现 GPT Transformer 模型架构 近年来&#xff0c;大模型的发展势头迅猛&#xff0c;成为了人工智能领域的研究热点。大模型以其强大的语言理解和生成能力&#xff0c;在自然语言处理、机器翻译、文本生成等多个领域取得了显著的成果。但这些都离不开其背后的核心架…

数据集的重要性:如何构建AIGC训练集

文章目录 一、为什么数据集对AIGC如此重要&#xff1f;1. 数据决定模型的知识边界2. 数据质量直接影响生成效果3. 数据集多样性提升模型鲁棒性 二、构建AIGC训练集的关键步骤1. 明确目标任务和生成需求2. 数据源的选择3. 数据清洗与预处理4. 数据标注5. 数据增强 三、针对不同类…