在上一篇文章中,我们给出了示例代码,下边就示例代码中的关键部分做一解读:
1. struct netlink_kernel_cfg 结构体
1. 定义
通常位于内核头文件 /usr/src/linux-5.15-headers-x.x/include/linux/netlink.h :
struct netlink_kernel_cfg {
unsigned int groups; // 允许的组数
unsigned int flags; // 标记
void (*input)(struct sk_buff *skb); // 输入处理回调
struct mutex *cb_mutex;
int (*bind)(struct net *net, int group); // 绑定回调
void (*unbind)(struct net *net, int group); // 解绑回调
bool (*compare)(struct net *net, struct sock *sk);
};
2. 结构体参数说明
- groups:
- 类型:
unsigned int - 描述:指定允许的 Netlink 组数。Netlink 组用于多播消息的发送和接收,允许多个用户空间进程订阅同一组的消息。
- 类型:
- input:
- 类型:指向函数的指针,函数签名为
int (*input)(struct sk_buff *skb) - 描述:这是一个回调函数,用于处理接收到的 Netlink 消息。当内核接收到来自用户空间的消息时,会调用此函数进行处理。skb 是指向 socket 缓冲区的指针,包含了接收到的数据。
- 类型:指向函数的指针,函数签名为
- bind:
- 类型:指向函数的指针,函数签名为
int (*bind)(struct netlink_sock *sock, struct netlink_kernel_cfg *cfg) - 描述:这是一个可选的回调函数,用于在绑定 Netlink 套接字时执行特定的操作。可以在此函数中进行额外的初始化或配置。
- 类型:指向函数的指针,函数签名为
3. 作用
netlink_kernel_cfg结构体用于配置 Netlink 套接字,包含了允许的组数、输入处理函数和绑定函数等参数。- 通过合理配置 netlink_kernel_cfg,可以实现内核与用户空间之间的高效通信,处理网络相关的消息和事件。
2. init_net 全局变量
在 Linux 内核中,init_net 是一个全局变量,表示系统初始化时创建的默认网络命名空间(network namespace)。它是一个 struct net 类型的结构体实例,包含了与网络相关的各种信息和状态。
1. init_net 的作用
- 默认网络命名空间:
init_net代表了系统启动时的网络命名空间,所有未特别指定命名空间的网络操作都将在这个命名空间中进行。 - 网络资源管理:它包含了与网络相关的资源和状态,例如网络接口、路由表、套接字等。
2. 在示例中的使用
在之前的示例中,init_net 被用作创建 Netlink 套接字的上下文:
nl_sock = netlink_kernel_create(&init_net, MY_MOD_NETLINK_TOKEN, &cfg);
- 参数解释:
&init_net:传递init_net的地址,表示要在默认网络命名空间中创建 Netlink 套接字。MY_MOD_NETLINK_TOKEN:指定 Netlink 套接字的类型。&cfg:传递配置结构体,包含了允许的组数和输入处理函数等。
3. 网络命名空间的概念
- 命名空间:Linux 的网络命名空间允许将网络资源(如网络接口、路由表等)隔离,使得不同的进程可以在不同的网络环境中运行。
- init_net:作为默认命名空间,
init_net是所有进程在没有指定其他命名空间时使用的网络环境。
4. 总结
init_net是 Linux 内核中表示默认网络命名空间的全局变量。- 在创建 Netlink 套接字时,使用
init_net作为上下文,确保套接字在默认网络命名空间中运行。 - 通过网络命名空间,Linux 提供了灵活的网络资源管理和隔离机制。
3. NLMSG_SPACE 与NLMSG_DATA 宏定义
在 Linux 内核中,NLMSG_SPACE 和 NLMSG_DATA 两个宏定义用于处理 Netlink 消息的结构和数据。这两个宏的使用是为了简化 Netlink 消息的管理和访问,确保代码的可读性和正确性。
1. NLMSG_SPACE 宏
-
定义:
#define NLMSG_SPACE(len) ((len) + NLMSG_HDRLEN) -
作用:
NLMSG_SPACE用于计算 Netlink 消息所需的总字节数,包括消息头的长度和有效载荷的长度。NLMSG_HDRLEN是 Netlink 消息头的长度,通常是固定的。
-
重要性:
- 内存分配:在创建 Netlink 消息时,使用
NLMSG_SPACE可以确保分配足够的内存来存储整个消息,包括头部和数据部分。 - 避免错误:通过使用这个宏,可以避免手动计算消息长度时可能出现的错误,确保消息结构的完整性。
- 内存分配:在创建 Netlink 消息时,使用
2. NLMSG_DATA 宏
-
定义:
#define NLMSG_DATA(nlh) ((void *)(((char *)nlh) + NLMSG_HDRLEN)) -
作用:
NLMSG_DATA用于获取指向 Netlink 消息有效载荷的指针。它通过将消息头的指针偏移NLMSG_HDRLEN的长度来实现。- 这个宏返回一个指向有效载荷数据的指针,方便后续的数据处理。
-
重要性:
- 简化访问:使用
NLMSG_DATA可以简化访问 Netlink 消息有效载荷的过程,避免手动计算偏移量。 - 提高可读性:通过使用宏,代码的可读性提高,其他开发者可以更容易理解消息的结构。
- 简化访问:使用
3. 示例
-
以下是一个简单的示例,展示如何使用这两个宏:
struct nlmsghdr *message; int msglen = sizeof(my_data); // 分配内存 message = (struct nlmsghdr *)malloc(NLMSG_SPACE(msglen)); // 设置消息头 message->nlmsg_len = NLMSG_SPACE(msglen); message->nlmsg_type = MY_NETLINK_TYPE; // 访问有效载荷 memcpy(NLMSG_DATA(message), &my_data, msglen);
4. 总结
NLMSG_SPACE和NLMSG_DATA是用于处理 Netlink 消息的两个重要宏。NLMSG_SPACE确保分配足够的内存以容纳整个消息,而NLMSG_DATA提供了一个方便的方式来访问消息的有效载荷。- 这两个宏的使用提高了代码的安全性、可读性和可维护性,减少了出错的可能性。