netlink怎么读_ovs源码阅读--netlink使用

news/2024/6/18 13:24:41 标签: netlink怎么读

netlink socket是一种用于用户态进程和内核态进程之间的通信机制。它通过为内核模块提供一组特殊的API,并为用户程序提供了一组标准的socket接口的方式,实现了全双工的通讯连接。

特点:

双向传输,异步通信

用户空间中使用标准socket API

内核空间中使用专门的API

支持多播

可由内核端发起通信

支持32种协议类型

netlink仅支持32种协议类型,这在实际应用中可能并不足够,因此产生了generic netlink(以下简称为genl),

generic netlink支持1023个子协议号,弥补了netlink协议类型较少的缺陷。

netlink通信架构

Netlink子系统:所有genl通信的基础,Netlink子系统中收到的所有Generic类型的netlink数据都被送到genl总线上;从内核发出的数据也经由genl总线送至netlink子系统,再打包送至用户空间

Generic Netlink控制器:作为内核的一部分,负责动态地分配genl通道(即genl family id),并管理genl任务,genl控制器是一个特殊的genl内核用户,它负责监听genl bus上的通信通道

genl通信建立在一系列的通信通道的基础上,每个genl family对应多个通道,这些通道由genl控制器动态分配

相关结构体

genl family

Generic Netlink是基于客户端-服务端模型的通信机制,服务端注册family(family是对genl服务的各项定义的集合),控制器和客户端都通过已注册的信息与服务端通信。

//genl_family主要字段

struct genl_family

{

unsigned int id; //family id unsigned int hdrsize; //用户自定议头部长度 char name[GENL_NAMSIZ]; //family名,要求不同的family使用不同的名字 unsigned int version; //版本 unsigned int maxattr; //最大attr类型数,使用netlink标准的attr来传输数据 genl_ops *ops; // 操作集合 };

genl_ops

定义了netlink family相关的操作

// genl_ops主要字段

struct genl_ops

{

u8 cmd; //命令名,用于识别genl_ops unsigned int flags; //设置属性 struct nla_policy *policy; //定义了attr规则,genl在触发事件处理程序之前,会用其进行attr校验 int (*doit)(struct sk_buff *skb, struct genl_info *info); int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb); };

doit:回调函数,在generic netlink收到数据时触发,运行在进程上下文

dumpit:回调函数,当genl_ops的flag标志被添加了NLM_F_DUMP以后,每次收到genl消息即会回触发这个函数

dumpit与doit的区别是:dumpit的第一个参数skb不会携带从客户端发来的数据。相反地,开发者应该在skb中填入需要传给客户端的数据,skb中携带的数据会被自动送到客户端。只要dumpit的返回值大于0,dumpit函数就会再次被调用,并被要求在skb中填入数据。当服务端没有数据要传给客户端时,dumpit要返回0。如果函数中出错,要求返回一个负值。

nal_policy

定义了attr规则

struct nla_policy

{

u16 type; //attr中的数据类型 u16 len; //如果在type字段配置的是字符串有关的值,要把len设置为字符串的最大长度 };

genl_info

内核在接收到用户的genetlink消息后,会对消息解析并封装成genl_info结构

struct genl_info

{

u32 snd_seq; //发送序号 u32 snd_pid; //发送客户端的PID struct nlmsghdr * nlhdr; //netlink header的指针 struct genlmsghdr * genlhdr; //genl头部的指针(即family头部) void * userhdr; //用户自定义头部指针 struct nlattr ** attrs; //如果定义了genl_ops->policy,保存被policy过滤以后的结果 };

Generic Netlink服务端(内核)初始化

这里以OVS中packet的处理为例:

1. 定义family

//定义packet family

static struct genl_family dp_packet_genl_family __ro_after_init = { .hdrsize = sizeof(struct ovs_header), .name = OVS_PACKET_FAMILY, .version = OVS_PACKET_VERSION, .maxattr = OVS_PACKET_ATTR_MAX, .netnsok = true, .parallel_ops = true, .ops = dp_packet_genl_ops, //操作集合 .n_ops = ARRAY_SIZE(dp_packet_genl_ops), .module = THIS_MODULE, };

2. 定义operation

// 定义packet family 的操作 --- packet类型的操作只支持OVS_PACKET_CMD_EXECUTE

static struct genl_ops dp_packet_genl_ops[] = { { .cmd = OVS_PACKET_CMD_EXECUTE, .flags = GENL_UNS_ADMIN_PERM, .policy = packet_policy, .doit = ovs_packet_cmd_execute //接受数据包时,调用ovs_packet_cmd_execute进行处理 } }; // 定义packet family 的过滤规则 static const struct nla_policy packet_policy[OVS_PACKET_ATTR_MAX + 1] = { [OVS_PACKET_ATTR_PACKET] = { .len = ETH_HLEN }, [OVS_PACKET_ATTR_KEY] = { .type = NLA_NESTED }, [OVS_PACKET_ATTR_ACTIONS] = { .type = NLA_NESTED }, [OVS_PACKET_ATTR_PROBE] = { .type = NLA_FLAG }, [OVS_PACKET_ATTR_MRU] = { .type = NLA_U16 }, };

3. 注册family

genl_register_family(&dp_packet_genl_family);

Generic Netlink客户端(用户空间)初始化

struct sockaddr_nl saddr;

int sock; sock = socket(AF_NETLINK, SOCK_RAW, NETLINK_GENERIC); //创建一个netlink类型的socket if (sock < 0) { return -1; } memset(&saddr, 0, sizeof(saddr)); saddr.nl_family = AF_NETLINK; saddr.nl_pid = getpid(); //获取family id if (bind(sock, (struct sockaddr*)&saddr, sizeof(saddr)) < 0) { //绑定 printf("bind fail!\n"); close(*p_sock); return -1; }

内核空间接受发送数据

接受数据:内核端一旦收到generic netlink数据,会触发doit函数运行,通过回调函数进行处理

发送数据:将数据打包好之后,可通过单播(genlmsg_unicast)或多播()的形式进行发送

用户空间接受发送数据

接受数据:调用recv函数即可完成从内核来的数据的接收

发送数据:调用sendto来发送数据

netlink收发数据—以ovs中packet为例

参考内容


http://www.niftyadmin.cn/n/764339.html

相关文章

牛客网_检查重复字符串

解答&#xff1a; 1、正则表达式的方向引用 function containsRepeatingLetter(str) {return /([a-zA-Z])\1/.test(str); } \1涉及正则表达式中反向引用的概念&#xff0c;参考&#xff1a;正则表达式中的反向引用 2、字符串方法 function containsRepeatingLetter(str) {…

ethtool如何让接口闪灯_linux网卡模式设置mii-tool和ethtool

DEV了mii-tool 更改网络接口协商的方法&#xff1a;# mii-tool --helpusage: mii-tool [-VvRrwl] [-A media,... | -F media] [interface...]-v, --verbose more verbose output 注&#xff1a;显示网络接口的信息&#xff1b;-R, --reset reset MII to poweron state 注&#…

python中pop函数删除0为什么显示的是1_python,一个类的函数中,列表明明为空,但为什么pop的时候不抛异常??...

#encodingGBKimportosclassDirectoryWalker:def__init__(self,directory):#只被执行一次self.stack[directory]self.files[]self.index0def__getitem__(self,index):while1:try:fi...#encodingGBKimport osclass DirectoryWalker:def __init__(self,directory):#只被执行一次se…

javascript中的动态集合——NodeList、HTMLCollection、NamedNodeMap

一、NodeList、HTMLCollection、NamedNodeMap的相同点与不同点 &#xff08;1&#xff09;相同点 1. 三者都是类数组对象 2. 都有item()方法 &#xff08;2&#xff09;不同点 1. NodeList是节点&#xff08;12种&#xff09;的集合、HTMLCollection是元素节点的集合、Nam…

oracle改成归档模式_修改oracle为归档模式

修改oracle为归档模式1&#xff0c;查看是否为归档模式SQL> archive log list;Database log mode No Archive ModeAutomatic archival DisabledArchive destination USE_DB_RECOVERY_FILE_DESTOldest online log sequence 31Curren…

javascript中的深浅拷贝(非构造函数的继承)

首先&#xff0c;我们应该明确深浅拷贝是针对Array、Object这样的复杂类型的。 一 常见的深浅拷贝的方法 &#xff08;1&#xff09;数组和对象的浅拷贝 如果是数组&#xff0c;我们可以利用数组的一些方法比如&#xff1a;slice、concat 返回一个新数组的特性来实现拷贝。 …

centos7 r语言安装_centos7安装R语言(epel-release源)

本文介绍在centos7下通过epel-release源安装R语言&#xff0c;此方法简单粗暴&#xff0c;类似于ubuntu下的sudo apt-get install r-base&#xff0c;值得拥有&#xff0c;具体步骤如下&#xff1a;1、安装epel-release&#xff0c;执行命令sudo yum install -y epel-release注…

javascript中new的模拟实现

new 运算符创建一个用户定义的对象类型的实例或具有构造函数的内置对象的实例。 语法&#xff1a;new constructor[([arguments])] 那么什么是构造函数呢&#xff1f; 构造函数 constructor 是用于创建和初始化类中创建的一个对象的一种特殊方法。 &#xff08;1&#xff09;我…