xref: /aosp_15_r20/external/ethtool/libmnl/examples/rtnl/rtnl-route-dump.c (revision 1b481fc3bb1b45d4cf28d1ec12969dc1055f555d)
1 /* This example is placed in the public domain. */
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <time.h>
7 #include <arpa/inet.h>
8 
9 #include <libmnl/libmnl.h>
10 #include <linux/if.h>
11 #include <linux/if_link.h>
12 #include <linux/rtnetlink.h>
13 
data_attr_cb2(const struct nlattr * attr,void * data)14 static int data_attr_cb2(const struct nlattr *attr, void *data)
15 {
16 	const struct nlattr **tb = data;
17 
18 	/* skip unsupported attribute in user-space */
19 	if (mnl_attr_type_valid(attr, RTAX_MAX) < 0)
20 		return MNL_CB_OK;
21 
22 	if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
23 		perror("mnl_attr_validate");
24 		return MNL_CB_ERROR;
25 	}
26 
27 	tb[mnl_attr_get_type(attr)] = attr;
28 	return MNL_CB_OK;
29 }
30 
attributes_show_ipv4(struct nlattr * tb[])31 static void attributes_show_ipv4(struct nlattr *tb[])
32 {
33 	if (tb[RTA_TABLE]) {
34 		printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE]));
35 	}
36 	if (tb[RTA_DST]) {
37 		struct in_addr *addr = mnl_attr_get_payload(tb[RTA_DST]);
38 		printf("dst=%s ", inet_ntoa(*addr));
39 	}
40 	if (tb[RTA_SRC]) {
41 		struct in_addr *addr = mnl_attr_get_payload(tb[RTA_SRC]);
42 		printf("src=%s ", inet_ntoa(*addr));
43 	}
44 	if (tb[RTA_OIF]) {
45 		printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF]));
46 	}
47 	if (tb[RTA_FLOW]) {
48 		printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW]));
49 	}
50 	if (tb[RTA_PREFSRC]) {
51 		struct in_addr *addr = mnl_attr_get_payload(tb[RTA_PREFSRC]);
52 		printf("prefsrc=%s ", inet_ntoa(*addr));
53 	}
54 	if (tb[RTA_GATEWAY]) {
55 		struct in_addr *addr = mnl_attr_get_payload(tb[RTA_GATEWAY]);
56 		printf("gw=%s ", inet_ntoa(*addr));
57 	}
58 	if (tb[RTA_PRIORITY]) {
59 		printf("prio=%u ", mnl_attr_get_u32(tb[RTA_PRIORITY]));
60 	}
61 	if (tb[RTA_METRICS]) {
62 		int i;
63 		struct nlattr *tbx[RTAX_MAX+1] = {};
64 
65 		mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx);
66 
67 		for (i=0; i<RTAX_MAX; i++) {
68 			if (tbx[i]) {
69 				printf("metrics[%d]=%u ",
70 					i, mnl_attr_get_u32(tbx[i]));
71 			}
72 		}
73 	}
74 }
75 
76 /* like inet_ntoa(), not reentrant */
inet6_ntoa(struct in6_addr in6)77 static const char *inet6_ntoa(struct in6_addr in6)
78 {
79 	static char buf[INET6_ADDRSTRLEN];
80 
81 	return inet_ntop(AF_INET6, &in6.s6_addr, buf, sizeof(buf));
82 }
83 
attributes_show_ipv6(struct nlattr * tb[])84 static void attributes_show_ipv6(struct nlattr *tb[])
85 {
86 	if (tb[RTA_TABLE]) {
87 		printf("table=%u ", mnl_attr_get_u32(tb[RTA_TABLE]));
88 	}
89 	if (tb[RTA_DST]) {
90 		struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_DST]);
91 		printf("dst=%s ", inet6_ntoa(*addr));
92 	}
93 	if (tb[RTA_SRC]) {
94 		struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_SRC]);
95 		printf("src=%s ", inet6_ntoa(*addr));
96 	}
97 	if (tb[RTA_OIF]) {
98 		printf("oif=%u ", mnl_attr_get_u32(tb[RTA_OIF]));
99 	}
100 	if (tb[RTA_FLOW]) {
101 		printf("flow=%u ", mnl_attr_get_u32(tb[RTA_FLOW]));
102 	}
103 	if (tb[RTA_PREFSRC]) {
104 		struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_PREFSRC]);
105 		printf("prefsrc=%s ", inet6_ntoa(*addr));
106 	}
107 	if (tb[RTA_GATEWAY]) {
108 		struct in6_addr *addr = mnl_attr_get_payload(tb[RTA_GATEWAY]);
109 		printf("gw=%s ", inet6_ntoa(*addr));
110 	}
111 	if (tb[RTA_PRIORITY]) {
112 		printf("prio=%u ", mnl_attr_get_u32(tb[RTA_PRIORITY]));
113 	}
114 	if (tb[RTA_METRICS]) {
115 		int i;
116 		struct nlattr *tbx[RTAX_MAX+1] = {};
117 
118 		mnl_attr_parse_nested(tb[RTA_METRICS], data_attr_cb2, tbx);
119 
120 		for (i=0; i<RTAX_MAX; i++) {
121 			if (tbx[i]) {
122 				printf("metrics[%d]=%u ",
123 					i, mnl_attr_get_u32(tbx[i]));
124 			}
125 		}
126 	}
127 }
128 
data_ipv4_attr_cb(const struct nlattr * attr,void * data)129 static int data_ipv4_attr_cb(const struct nlattr *attr, void *data)
130 {
131 	const struct nlattr **tb = data;
132 	int type = mnl_attr_get_type(attr);
133 
134 	/* skip unsupported attribute in user-space */
135 	if (mnl_attr_type_valid(attr, RTA_MAX) < 0)
136 		return MNL_CB_OK;
137 
138 	switch(type) {
139 	case RTA_TABLE:
140 	case RTA_DST:
141 	case RTA_SRC:
142 	case RTA_OIF:
143 	case RTA_FLOW:
144 	case RTA_PREFSRC:
145 	case RTA_GATEWAY:
146 	case RTA_PRIORITY:
147 		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
148 			perror("mnl_attr_validate");
149 			return MNL_CB_ERROR;
150 		}
151 		break;
152 	case RTA_METRICS:
153 		if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
154 			perror("mnl_attr_validate");
155 			return MNL_CB_ERROR;
156 		}
157 		break;
158 	}
159 	tb[type] = attr;
160 	return MNL_CB_OK;
161 }
162 
data_ipv6_attr_cb(const struct nlattr * attr,void * data)163 static int data_ipv6_attr_cb(const struct nlattr *attr, void *data)
164 {
165 	const struct nlattr **tb = data;
166 	int type = mnl_attr_get_type(attr);
167 
168 	/* skip unsupported attribute in user-space */
169 	if (mnl_attr_type_valid(attr, RTA_MAX) < 0)
170 		return MNL_CB_OK;
171 
172 	switch(type) {
173 	case RTA_TABLE:
174 	case RTA_OIF:
175 	case RTA_FLOW:
176 	case RTA_PRIORITY:
177 		if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0) {
178 			perror("mnl_attr_validate");
179 			return MNL_CB_ERROR;
180 		}
181 		break;
182 	case RTA_DST:
183 	case RTA_SRC:
184 	case RTA_PREFSRC:
185 	case RTA_GATEWAY:
186 		if (mnl_attr_validate2(attr, MNL_TYPE_BINARY,
187 					sizeof(struct in6_addr)) < 0) {
188 			perror("mnl_attr_validate2");
189 			return MNL_CB_ERROR;
190 		}
191 		break;
192 	case RTA_METRICS:
193 		if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0) {
194 			perror("mnl_attr_validate");
195 			return MNL_CB_ERROR;
196 		}
197 		break;
198 	}
199 	tb[type] = attr;
200 	return MNL_CB_OK;
201 }
202 
data_cb(const struct nlmsghdr * nlh,void * data)203 static int data_cb(const struct nlmsghdr *nlh, void *data)
204 {
205 	struct nlattr *tb[RTA_MAX+1] = {};
206 	struct rtmsg *rm = mnl_nlmsg_get_payload(nlh);
207 
208 	/* protocol family = AF_INET | AF_INET6 */
209 	printf("family=%u ", rm->rtm_family);
210 
211 	/* destination CIDR, eg. 24 or 32 for IPv4 */
212 	printf("dst_len=%u ", rm->rtm_dst_len);
213 
214 	/* source CIDR */
215 	printf("src_len=%u ", rm->rtm_src_len);
216 
217 	/* type of service (TOS), eg. 0 */
218 	printf("tos=%u ", rm->rtm_tos);
219 
220 	/* table id:
221 	 *	RT_TABLE_UNSPEC		= 0
222 	 *
223 	 * 	... user defined values ...
224 	 *
225 	 *	RT_TABLE_COMPAT		= 252
226 	 *	RT_TABLE_DEFAULT	= 253
227 	 *	RT_TABLE_MAIN		= 254
228 	 *	RT_TABLE_LOCAL		= 255
229 	 *	RT_TABLE_MAX		= 0xFFFFFFFF
230 	 *
231 	 * Synonimous attribute: RTA_TABLE.
232 	 */
233 	printf("table=%u ", rm->rtm_table);
234 
235 	/* type:
236 	 * 	RTN_UNSPEC	= 0
237 	 * 	RTN_UNICAST	= 1
238 	 * 	RTN_LOCAL	= 2
239 	 * 	RTN_BROADCAST	= 3
240 	 *	RTN_ANYCAST	= 4
241 	 *	RTN_MULTICAST	= 5
242 	 *	RTN_BLACKHOLE	= 6
243 	 *	RTN_UNREACHABLE	= 7
244 	 *	RTN_PROHIBIT	= 8
245 	 *	RTN_THROW	= 9
246 	 *	RTN_NAT		= 10
247 	 *	RTN_XRESOLVE	= 11
248 	 *	__RTN_MAX	= 12
249 	 */
250 	printf("type=%u ", rm->rtm_type);
251 
252 	/* scope:
253 	 * 	RT_SCOPE_UNIVERSE	= 0   : everywhere in the universe
254 	 *
255 	 *      ... user defined values ...
256 	 *
257 	 * 	RT_SCOPE_SITE		= 200
258 	 * 	RT_SCOPE_LINK		= 253 : destination attached to link
259 	 * 	RT_SCOPE_HOST		= 254 : local address
260 	 * 	RT_SCOPE_NOWHERE	= 255 : not existing destination
261 	 */
262 	printf("scope=%u ", rm->rtm_scope);
263 
264 	/* protocol:
265 	 * 	RTPROT_UNSPEC	= 0
266 	 * 	RTPROT_REDIRECT = 1
267 	 * 	RTPROT_KERNEL	= 2 : route installed by kernel
268 	 * 	RTPROT_BOOT	= 3 : route installed during boot
269 	 * 	RTPROT_STATIC	= 4 : route installed by administrator
270 	 *
271 	 * Values >= RTPROT_STATIC are not interpreted by kernel, they are
272 	 * just user-defined.
273 	 */
274 	printf("proto=%u ", rm->rtm_protocol);
275 
276 	/* flags:
277 	 * 	RTM_F_NOTIFY	= 0x100: notify user of route change
278 	 * 	RTM_F_CLONED	= 0x200: this route is cloned
279 	 * 	RTM_F_EQUALIZE	= 0x400: Multipath equalizer: NI
280 	 * 	RTM_F_PREFIX	= 0x800: Prefix addresses
281 	 */
282 	printf("flags=%x ", rm->rtm_flags);
283 
284 	switch(rm->rtm_family) {
285 	case AF_INET:
286 		mnl_attr_parse(nlh, sizeof(*rm), data_ipv4_attr_cb, tb);
287 		attributes_show_ipv4(tb);
288 		break;
289 	case AF_INET6:
290 		mnl_attr_parse(nlh, sizeof(*rm), data_ipv6_attr_cb, tb);
291 		attributes_show_ipv6(tb);
292 		break;
293 	}
294 
295 	printf("\n");
296 	return MNL_CB_OK;
297 }
298 
main(int argc,char * argv[])299 int main(int argc, char *argv[])
300 {
301 	char buf[MNL_SOCKET_DUMP_SIZE];
302 	unsigned int seq, portid;
303 	struct mnl_socket *nl;
304 	struct nlmsghdr *nlh;
305 	struct rtmsg *rtm;
306 	int ret;
307 
308 	if (argc != 2) {
309 		fprintf(stderr, "Usage: %s <inet|inet6>\n", argv[0]);
310 		exit(EXIT_FAILURE);
311 	}
312 
313 	nlh = mnl_nlmsg_put_header(buf);
314 	nlh->nlmsg_type = RTM_GETROUTE;
315 	nlh->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP;
316 	nlh->nlmsg_seq = seq = time(NULL);
317 	rtm = mnl_nlmsg_put_extra_header(nlh, sizeof(struct rtmsg));
318 
319 	if (strcmp(argv[1], "inet") == 0)
320 		rtm->rtm_family = AF_INET;
321 	else if (strcmp(argv[1], "inet6") == 0)
322 		rtm->rtm_family = AF_INET6;
323 
324 	nl = mnl_socket_open(NETLINK_ROUTE);
325 	if (nl == NULL) {
326 		perror("mnl_socket_open");
327 		exit(EXIT_FAILURE);
328 	}
329 
330 	if (mnl_socket_bind(nl, 0, MNL_SOCKET_AUTOPID) < 0) {
331 		perror("mnl_socket_bind");
332 		exit(EXIT_FAILURE);
333 	}
334 	portid = mnl_socket_get_portid(nl);
335 
336 	if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0) {
337 		perror("mnl_socket_sendto");
338 		exit(EXIT_FAILURE);
339 	}
340 
341 	ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
342 	while (ret > 0) {
343 		ret = mnl_cb_run(buf, ret, seq, portid, data_cb, NULL);
344 		if (ret <= MNL_CB_STOP)
345 			break;
346 		ret = mnl_socket_recvfrom(nl, buf, sizeof(buf));
347 	}
348 	if (ret == -1) {
349 		perror("error");
350 		exit(EXIT_FAILURE);
351 	}
352 
353 	mnl_socket_close(nl);
354 
355 	return 0;
356 }
357