Linux内核 -- Netlink使用

简介

Netlink 是 Linux 内核与用户空间通信的一种机制,提供了一种可扩展的、基于消息的接口。它最初是为网络配置而设计的,但现在已被扩展到许多其他内核子系统。Netlink 支持单播和多播通信。

Netlink 消息由头部和负载组成。头部包含消息的元数据,如消息类型和长度,而负载包含实际的数据。

c 复制代码
struct nlmsghdr {
    __u32 nlmsg_len;   // 消息长度
    __u16 nlmsg_type;  // 消息类型
    __u16 nlmsg_flags; // 标志
    __u32 nlmsg_seq;   // 序列号
    __u32 nlmsg_pid;   // 发送者的进程 ID
};

单播通信

单播通信是指消息从一个发送者发送到一个接收者。Netlink 单播通常用于请求-响应类型的通信。

单播通信示例

  1. 创建 Netlink 套接字:

    c 复制代码
    int sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
  2. 准备发送的消息:

    c 复制代码
    struct nlmsghdr *nlh = malloc(NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = 0;
    strcpy(NLMSG_DATA(nlh), "Hello");
    
    struct sockaddr_nl dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0; // 发送到内核
  3. 发送消息:

    c 复制代码
    sendto(sockfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
  4. 接收响应:

    c 复制代码
    recv(sockfd, nlh, NLMSG_SPACE(MAX_PAYLOAD), 0);
    printf("Received message payload: %s

", NLMSG_DATA(nlh));

复制代码
## 多播通信

多播通信允许一个发送者将消息发送到多个接收者。Netlink 多播通常用于通知机制,如网络接口状态变化。

### 多播通信示例

1. 创建 Netlink 套接字并加入多播组:
```c
int sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
struct sockaddr_nl local_addr;
memset(&local_addr, 0, sizeof(local_addr));
local_addr.nl_family = AF_NETLINK;
local_addr.nl_pid = getpid();
local_addr.nl_groups = RTMGRP_LINK;

bind(sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr));
  1. 准备并发送多播消息:

    c 复制代码
    struct nlmsghdr *nlh = malloc(NLMSG_SPACE(MAX_PAYLOAD));
    nlh->nlmsg_len = NLMSG_SPACE(MAX_PAYLOAD);
    nlh->nlmsg_pid = getpid();
    nlh->nlmsg_flags = NLM_F_REQUEST;
    strcpy(NLMSG_DATA(nlh), "Multicast Message");
    
    struct sockaddr_nl dest_addr;
    memset(&dest_addr, 0, sizeof(dest_addr));
    dest_addr.nl_family = AF_NETLINK;
    dest_addr.nl_pid = 0; // 发送到内核
    dest_addr.nl_groups = RTMGRP_LINK;
    
    sendto(sockfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr));
  2. 接收多播消息:

    c 复制代码
    recv(sockfd, nlh, NLMSG_SPACE(MAX_PAYLOAD), 0);
    printf("Received multicast message payload: %s

", NLMSG_DATA(nlh));

复制代码
## Netlink 内核接收用户态消息的实现

内核中接收用户态 Netlink 消息的实现需要在内核模块中注册一个 Netlink 套接字,并编写回调函数处理接收到的消息。

### 内核模块示例

1. 注册 Netlink 套接字:
```c
struct netlink_kernel_cfg cfg = {
    .input = netlink_recv_msg,
};

struct sock *nl_sk = netlink_kernel_create(&init_net, NETLINK_USER, &cfg);
if (!nl_sk) {
    printk(KERN_ALERT "Error creating Netlink socket.
");
    return -1;
}
  1. 实现消息接收回调函数:

    c 复制代码
    static void netlink_recv_msg(struct sk_buff *skb) {
        struct nlmsghdr *nlh = (struct nlmsghdr *)skb->data;
        printk(KERN_INFO "Received Netlink message payload: %s

", (char *)nlmsg_data(nlh));

}

复制代码
## nl_groups 字段的用法及注意事项

`nl_groups` 字段用于指定 Netlink 套接字加入的多播组。它可以是一个或多个多播组的位掩码。

### 使用示例

1. 创建套接字时指定多播组:
```c
struct sockaddr_nl local_addr;
memset(&local_addr, 0, sizeof(local_addr));
local_addr.nl_family = AF_NETLINK;
local_addr.nl_pid = getpid();
local_addr.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR; // 加入多个组

bind(sockfd, (struct sockaddr *)&local_addr, sizeof(local_addr));

注意事项

  • 加入多播组后,套接字将接收该组的所有消息,因此需要在应用程序中实现相应的消息过滤机制。
  • 多播组的位掩码可以通过内核头文件 (linux/rtnetlink.h) 中定义的宏来设置。

总结

Netlink 机制在 Linux 系统中非常强大,广泛用于内核与用户空间的通信。理解单播和多播通信的实现对系统编程和网络编程都有重要意义。同时,掌握 Netlink 的内核接收实现和多播组的使用方法,可以更高效地利用 Netlink 机制进行开发。

相关推荐
沸速存储33 分钟前
AI 机器人靠哪些内存与存储驱动整机运行?
服务器·科技·嵌入式硬件·电脑
码农小韩44 分钟前
Linux应用开发(八)——TCP/IP网络编程基础
linux·嵌入式软件开发·linux操作系统·嵌入式操作系统·linux网络编程·linux应用
迷途之人不知返1 小时前
【进程】-5-进程优先级
linux
fengyehongWorld1 小时前
Linux squid搭建基础代理服务器
linux·运维·服务器
木白CPP1 小时前
Linux DMA驱动详解(二)-----DMA的使用者
java·linux·运维
赵民勇2 小时前
systemd-socket-activate命令详解
linux·运维
Cx330❀2 小时前
【Linux网络】网络层 IP 协议:从网段划分到内核源码解析
大数据·linux·服务器·网络·tcp/ip·性能优化·langchain
企鹅的蚂蚁3 小时前
LubanCat RK3588 实时 Linux 开发(七):YT6801 PCIe 网卡驱动移植与 vermagic 排查
linux·rk3588·linux驱动·yt6801·pcie网卡·vermagic
DYWorker0013 小时前
Linux驱动子系统:DMA子系统 —— Consumer和Provider(006)
linux·驱动开发
byte轻骑兵3 小时前
【BlueZ】 log 模块:日志系统的实现与自定义日志输出配置
linux·人工智能·bluez·电脑蓝牙·嵌入式蓝牙