Linux基础 -- 用户态Generic Netlink库高性能接收与回调框架

用户态Generic Netlink库高性能接收与回调框架

一、概述

在 Linux 系统中,Netlink 是用户态与内核态通信的强大机制。libnl 是一个专为简化 Netlink 编程而设计的库,提供了接收和处理 Netlink 消息的高级接口。libnl-genl 是其通用 Netlink (Generic Netlink) 扩展库,专门用于处理自定义协议。本文将详细介绍如何通过 nl_socket_modify_cbnl_cb_set 两种方法实现高效的 Netlink 消息接收和处理框架。

Netlink 使用回调机制来处理接收到的消息。常用的回调设置方法有两种:

1. nl_socket_modify_cb

  • 仅在指定的 Netlink 套接字上设置回调。
  • 适合在每个套接字上使用不同回调。

2. nl_cb_set

  • 在回调上下文 (struct nl_cb *) 上设置回调。
  • 可以在多个套接字之间共享。

1. epoll + 非阻塞 + 批量接收

  • 使用 epoll 进行非阻塞监听。
  • 通过大缓冲区批量接收消息。
  • 结合 libnllibnl-genl 实现高效的 Netlink 消息接收。
c 复制代码
#include <netlink/netlink.h>
#include <netlink/msg.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <sys/epoll.h>
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>

#define MY_GENL_FAMILY "my_custom_family"

// 自定义消息处理回调
int my_genl_handler(struct nl_msg *msg, void *arg) {
	struct nlmsghdr *nlh = nlmsg_hdr(msg);
	struct genlmsghdr *gnlh = nlmsg_data(nlh);
    
	printf("[Genl Handler] Received a Netlink message.\n");
	printf("Command: %d, Version: %d\n", gnlh->cmd, gnlh->version);
	
	struct nlattr *attrs[GENL_MAX_ATTRS + 1] = {};
	nla_parse(attrs, GENL_MAX_ATTRS, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
	
	if (attrs[GENL_ATTR_MSG]) {
		printf("Message: %s\n", nla_get_string(attrs[GENL_ATTR_MSG]));
	}
	
    return NL_OK;
}

// 设置非阻塞模式
void set_nonblocking(int fd) {
    int flags = fcntl(fd, F_GETFL, 0);
    fcntl(fd, F_SETFL, flags | O_NONBLOCK);
}

int main() {
    struct nl_sock *sock = nl_socket_alloc();
    nl_connect(sock, NETLINK_GENERIC);

    // 查找 Generic Netlink family
    int family_id = genl_ctrl_resolve(sock, MY_GENL_FAMILY);
    if (family_id < 0) {
        printf("[Error] Could not resolve Generic Netlink family\n");
        return -1;
    }

    struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
    nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, my_genl_handler, NULL);
    nl_socket_set_cb(sock, cb);

    int fd = nl_socket_get_fd(sock);
    set_nonblocking(fd);

    int epfd = epoll_create1(0);
    struct epoll_event ev, events[10];
    ev.events = EPOLLIN;
    ev.data.fd = fd;
    epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev);

    while (1) {
        int nfds = epoll_wait(epfd, events, 10, -1);
        for (int i = 0; i < nfds; i++) {
            if (events[i].data.fd == fd) {
                nl_recvmsgs(sock, cb); // 使用 libnl + epoll 处理消息
            }
        }
    }

    nl_cb_put(cb);
    nl_close(sock);
    nl_socket_free(sock);
    close(epfd);
    return 0;
}

3. 多线程处理(可选)

  • 通过线程池并行处理接收到的 Netlink 消息。
  • 每个线程从 epoll 事件队列中读取并解析 Netlink 消息。

四、最佳实践

  • 通过 nl_socket_modify_cb 灵活调整特定套接字的回调。
  • 通过 nl_cb_set 设置全局回调,并在多套接字间复用。
  • 对于高频 Netlink 通信,采用非阻塞模式 + epoll + 批量处理。
  • 使用 libnl-genl 处理 Generic Netlink,简化自定义协议实现。

五、总结

本框架提供了一种高效的 Netlink 消息接收和处理方式,适用于高并发和高性能场景,并支持自定义协议的灵活扩展。

相关推荐
FoldWinCard23 分钟前
D5 Linux 网络及端口命令
linux·运维·服务器
零涂毕业设计2 小时前
毕业设计模块开发-OLED显示屏(IIC协议0.96寸)STM32 ESP32 FPGA Linux驱动免费分享
linux·stm32·单片机·嵌入式·esp32·fpga·oled
tedcloud1232 小时前
OmniRoute怎么部署?开源AI模型路由平台Linux部署教程
linux·服务器·人工智能·开源·音视频
霸道流氓气质2 小时前
KMS 密钥管理服务(Key Management Service)原理与实践
linux·服务器·数据库
SakitamaX2 小时前
LVS(Linux Virtual Server)概念详解
linux·运维·lvs
小张同学a.2 小时前
Linux系统管理
linux·运维
阿龙的工作记录3 小时前
深入理解Linux设备驱动模型
linux·嵌入式硬件·工作记录
代码村新手3 小时前
Linux的基本指令
linux·运维·服务器
撩得Android一次心动5 小时前
Linux编程笔记3【个人用】
linux·笔记
OpenPomeloxCommunity5 小时前
3. Linux 同步机制之 spinlock 设计与实现(一):通用层
linux