Linux内核 — Netlink使用

Linux内核 — Netlink使用netlink netlink

大家好,欢迎来到IT知识分享网。

Linux Netlink 机制

简介

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

Netlink 消息的基本结构

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

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

单播通信

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

单播通信示例

  1. 创建 Netlink 套接字:
    int sockfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); 
  2. 准备发送的消息:
    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. 发送消息:
    sendto(sockfd, nlh, nlh->nlmsg_len, 0, (struct sockaddr *)&dest_addr, sizeof(dest_addr)); 
  4. 接收响应:
    recv(sockfd, nlh, NLMSG_SPACE(MAX_PAYLOAD), 0); printf("Received message payload: %s", NLMSG_DATA(nlh)); 

多播通信

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

多播通信示例

  1. 创建 Netlink 套接字并加入多播组:
    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)); 
  2. 准备并发送多播消息:
    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)); 
  3. 接收多播消息:
    recv(sockfd, nlh, NLMSG_SPACE(MAX_PAYLOAD), 0); printf("Received multicast message payload: %s", NLMSG_DATA(nlh)); 

Netlink 内核接收用户态消息的实现

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

内核模块示例

  1. 注册 Netlink 套接字:
    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; } 
  2. 实现消息接收回调函数:
    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. 创建套接字时指定多播组:
    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 内核向用户态发送消息的实现

广播代码示例

#include <linux/module.h> #include <linux/netlink.h> #include <linux/skbuff.h> #include <net/sock.h> #define NETLINK_USER 31 #define MULTICAST_GROUP 1 struct sock *nl_sk = NULL; static void send_netlink_broadcast(char *msg, int msg_size) { 
    struct sk_buff *skb_out; struct nlmsghdr *nlh; int res; skb_out = nlmsg_new(msg_size, GFP_KERNEL); if (!skb_out) { 
    pr_err("Failed to allocate new skb\n"); return; } nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); NETLINK_CB(skb_out).dst_group = MULTICAST_GROUP; // Multicast group memcpy(nlmsg_data(nlh), msg, msg_size); // Send broadcast to all listeners in the multicast group res = nlmsg_multicast(nl_sk, skb_out, 0, MULTICAST_GROUP, GFP_KERNEL); if (res < 0) pr_err("Error while broadcasting to users\n"); } 

单播代码示例

#include <linux/module.h> #include <linux/netlink.h> #include <linux/skbuff.h> #include <net/sock.h> #define NETLINK_USER 31 struct sock *nl_sk = NULL; static void send_netlink_msg_to_user(int pid, char *msg, int msg_size) { 
    struct sk_buff *skb_out; struct nlmsghdr *nlh; int res; skb_out = nlmsg_new(msg_size, GFP_KERNEL); if (!skb_out) { 
    pr_err("Failed to allocate new skb\n"); return; } nlh = nlmsg_put(skb_out, 0, 0, NLMSG_DONE, msg_size, 0); NETLINK_CB(skb_out).dst_group = 0; // Not in multicast group memcpy(nlmsg_data(nlh), msg, msg_size); res = nlmsg_unicast(nl_sk, skb_out, pid); if (res < 0) pr_err("Error while sending back to user\n"); } 

总结

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

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/147076.html

(0)
上一篇 2025-04-10 14:10
下一篇 2025-04-10 14:15

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信