一、Rtnetlink
Rtnetlink 允许对内核路由表进行读和更改,它用于内核与各个子系统之间(路由子系统、IP地址、链接参数等)的通信,
用户空间可以通过NET_LINK_ROUTER socket 与内核进行通信,该过程基于标准的netlink消息进行。
一些rtnetlink消息在初始头后有一些可选属性,下面是该属性的结构:
1 struct rtattr {
2 unsigned short rta_len; /*Length of option*/
3 unsigned short rta_type; /*Type of option*/
4 /*Data follows*/
5 };
操作这些属性只可以用RTA_*这些宏来造作
1 /*Macros to handle rtattributes*/
2
3 /*对齐*/
4 #define RTA_ALIGNTO 4
5 #define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) )
6
7 /*判断是否为合法的路由属性*/
8 #define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && 9 (rta)->rta_len >= sizeof(struct rtattr) && 10 (rta)->rta_len <= (len))
11
12 /*获取下一个rtattr的首地址*/
13 #define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), 14 (struct rtattr*)(((char*)(rta)) + RTA_ALIGN((rta)->rta_len)))
15
16 /*返回加上 rtattr header的总长度*/
17 #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len))
18
19 /*返回数据对齐的最小值*/
20 #define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len))
21
22 /*返回属性数据部分首地址*/
23 #define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0)))
24
25 /*返回属性数据部分的长度*/
26 #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0))
27
28 /*****************************************************************29 ******************************************************************/
30 rtnetlink_socket = socket(AF_NETLINK, int socket_type, NETLINK_ROUTE);
31
32 int RTA_OK(struct rtattr *rta, int rtabuflen);
33
34 void *RTA_DATA(struct rtattr *rta);
35
36 unsigned int RTA_PAYLOAD(struct rtattr *rta);
37
38 struct rtattr *RTA_NEXT(struct rtattr *rta, unsigned int rtabuflen);
39
40 unsigned int RTA_LENGTH(unsigned int length);
41
42 unsigned int RTA_SPACE(unsigned int length);
Rtnetlink 由下面这些消息类型构成(新加在标准的netlink消息上)
(1)#RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK
创建或者删除一个特定的网络接口,或者从一个特定的网络接口上获得信息。
这些消息含有一个ifinfomsg类型的结构,紧跟在后面的是一系列的rtattr结构。
1 /*****************************************************************2 * Link layer specific messages.3 ****/
4
5 /*struct ifinfomsg6 * passes link level specific information, not dependent7 * on network protocol.8 */
9
10 struct ifinfomsg {
11 unsigned char ifi_family; /*AF_UNSPEC*/
12 unsigned short ifi_type; /*Device type*/
13 int ifi_index; /*Interface index*/
14 unsigned int ifi_flags; /*Device flags*/
15 unsigned int ifi_change; /*change mask*/
16 };
17 /*
18 * ifi_family: 接口地址类型19 * ifi_type: 设备类型20 * ifi_index: 是结构唯一的索引21 * ifi_flags: 设备标志,可以看netdevice 结构22 * ifi_change: 保留值,通常设置为0xFFFFFFFF23 */
24
25 /*
26 ifi_type代表硬件设备的类型:27 ARPHRD_ETHER 10M以太网28 ARPHRD_PPP PPP拨号29 ARPHRDLOOPBACK 环路设备30
31 ifi_flags包含设备的一些标志:32 IFF_UP 接口正在运行33 IFF_BROADCAST 有效的广播地址集34 IFF_DEBUG 内部调试标志35 IFF_LOOPBACK 这是自环接口36 IFF_POINTOPOINT 这是点到点的链路设备37 IFF_RUNNING 资源已分配38 IFF_NOARP 无arp协议,没有设置第二层目的地址39 IFF_PROMISC 接口为杂凑(promiscuous)模式40 IFF_NOTRAILERS 避免使用trailer41 IFF_ALLMULTI 接收所有组播(multicast)报文42 IFF_MASTER 主负载平衡群(bundle)43 IFF_SLAVE 从负载平衡群(bundle)44 IFF_MULTICAST 支持组播(multicast)45 IFF_PORTSEL 可以通过ifmap选择介质(media)类型46 IFF_AUTOMEDIA 自动选择介质47 IFF_DYNAMIC 接口关闭时丢弃地址48
49 Routing attributes(rtattr部分属性,rta_type)50
51 rta_type value type description52 ──────────────────────────────────────────────────────────53 IFLA_UNSPEC - 未说明,未指定的数据54 IFLA_ADDRESS hardware address L2硬件地址55 IFLA_BROADCAST hardware address L2广播地址.56 IFLA_IFNAME asciiz string char型设备名.57 IFLA_MTU unsigned int MTU of the device.58 IFLA_LINK int Link type.59 IFLA_QDISC asciiz string Queueing discipline.60 IFLA_STATS see below struct rtnl_link_stats的设备信息61
62 //用来获取ifinfomsg后面的rtattr结构63 #define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))64 */
(2)# RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR
添加,删除或者接收一个和接口相关的IP地址的信息。
在linux2.2中,一个网口是可以有多个IP地址信息的。这些消息含有一个ifaddrmsg类型的结构,紧跟在后面的是一系列的rtattr结构。
1 struct ifaddrmsg {
2 unsigned char ifa_family; /*Address type*/
3 unsigned char ifa_prefixlen; /*Prefixlength of address*/
4 unsigned char ifa_flags; /*Address flags*/
5 unsigned char ifa_scope; /*Address scope*/
6 int ifa_index; /*Interface index*/
7 };
8 /*
9 * ifa_family: 地址类型(通常为AF_INET or AF_INET6))10 * ifa_prefixlen: 地址的地址掩码长度,如果改地址定义在这个family11 * ifa_flags:12 * ifa_scope: 地址的作用域13 * ifa_index: 接口索引与接口地址关联14 */
15
16 /*
17 Attributes (rtattr部分属性,rta_type)18 rta_type value type description19 ─────────────────────────────────────────────────────────────20 IFA_UNSPEC - unspecified.21 IFA_ADDRESS raw protocol address 接口地址 interface address22 IFA_LOCAL raw protocol address 本地地址 local address23 IFA_LABEL asciiz string 接口名称 name of the interface24 IFA_BROADCAST raw protocol address 广播 broadcast address.25 IFA_ANYCAST raw protocol address anycast address26 IFA_CACHEINFO struct ifa_cacheinfo Address information.27
28 */
(3)#RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE
创建,删除或者获取网络设备的路由信息;这些消息包含一个rtmsg结构,其后跟数目可选的rtattr结构。
对于RTM_GETROUTE,设置rtm_dst_len以及rtm_src_len为0表示获取指定路由表的所有条目(entries)。
其它的成员,除了rtm_table、rtm_protocol,0是通配符
1 struct rtmsg {
2 unsigned char rtm_family;
3 unsigned char rtm_dst_len;
4 unsigned char rtm_src_len;
5 unsigned char rtm_tos;
6
7 unsigned char rtm_table; /*Routing table id*/
8 unsigned char rtm_protocol; /*Routing protocol; see below*/
9 unsigned char rtm_scope; /*See below*/
10 unsigned char rtm_type; /*See below*/
11
12 unsigned rtm_flags;
13 };
14
15 rtm_type Route type
16 ───────────────────────────────────────────────────────────
17 RTN_UNSPEC unknown route /*位置路由*/
18 RTN_UNICAST a gateway or direct route /*网关或直连路由*/
19 RTN_LOCAL a local interface route /*本地接口路由*/
20 RTN_BROADCAST a local broadcast route (sent as a broadcast) /*本地广播式接收,发送*/
21 RTN_ANYCAST a local broadcast route (sent as a unicast) /*本地单播路由*/
22 RTN_MULTICAST a multicast route /*多播路由*/
23 RTN_BLACKHOLE a packet dropping route /*丢弃*/
24 RTN_UNREACHABLE an unreachable destination /*目标不可达*/
25 RTN_PROHIBIT a packet rejection route /*拒绝*/
26 RTN_THROW continue routing lookup in another table /*不在本表*/
27 RTN_NAT a network address translation rule /*nat*/
28 RTN_XRESOLVE refer to an external resolver (not implemented)
29
30 rtm_protocol Route origin.
31 ───────────────────────────────────────
32 RTPROT_UNSPEC unknown
33 RTPROT_REDIRECT by an ICMP redirect (currently unused) /*通过icmp转发建立路由 (目前没用)*/
34 RTPROT_KERNEL by the kernel /*通过内核建立路由*/
35 RTPROT_BOOT during boot /*启动时建立路由*/
36 RTPROT_STATIC by the administrator /*管理员建立*/
37
38 rtm_scope is the distance to the destination:
39
40 RT_SCOPE_UNIVERSE global route
41 RT_SCOPE_SITE interior route in the local autonomous system
42 RT_SCOPE_LINK route on this link
43 RT_SCOPE_HOST route on the local host
44 RT_SCOPE_NOWHERE destination doesn't exist
45
46 /*用户可用范围*/
47 RT_SCOPE_UNIVERSE ~ RT_SCOPE_SITE are available to the user.
48
49 The rtm_flags have the following meanings:
50
51 RTM_F_NOTIFY if the route changes, notify the user via rtnetlink
52 RTM_F_CLONED route is cloned from another route
53 RTM_F_EQUALIZE a multipath equalizer (not yet implemented)
54
55 rtm_table specifies the routing table
56
57 RT_TABLE_UNSPEC an unspecified routing table /*0 未指定的表*/
58 RT_TABLE_DEFAULT the default table /*253 默认表*/
59 RT_TABLE_MAIN the main table /*254 main 表*/
60 RT_TABLE_LOCAL the local table /*255 local 表*/
61
62 //用户可以使用 RT_TABLE_UNSPEC 到 RT_TABLE_DEFAULT 之间的任意值
63
64 Attributes
65
66 rta_type value type description
67 ──────────────────────────────────────────────────────────────
68 RTA_UNSPEC - ignored.
69 RTA_DST protocol address Route destination address. /*目的*/
70 RTA_SRC protocol address Route source address. /*源地址*/
71 RTA_IIF int Input interface index. /*输入设备 index*/
72 RTA_OIF int Output interface index.
73 RTA_GATEWAY protocol address The gateway of the route /*网关*/
74 RTA_PRIORITY int Priority of route. /*优先级*/
75 RTA_PREFSRC
76 RTA_METRICS int Route metric /*路由metric 值*/
77 RTA_MULTIPATH
78 RTA_PROTOINFO
79 RTA_FLOW
80 RTA_CACHEINFO
一面是一个具体实例:
1 /*********************************************************2 * Filename: nl_netinfo.c3 * Author: zhangwj4 * Date:5 * Descripte:6 * Email:7 * Warnning:8 **********************************************************/
9 #include
10 #include
11 #include
12 #include /*See NOTES*/
13 #include
14 #include
15 #include
16 #include
17 #include
18 #include
19 #include
20
21 #define EPOLL_LISTEN_MAX_CNT 256
22 #define EPOLL_LISTEN_TIMEOUT 500
23
24 int g_nlfd = -1;
25 int g_epollfd = -1;
26
27 void parse_rtattr(struct rtattr **tb, int max, struct rtattr *attr, int len)
28 {
29 for (; RTA_OK(attr, len); attr = RTA_NEXT(attr, len)) {
30 if (attr->rta_type <= max) {
31 tb[attr->rta_type] = attr;
32 }
33 }
34 }
35
36 void nl_netroute_handle(struct nlmsghdr *nlh)
37 {
38 int len;
39 struct rtattr *tb[RTA_MAX + 1];
40 struct rtmsg *rt;
41 char tmp[256];
42
43 bzero(tb, sizeof(tb));
44 rt = NLMSG_DATA(nlh);
45 len = nlh->nlmsg_len - NLMSG_SPACE(sizeof(*rt));
46 parse_rtattr(tb, RTA_MAX, RTM_RTA(rt), len);
47 printf("%s:", (nlh->nlmsg_type==RTM_NEWROUTE)?"NEWROUT":"DELROUT");
48 if (tb[RTA_DST] != NULL) {
49 inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_DST]), tmp, sizeof(tmp));
50 printf("DST: %s", tmp);
51 }
52 if (tb[RTA_SRC] != NULL) {
53 inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_SRC]), tmp, sizeof(tmp));
54 printf("SRC: %s", tmp);
55 }
56 if (tb[RTA_GATEWAY] != NULL) {
57 inet_ntop(rt->rtm_family, RTA_DATA(tb[RTA_GATEWAY]), tmp, sizeof(tmp));
58 printf("GATEWAY: %s", tmp);
59 }
60 printf("\n");
61 }
62
63 void nl_netifinfo_handle(struct nlmsghdr *nlh)
64 {
65 int len;
66 struct rtattr *tb[IFLA_MAX + 1];
67 struct ifinfomsg *ifinfo;
68
69 bzero(tb, sizeof(tb));
70 ifinfo = NLMSG_DATA(nlh);
71 len = nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifinfo));
72 parse_rtattr(tb, IFLA_MAX, IFLA_RTA (ifinfo), len);
73
74 printf("%s: %s", (nlh->nlmsg_type==RTM_NEWLINK) ? "NEWLINK" : "DELLINK", (ifinfo->ifi_flags & IFF_UP) ? "up" : "down");
75 if(tb[IFLA_IFNAME]) {
76 printf("%s", RTA_DATA(tb[IFLA_IFNAME]));
77 }
78 printf("\n");
79 }
80
81 void nl_netifaddr_handle(struct nlmsghdr *nlh)
82 {
83 int len;
84 struct rtattr *tb[IFA_MAX + 1];
85 struct ifaddrmsg *ifaddr;
86 char tmp[256];
87
88 bzero(tb, sizeof(tb));
89 ifaddr = NLMSG_DATA(nlh);
90 len =nlh->nlmsg_len - NLMSG_SPACE(sizeof(*ifaddr));
91 parse_rtattr(tb, IFA_MAX, IFA_RTA (ifaddr), len);
92
93 printf("%s", (nlh->nlmsg_type == RTM_NEWADDR)? "NEWADDR":"DELADDR");
94 if (tb[IFA_LABEL] != NULL) {
95 printf("%s", RTA_DATA(tb[IFA_LABEL]));
96 }
97 if (tb[IFA_ADDRESS] != NULL) {
98 inet_ntop(ifaddr->ifa_family, RTA_DATA(tb[IFA_ADDRESS]), tmp, sizeof(tmp));
99 printf("%s", tmp);
100 }
101 printf("\n");
102 }
103
104 void nl_netlink_handle(int fd)
105 {
106 int r_size;
107 socklen_t len = 0;
108 char buff[2048] = {0};
109 struct sockaddr_nl addr;
110 struct nlmsghdr *nlh;
111
112 while(1)
113 {
114 len = sizeof(addr);
115 r_size = recvfrom(fd, (void *)buff, sizeof(buff), 0, (struct sockaddr *)&addr, &len);
116 nlh = (struct nlmsghdr *)buff;
117 for(; NLMSG_OK(nlh, r_size); nlh = NLMSG_NEXT(nlh, r_size))
118 {
119 switch(nlh->nlmsg_type) {
120 case NLMSG_DONE:
121 case NLMSG_ERROR:
122 break;
123 case RTM_NEWLINK: /* */
124 case RTM_DELLINK:
125 nl_netifinfo_handle(nlh);
126 break;
127 case RTM_NEWADDR:
128 case RTM_DELADDR: /* */
129 nl_netifaddr_handle(nlh);
130 break;
131 case RTM_NEWROUTE:
132 case RTM_DELROUTE: /* */
133 nl_netroute_handle(nlh);
134 break;
135 default:
136 break;
137 }
138 }
139 }
140 }
141
142 void epoll_event_handle(void)
143 {
144 int i = 0;
145 int fd_cnt = 0;
146 int sfd;
147 struct epoll_event events[EPOLL_LISTEN_MAX_CNT];
148
149 memset(events, 0, sizeof(events));
150 while(1)
151 {
152 /*wait epoll event*/
153 fd_cnt = epoll_wait(g_epollfd, events, EPOLL_LISTEN_MAX_CNT, EPOLL_LISTEN_TIMEOUT);
154 for(i = 0; i < fd_cnt; i++)
155 {
156 sfd = events[i].data.fd;
157 if(events[i].events & EPOLLIN)
158 {
159 if (sfd == g_nlfd)
160 {
161 nl_netlink_handle(sfd);
162 }
163 }
164 }
165 }
166 }
167
168 int epoll_add_fd(int fd)
169 {
170 struct epoll_event ev;
171
172 ev.data.fd = fd;
173 ev.events = EPOLLIN | EPOLLET;
174
175 if (epoll_ctl(g_epollfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
176 perror("epoll add fd error");
177 return -1;
178 }
179
180 printf("epoll add fd[%d] success\n", fd);
181 return 0;
182 }
183
184 int init_epoll_fd()
185 {
186 int epollfd = -1;
187
188 epollfd = epoll_create(EPOLL_LISTEN_MAX_CNT);
189 if (epollfd < 0) {
190 perror("epoll create failure!...");
191 return -1;
192 }
193 g_epollfd = epollfd;
194
195 printf("epool create fd [%d] success\n", epollfd);
196 return g_epollfd;
197 }
198
199 int init_nl_sockfd()
200 {
201 int ret = 0;
202 int nlfd = -1;
203 struct sockaddr_nl sa;
204
205 /*open a netlink fd*/
206 nlfd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
207 if (nlfd < 0) {
208 perror("create netlink socket failure");
209 return -1;
210 }
211
212 memset(&sa, 0, sizeof(sa));
213 sa.nl_family = AF_NETLINK;
214 sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE;
215
216 /*bind netlink*/
217 ret = bind(nlfd, (struct sockaddr *)&sa, sizeof(sa));
218 if (ret < 0) {
219 perror("bind nlfd error");
220 close(nlfd);
221 return -1;
222 }
223
224 if (epoll_add_fd(nlfd)) {
225 close(nlfd);
226 return -1;
227 }
228 g_nlfd = nlfd;
229
230 printf("netlink create fd [%d] success\n", nlfd);
231 return nlfd;
232 }
233
234
235 int main(int argc, char **argv)
236 {
237 if (init_epoll_fd() < 0) { /*创建epoll 监听fd*/
238 return -1;
239 }
240
241 if (init_nl_sockfd() < 0) { /*创建netlink*/
242 return -1;
243 }
244
245 /*循环接收处理*/
246 epoll_event_handle();
247
248 return 0;
249 }
参考资料: