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_IFNAME | asciiz string | 设备名称(如wlan0) |
IFLA_MTU | unsigned int | 设备的MTU |
IFLA_LINK | int | 链接类型 |
IFLA_QDISC | asciiz string | 队列规则 |
IFLA_STATS | struct 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_LABEL | string 类型 | 接口名称 (接口名称如wlan0) |
IFA_BROADCAST | 原始协议地址类型 | 广播地址 |
IFA_ANYCAST | 原始协议地址类型 | 任意播地址 |
IFA_CACHEINFO | struct 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_MAIN main table RT_TABLE_LOCAL 本地table 注:用户使用在RT_TABLE_UNSPEC 与RT_TABLE_DEFAULT
-
rtm_protocol:
路由协议 RTPROT_UNSPEC - RTPROT_REDIRECT 通过ICMP 重定向(当前未使用) RTPROT_KERNEL by kernel RTPROT_BOOT during boot RTPROT_STATIC 管理员 大于PTRPOT_STATIC 的值不被内核解释,仅仅用于用户信息。 可标记路由信息的来源或区分多个路由守护进程。
-
rtm_socpe:
// 获取到目的地的距离
RT_SCOPE_UNIVERSE global route RT_SCOPE_SITE interior route in the local autonomous system RT_SCOPE_LINK route on this link RT_SCOPE_HOST route on the local host RT_SCOPE_NOWHERE destination 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_IIF | int | 输入的接口index |
RTA_OIF | int | 输出的接口index |
RTA_GATEWAY | 协议地址 | 路由的网关 |
RTA_PRIORITY | int | 路由的优先级 |
RTA_PREFSRC | 协议地址 | 首选的源地址 |
RTA_METRICS | int | 路由度量 |
RTA_MULTIPATH | ||
RTA_PROTOINFO | - | - |
RTA_FLOW | int | 路由领域 |
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_ROUTER IPv6 路由器
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