如何通过netlink接收RTM_NEWTFILTER、RTM_DELTFILTER消息
问题解决方法
1. 无法接收TFILTER通知的根因
你当前代码的sa.nl_groups字段仅订阅了链路状态、IPv4地址、IPv4路由三类netlink事件组,TC(流量控制)相关的qdisc、分类器、过滤器事件都属于RTMGRP_TC事件组,未订阅该组自然无法接收RTM_NEWTFILTER/RTM_DELTFILTER通知。
2. 代码修改步骤
2.1 新增TC事件组订阅
修改main函数中sa.nl_groups的赋值逻辑,加入TC事件组:
// 原代码 // sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE; // 修改后 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_TC;
如果编译时提示RTMGRP_TC未定义,可以替换为原始宏计算值:
sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | (1 << (RTNLGRP_TC - 1));
2.2 修正消息解析逻辑
你当前代码默认把所有netlink消息的payload都当做struct ifinfomsg解析,TC类消息的payload结构是struct tcmsg,直接打印会出现字段错位问题,需要按消息类型做分支解析:
// read_msg函数中判断消息类型分支 if (nh->nlmsg_type >= RTM_NEWQDISC && nh->nlmsg_type <= RTM_DELACTION) { // TC类消息用tcmsg解析 struct tcmsg *tcmsg = NLMSG_DATA(nh); printf("\ttcm_ifindex = %d, tcm_handle = 0x%x, tcm_parent = 0x%x\n", tcmsg->tcm_ifindex, tcmsg->tcm_handle, tcmsg->tcm_parent); print_type(nh->nlmsg_type); } else if (nh->nlmsg_type >= RTM_NEWLINK && nh->nlmsg_type <= RTM_GETLINK) { // 链路类消息用ifinfomsg解析 struct ifinfomsg *ifimsg = NLMSG_DATA(nh); printf("\tifi_family = %u, ifi_type = %u, ifi_index = %u, ifi_flags = 0x%X, ifi_change = 0x%X\n", ifimsg->ifi_family, ifimsg->ifi_type, ifimsg->ifi_index, ifimsg->ifi_flags, ifimsg->ifi_change); print_type(nh->nlmsg_type); print_flags(ifimsg->ifi_flags, ifimsg->ifi_change); }
3. 其他接收TC过滤器变更的方式
- 可以使用
libnl、libmnl这类封装好的netlink开发库,无需手动处理消息对齐、属性解析等底层逻辑,开发效率更高 - 也可以通过inotify监控tc配置相关的sysfs节点,不过该方式仅能感知变更事件,无法获取变更的具体内容,可靠性低于netlink通知
内容的提问来源于stack exchange,提问作者stanislav888
相关产品推荐
相关产品推荐

