首页 > 其他分享 >3.4 ICMPv6 初始化

3.4 ICMPv6 初始化

时间:2024-04-05 18:00:19浏览次数:211  
标签:初始化 err icmpv6 init sk ICMPv6 3.4 icmp

3.4 ICMPv6 初始化

1. ICMPv6 简述

ICMPv6 除了跟 ICMPv4 一样负责错误处理诊断之外,还负责邻居发现( Neighbour Discovery ND )组播侦听者发现(Multicast Listener Discover MLD)

  • 邻居发现(ND) -- ARP(IPV4)
  • 组播侦听者发现(MLD) --IGMP(IPV4)

但是这两个功能会放在后面去解析,本章节还是学习 ICMPv6 和 ICMPv4 相同的部分。另外同ICMPv4 一样,不能将ICMPv6 构建成内核模块。原因见 ICMPv4 附录。

2. ICMPv6 初始化

首先就是 ICMPv6 在网络协议栈中的初始化。ICMPv6 同 ICMPv4 一样,附属于IP层三层网络协议,所以和TCPv6、UDPv6一样,在inet6_init()中完成初始化。

static int __init inet6_init(void)
{
    ...
	err = icmpv6_init();
	if (err)
		goto icmp_fail;
	...
}

inet6_init()中,调用 icmpv6_init()函数对ICMPv6 进行初始化。跟 ICMPv4 初始化有一点点的区别是,在 ICMPv4中,协议注册和内核初始化是分开的,而 ICMPv6 中,它们都在 icmpv6_init() 中进行处理。怎么说呢,毕竟是后者,进行代码整理和优化也是应该的。ICMPv6 很多地方都体现了编码优化的身影。

int __init icmpv6_init(void)
{
	int err;
    
	err = register_pernet_subsys(&icmpv6_sk_ops);
	if (err < 0)
		return err;

	err = -EAGAIN;
	if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
		goto fail;

	err = inet6_register_icmp_sender(icmp6_send);
	if (err)
		goto sender_reg_err;
	return 0;
	...
}

2.1 ICMPv6 内核模块初始化

在 ICMPv6 中,首先执行的是 ICMPv6 的内核套接字创建初始化

static struct pernet_operations icmpv6_sk_ops = {
	.init = icmpv6_sk_init,
	.exit = icmpv6_sk_exit,
};

int __init icmpv6_init(void)
{
	err = register_pernet_subsys(&icmpv6_sk_ops);
	if (err < 0)
		return err;
	...
}

最终ICMPv6 内核模块初始化函数注册在了icmpv6_sk_init()上。这个函数主要完成如下功能:

  • 为每个CPU创建 ICMPv6 原始套接字,并储存在数组中。

    static int __net_init icmpv6_sk_init(struct net *net)
    {
    	struct sock *sk;
    	int err, i, j;
    
    	// 申请足够空间
    	net->ipv6.icmp_sk =
    		kcalloc(nr_cpu_ids, sizeof(struct sock *), GFP_KERNEL);
    	if (!net->ipv6.icmp_sk)
    		return -ENOMEM;
    
    	// 遍历每个CPU,为每个CPU创建ICMPv6原始套接字
    	for_each_possible_cpu (i) {
    		err = inet_ctl_sock_create(&sk, PF_INET6, SOCK_RAW,
    					   IPPROTO_ICMPV6, net);
    		if (err < 0) {
    			pr_err("Failed to initialize the ICMP6 control socket (err %d)\n",
    			       err);
    			goto fail;
    		}
    		// 将套接字存放在ICMPv6 原始套接字的数组中
    		net->ipv6.icmp_sk[i] = sk;
    
    		/* Enough space for 2 64K ICMP packets, including
    		 * sk_buff struct overhead.
    		 */
    		sk->sk_sndbuf = 2 * SKB_TRUESIZE(64 * 1024);
    	}
    	return 0;
    
    fail:
    	// 创建失败则销毁所有ICMPv6 原始套接字,并释放数组空间
    	for (j = 0; j < i; j++)
    		inet_ctl_sock_destroy(net->ipv6.icmp_sk[j]);
    	kfree(net->ipv6.icmp_sk);
    	return err;
    }
    

    和ICMPv4 不同的是,ICMPv6 似乎并没有一些协议上参数的限制。比如限速等。

2.2 ICMPv6 收包处理函数初始化

ICMPv6 协议结构体:

struct inet6_protocol icmpv6_protocol = {
	.handler	=	icmpv6_rcv,
	.err_handler	=	icmpv6_err,
	.flags		=	INET6_PROTO_NOPOLICY|INET6_PROTO_FINAL,
};

int __init icmpv6_init(void)
{
    ...
	err = -EAGAIN;
	if (inet6_add_protocol(&icmpv6_protocol, IPPROTO_ICMPV6) < 0)
		goto fail;
	...
}
  • icmpv6_rcv icmpv6 的数据包处理函数,在处理IP报文时,协议字段为IPPROTO_ICMPV6(58)时,就是用icmpv6_rcv()来处理。
  • INET6_PROTO_NOPOLICY 标志着不使用ipsec进行安全策略检查。
  • INET6_PROTO_FINAL 标志着该协议在这一层是最终的协议封装,不会再有其他协议。以避免意外的协议嵌套。

2.3 注册 ICMPv6 数据包发送函数

static ip6_icmp_send_t __rcu *ip6_icmp_send;
int inet6_register_icmp_sender(ip6_icmp_send_t *fn)
{
	return (cmpxchg((ip6_icmp_send_t **)&ip6_icmp_send, NULL, fn) == NULL) ?
		0 : -EBUSY;
}

int __init icmpv6_init(void)
{
	...
	err = inet6_register_icmp_sender(icmp6_send);
	...
}

这个处理比较简单,仅仅是为 ICMPv6 的发送报文函数指针ip6_icmp_send注册发送函数为 icmp6_send(), 发送函数的实现将在后面展开。

初始化部分完成。下一节将介绍ICMPv6 报文格式和报文类型。

标签:初始化,err,icmpv6,init,sk,ICMPv6,3.4,icmp
From: https://www.cnblogs.com/kmist/p/18116013

相关文章

  • C# 构造函数 (初始化成员变量的角色)
    构造函数是一种特殊的方法。创建对象时会自动调用它。构造函数不返回值。构造函数的目的是初始化对象的状态。构造函数与类具有相同的名称。构造函数是方法,因此它们也可以重载。构造函数不能被继承。它们按继承顺序被调用。如果我们不为类编写任何构造函数,则C#提供一个......
  • 顺序表的定义,初始化,增加删除,按值按位查找
    这是一个使用C++语言实现的顺序表。顺序表是一种线性表,它的元素在物理上是连续存储的。这里的顺序表是用数组来实现的。以下是对代码中函数的简单解释:InitList(SeqList&L):初始化顺序表,将所有元素赋值为0,长度为0。ListInsert(SeqList&L,inti,intc):在顺序表的第i个位......
  • 第五篇:3.4 用户归因和受众(User attribution and audience) - IAB/MRC及《增强现实广告
    翻译计划第一篇概述—IAB与MRC及《增强现实广告效果测量指南》之目录、适用范围及术语第二篇广告效果测量定义和其他矩阵之-3.1广告印象(ADImpression)第三篇广告效果测量定义和其他矩阵之-3.2可见性(Viewability)第四篇广告效果测量定义和其他矩阵之-3.3无效流量(Invali......
  • Vue2电商前台项目(一):项目前的初始化及搭建
    一、项目初始化创建项目:sudovuecreateapp1.项目配置(1)浏览器自动打开在package.json文件中,serve后面加上--open"scripts":{"serve":"vue-cli-serviceserve--open","build":"vue-cli-servicebuild","lint":&q......
  • 2023.4 做题记录
    2023.4做题记录[NOIP2018提高组]旅行看到题目中要求\(m=n\)或\(m=n-1\),此时就应当分类讨论。①当\(m=n-1\)时:此时数据为一颗树。我们贪心的想:起始点为\(1\)的时候显然最优。对于每一个节点,在它子树内按照从小到大的顺序遍历显然最优。复杂度\(O(n\logn)\),瓶颈......
  • 华为 2023年4月19日 实习 机试第一题——批量初始化次数
    某部门在开发一个代码分析工具,需要分析模块之间的依赖关系,用来确定模块的初始化顺序,是否有循环依期等问题。“批量初始化”是指一次可以初始化一个或多个模块。例如模块1依赖模块2,模块3也依赖模块2,但模块1和3没有依赖关系,则必须先“批量初始化”模块2,再“批......
  • js 可以间接地“声明”或初始化变量的其他方式(除了直接使用var、let和const)
    在JavaScript中,除了直接使用var、let和const关键字来声明变量外,还有一些其他方式可以间接地“声明”或初始化变量。以下是一些示例:函数参数:当定义一个函数时,函数的参数列表中的每个参数实际上都会成为该函数作用域内的变量。这些变量在函数被调用时会被自动声明和初始化。func......
  • 初始化kubeadm init失败,再次初始化时显示6443、10259、10257、10250、2379、2380被占
    第一次使用kubeadminit初始化时,因kubelet.service和和kubelet未启动等部分原因导致初始化失败,当再次初始化时显示6443、10259、10257、10250、2379、2380这几个端口被占用,一个个使用sudolsof-i:port查看太麻烦,直接使用kubeadmreset将当前节点恢复为未安装Kubernetes的状......
  • MDK中如何使用STM32CubeMX来配置工程和生成初始化代码?
    在MDK中使用STM32CubeMX配置工程和生成初始化代码是一个高效的开发流程,它可以显著提高开发效率并减少手动配置错误。以下是详细的步骤和示例代码,展示如何使用STM32CubeMX来配置工程,并将其与MDK结合使用。1.安装STM32CubeMX首先,访问STMicroelectronics的官方网站,下载并安......
  • yolov8逐步分解(2)_DetectionTrainer类初始化过程
     接上篇文章yolov8逐步分解(1)--默认参数&超参配置文件加载继续讲解。 1.默认配置文件加载完成后,创建对象trainer时,需要从默认配置中获取类DetectionTrainer初始化所需的参数args,如下所示deftrain(cfg=DEFAULT_CFG,use_python=False):  """TrainandoptimizeYOLO......