netlink(2)- rtnetlink

netlink(2)- rtnetlink:

rtnetlink 介绍:

当创建socket时, 协议类型参数选择的是NETLINK_ROUTE, 得到的socket是rtnetlink_socket, 需要使用到rtnetlink.

​ 所有rtnetlink 消息都包含一个netlink消息头和附加属性,rtnetlink 中定义的一组宏就是用于操作这些属性所用。

​ rtnetlink 除了标准的netlink消息外还包含其它消息类型(如RTM_NEWLINK), 不同的消息对应的附加属性会有差异,后面会具体说明。

rtnetlink 包含的宏:

#include <linux/rtnetlink.h>
 	#define RTA_ALIGNTO 4

	#define RTA_ALIGN(len) (((len)+RTA_ALIGNTO-1)& ~(RTA_ALIGNTO-1))
	/*RTA_ALIGN(len) 得到不小于len 且是RTA_ALIGNTO 对齐(即整数倍)的最小数*/

	#define RTA_OK(rta,len) ((len) >= (int)sizeof(srtuct rtattr)&&\
							(rta)->rta_len >= sizeof(struct rtattr)&&\
							(rta->rta_len) <= (len))
	/* 确认len长度的数据中至少包含一个rta ,且rta 正常。 如果rta指向有效路由属性,attrlen 是属性的运行长度。 !此宏返回指针的有效性!*/

	#define RTA_NETX(rta,attrlen)  ((attrlen) - =RTA_ALIGN((rta)->rta_len),\
									(struct rtattr*)(((char*)(rta))+RTA_ALIGN(rta)->rta_len))
	/*返回下一个RTA的首地址,并且attrlen减去当前rta长度。 !此宏返回rta的下一个属性!*/

	#define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr))+(len))
	/*返回len字节数据+标题 对应的长度*/

	#define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
	/*在需要len字节数据的消息中,需要返回的空间量 (len+sizeof(rtattr))*/

	#define RTA_DATA(rta)	((void*)(((char*)(rta))+RTA_LENGTH(0)))
	/*!该宏返回一个指向该属性开始的指针数据!*/

	#define RTA_PAYLOAD(rta) ((int)((rta)->rta_len)-RTA_LENGTH(0))
	/* !返回此属性数据的长度 ! */

rtnetlink 包含的消息类型及对应数据结构:

rtattr 结构

rtattr 是可选的属性,在initital 头后面,结构如下:

struct rtattr{
    unsigned short rta_len;		/*option 的长度*/
    unsigned short rta_type;	/*option 的类型*/
    /*属性数据跟在这个结构之后*/
};

1. RTM_NEWLINK, RTM_DELINK, RTM_GETLINK 消息:

上述消息是创建,删除,获取有关特定网络接口的信息;

这些消息中包含一个ifinfomsg 结构且后面紧跟一系列rtattr结构。

ifinfomsg 结构

struct ifinfomsg{
    unsigned char 	ifi_family; /*地址族,设置为AF_UNSPEC*/
    unsigned short 	ifi_type;	/* Device type */
    int				ifi_index;	/* Interface index*/
    unsigned int	ifi_flags;	/* Device flags*/
	unsigned int	ifi_change; /* change mask*/
};

参数说明

ifi_family: 为AF_UNSPEC

ifi_type: 为

ifi_flags: 包含device flags, 参考https://www.man7.org/linux/man-pages/man7/netdevice.7.html

如:ifi_flags =IFF_LOWER_UP Driver signals L1 up

ifi_index: 网络接口独一无二的index值,当RTM_NEWLINK 消息发生时填的值。

ifi_change: 保留值,将来使用。

对应的rta_type 说明:

rta_type路由属性的值类型说明
IFLA_UNSPEC--
IFLA_ADDRESS硬件地址接口L2地址(如wlan0 的MAC 地址)
IFLA_BROADCAST硬件地址L2 广播地址
IFLA_IFNAMEasciiz string设备名称(如wlan0)
IFLA_MTUunsigned int设备的MTU
IFLA_LINKint链接类型
IFLA_QDISCasciiz string队列规则
IFLA_STATSstruct rtnl_link_status网络接口的状态

特别说明:

如RTM_NEWLINK 消息到来时: 设备可能是在newlink 状态,也可能在device down 状态,也可能在Device up 状态,也可能在dellink 状态, 收到该信息进行处理时,依赖ifi_flags 的标志,对设备状态进行修改。 如下:

/*----------NEWLINK Message-----------*/
switch(dev_type)
{
	case DEV_NONE:
	case DEV_DELLINK:
		dev_type=DEV_NEWLINK;
		...
		notify(...);
		if(ifi_flags==IFF_LOWER_UP)
		{
		dev_type=DEV_UP;
		....
		notify(...);
		}
		break;
	case DEV_NEWLINK:
	case DEV_DOWN:
		if(ifi_flags==IFF_LOWER_UP)
		{
		dev_type=DEV_UP;
		....
		notify(...);
		}
		break;
	case DEV_up:
		if(ifi_flags==IFI_LOWER_DOWN)
		{
		dev_type=DEV_DOWN;
		...
		notify(...);
		}
		break;
	default:
		break;
		
}
/*-------------Del Message----------*/
switch(dev_type)
{
	case DEV_NEWLINK:
	case DEV_UP:
	case DEV_DOWN:
		dev_type = DEV_DELLINK;
		...
		notify(...);
		break;
	default:
		break;
}

2. RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR

消息作用 :增加,删除,获取某个网络几口关联的IP地址信息。//一个网络接口可以携带多个IP地址,IPV4/IPV6.

结构顺序:包含一个ifaddrmsg 后可选若干rtattr 路由属性。

ifaddrmsg 结构:

struct ifaddrmsg {
                  unsigned char ifa_family;    /* Address type */
                  unsigned char ifa_prefixlen; /* Prefixlength of address */
                  unsigned char ifa_flags;     /* Address flags */
                  unsigned char ifa_scope;     /* Address scope */
                  unsigned int  ifa_index;     /* Interface index */
              };
  • ifa_family: 地址族,为AF_INET 或AF_INET6
  • ifa_prefixlen: address mask 的长度 (地址掩码长度)
  • ifa_scope: 地址范围
  • ifa_index:地址关联的网络接口索引值
  • ifa_flags:IFA_F_SECONDARY 用于辅助地址,IFA_F_PERMANENT 用于用户设置的永久地址。

对应的rta_type 说明:

type 类型数据类型描述
IFA_UNSPEC--
IFA_ADDRESS原始协议地址类型接口地址(接口本地IP地址)
IFA_LOCAL原始协议地址类型本地地址
IFA_LABELstring 类型接口名称 (接口名称如wlan0
IFA_BROADCAST原始协议地址类型广播地址
IFA_ANYCAST原始协议地址类型任意播地址
IFA_CACHEINFOstruct ifa_cacheinfo 类型地址信息

3. RTM_NEWROUTIE, RTM_DELROUTE, RTM_GETROUTE

**消息作用:**创建,删除或者获取某个网络路由的信息。

结构顺序:该message 包含一个rtmsg 后面跟随多个rtattr 结构(rtattr 可选)

rtmsg 结构:

struct rtmsg {
                  unsigned char rtm_family;   /* Address family of route */
                  unsigned char rtm_dst_len;  /* Length of destination */
                  unsigned char rtm_src_len;  /* Length of source */
                  unsigned char rtm_tos;      /* TOS filter */
                  unsigned char rtm_table;    /* Routing table ID;
                                                 see RTA_TABLE below */
                  unsigned char rtm_protocol; /* Routing protocol; see below */
                  unsigned char rtm_scope;    /* See below */
                  unsigned char rtm_type;     /* See below */

                  unsigned int  rtm_flags;
              };
  • rtm_table

    rtm_table路由表类型
    RT_TABLE_UNSPEC未指定的路由表
    RT_TABLE_DEFAULT默认路由表
    RT_TABLE_MAINmain table
    RT_TABLE_LOCAL本地table

    注:用户使用在RT_TABLE_UNSPEC 与RT_TABLE_DEFAULT

  • rtm_protocol:

    路由协议
    RTPROT_UNSPEC-
    RTPROT_REDIRECT通过ICMP 重定向(当前未使用)
    RTPROT_KERNELby kernel
    RTPROT_BOOTduring boot
    RTPROT_STATIC管理员

    大于PTRPOT_STATIC 的值不被内核解释,仅仅用于用户信息。 可标记路由信息的来源或区分多个路由守护进程。

  • rtm_socpe:

    // 获取到目的地的距离

    RT_SCOPE_UNIVERSEglobal route
    RT_SCOPE_SITEinterior route in the local autonomous system
    RT_SCOPE_LINKroute on this link
    RT_SCOPE_HOSTroute on the local host
    RT_SCOPE_NOWHEREdestination doesn’t exist

    注:RT_SCOP_UNIVERSE -RT_SCOPE_SITE 给用户使用。

  • rtm_type:

    rtm_type路由类型
    RTN_UNSPEC-
    RTN_UNICAST网关或直接路由
    RTN_LOCAL本地接口路由
    RTN_BROADCAST本地广播路由(作为广播发送)
    RTN_ANYCAST本地广播路由(作为单播发送)
    RTN_MULTICAST多播路由
    RTN_BLACKHOLE丢包路由
    RTN_UNREACHABLE不可达目的地
    RTN_PROHIBIT包拒绝路由
    RTN_THROW继续在另一个表中进行路由查询
    RTN_NAT网络地址转换规则
    RTN_XRESOLVE外部解析器
  • rtm_flags:

RTM_F_NOTIFY路由改变时通知用户
RTM_F_CLONED路由被其它路由克隆
RTM_F_EQUALIZE暂未使用

对应的rta_type 说明

rta_type值类型描述
RTA_UNSPEC--
RTA_DST协议地址路由目标地址
RTA_SRC协议地址路由源地址
RTA_IIFint输入的接口index
RTA_OIFint输出的接口index
RTA_GATEWAY协议地址路由的网关
RTA_PRIORITYint路由的优先级
RTA_PREFSRC协议地址首选的源地址
RTA_METRICSint路由度量
RTA_MULTIPATH
RTA_PROTOINFO--
RTA_FLOWint路由领域
RTA_CACHEINFO
RTA_TABLE路由表ID

4. RTM_NEWNEIGH, RTM_DELNEIGH, RTM_GETNEIGH

消息作用: 增加,删除,或获取邻里表项信息,如ARP entry.

数据结构: 信息包括一个mdmsg 结构

ndmsg 结构:

   struct ndmsg {
                  unsigned char ndm_family;
                  int           ndm_ifindex;  /* Interface index */
                  __u16         ndm_state;    /* State */
                  __u8          ndm_flags;    /* Flags */
                  __u8          ndm_type;
              };
  • ndm_state:

    ndm_state解释
    NUD_INCOMPLETE当前解决缓存条目
    NUD_REACHABLE确认的工作缓存条目
    NUD_STALE过期的缓存条目
    NUD_DELAY等待计时器的条目
    NUD_PROBE缓存条目当前重探测
    NUD_FAILED无效缓存条目
    NUD_NOARP设备没有目标缓存
    NUD_PERMANENT静态项
  • ndm_flags:

    ndm_flags说明
    NTF_PROXY代理ARP 表项
    NTF_ROUTERIPv6 路由器

rta_type:

rta_type说明
NDA_UNSPEC-
NDA_DST邻居缓存N/W 层目的地址 (对端IP地址)
NDA_LLADDR邻居缓存链路层地址(对端MAC地址)
NDA_CACHEINFO缓存统计

如果rta_type 是NDA_CACHEINFO , 则紧跟一个nda_cacheinfo 头。

nda_cacheinfo

 struct nda_cacheinfo {
                  __u32         ndm_confirmed;
                  __u32         ndm_used;
                  __u32         ndm_updated;
                  __u32         ndm_refcnt;
              };
  • 参考网址:
    https://www.man7.org/linux/man-pages/man7/netdevice.7.html
    https://www.man7.org/linux/man-pages/man7/rtnetlink.7.html
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
下面是一个简单的示例代码,用于检测所有网口的 UP 和 DOWN 状态。该代码使用了 Netlink Socket API,需要在 Linux 系统中编译和运行。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #define BUFSIZE 8192 int main() { int fd; struct sockaddr_nl sa; char buf[BUFSIZE]; struct nlmsghdr *nh; struct ifinfomsg *ifinfo; int len; // 创建 Netlink Socket if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) { perror("socket"); exit(1); } memset(&sa, 0, sizeof(sa)); sa.nl_family = AF_NETLINK; sa.nl_groups = RTMGRP_LINK; // 监听网卡变化事件 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("bind"); exit(1); } // 接收 Netlink 消息 while ((len = recv(fd, buf, BUFSIZE, 0)) > 0) { for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { if (nh->nlmsg_type == NLMSG_DONE) { break; } else if (nh->nlmsg_type == NLMSG_ERROR) { perror("recv"); exit(1); } else if (nh->nlmsg_type != RTM_NEWLINK) { continue; } ifinfo = (struct ifinfomsg *)NLMSG_DATA(nh); // 监听到网卡 UP 或 DOWN 事件 if (ifinfo->ifi_change & (IFACE_UP | IFACE_DOWN)) { printf("Interface %d is %s\n", ifinfo->ifi_index, (ifinfo->ifi_flags & IFF_UP) ? "UP" : "DOWN"); } } } close(fd); return 0; } ``` 该程序使用了 Netlink Socket API 监听 RTMGRP_LINK 组,对于每个 RTM_NEWLINK 消息,解析其中的 ifinfomsg 结构体,检查其 ifi_change 和 ifi_flags 成员以确定网卡 UP 或 DOWN 事件。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值