]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-netlink/netlink-message-rtnl.c
man/systemd.mount: tmpfs automatically gains After=swap.target dep
[thirdparty/systemd.git] / src / libsystemd / sd-netlink / netlink-message-rtnl.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <netinet/in.h>
4 #include <linux/fib_rules.h>
5 #include <linux/if_addrlabel.h>
6 #include <linux/if_bridge.h>
7 #include <linux/nexthop.h>
8 #include <stdbool.h>
9 #include <unistd.h>
10
11 #include "sd-netlink.h"
12
13 #include "format-util.h"
14 #include "netlink-internal.h"
15 #include "netlink-types.h"
16 #include "netlink-util.h"
17 #include "socket-util.h"
18
19 static bool rtnl_message_type_is_neigh(uint16_t type) {
20 return IN_SET(type, RTM_NEWNEIGH, RTM_GETNEIGH, RTM_DELNEIGH);
21 }
22
23 static bool rtnl_message_type_is_route(uint16_t type) {
24 return IN_SET(type, RTM_NEWROUTE, RTM_GETROUTE, RTM_DELROUTE);
25 }
26
27 static bool rtnl_message_type_is_nexthop(uint16_t type) {
28 return IN_SET(type, RTM_NEWNEXTHOP, RTM_GETNEXTHOP, RTM_DELNEXTHOP);
29 }
30
31 static bool rtnl_message_type_is_link(uint16_t type) {
32 return IN_SET(type,
33 RTM_NEWLINK, RTM_SETLINK, RTM_GETLINK, RTM_DELLINK,
34 RTM_NEWLINKPROP, RTM_DELLINKPROP, RTM_GETLINKPROP);
35 }
36
37 static bool rtnl_message_type_is_addr(uint16_t type) {
38 return IN_SET(type, RTM_NEWADDR, RTM_GETADDR, RTM_DELADDR);
39 }
40
41 static bool rtnl_message_type_is_addrlabel(uint16_t type) {
42 return IN_SET(type, RTM_NEWADDRLABEL, RTM_DELADDRLABEL, RTM_GETADDRLABEL);
43 }
44
45 static bool rtnl_message_type_is_routing_policy_rule(uint16_t type) {
46 return IN_SET(type, RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE);
47 }
48
49 static bool rtnl_message_type_is_traffic_control(uint16_t type) {
50 return IN_SET(type,
51 RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC,
52 RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS);
53 }
54
55 static bool rtnl_message_type_is_mdb(uint16_t type) {
56 return IN_SET(type, RTM_NEWMDB, RTM_DELMDB, RTM_GETMDB);
57 }
58
59 int sd_rtnl_message_route_set_dst_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
60 struct rtmsg *rtm;
61
62 assert_return(m, -EINVAL);
63 assert_return(m->hdr, -EINVAL);
64 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
65
66 rtm = NLMSG_DATA(m->hdr);
67
68 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
69 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
70 return -ERANGE;
71
72 rtm->rtm_dst_len = prefixlen;
73
74 return 0;
75 }
76
77 int sd_rtnl_message_route_set_src_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
78 struct rtmsg *rtm;
79
80 assert_return(m, -EINVAL);
81 assert_return(m->hdr, -EINVAL);
82 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
83
84 rtm = NLMSG_DATA(m->hdr);
85
86 if ((rtm->rtm_family == AF_INET && prefixlen > 32) ||
87 (rtm->rtm_family == AF_INET6 && prefixlen > 128))
88 return -ERANGE;
89
90 rtm->rtm_src_len = prefixlen;
91
92 return 0;
93 }
94
95 int sd_rtnl_message_route_set_scope(sd_netlink_message *m, unsigned char scope) {
96 struct rtmsg *rtm;
97
98 assert_return(m, -EINVAL);
99 assert_return(m->hdr, -EINVAL);
100 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
101
102 rtm = NLMSG_DATA(m->hdr);
103
104 rtm->rtm_scope = scope;
105
106 return 0;
107 }
108
109 int sd_rtnl_message_route_set_flags(sd_netlink_message *m, unsigned flags) {
110 struct rtmsg *rtm;
111
112 assert_return(m, -EINVAL);
113 assert_return(m->hdr, -EINVAL);
114 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
115
116 rtm = NLMSG_DATA(m->hdr);
117
118 rtm->rtm_flags = flags;
119
120 return 0;
121 }
122
123 int sd_rtnl_message_route_get_flags(sd_netlink_message *m, unsigned *flags) {
124 struct rtmsg *rtm;
125
126 assert_return(m, -EINVAL);
127 assert_return(m->hdr, -EINVAL);
128 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
129 assert_return(flags, -EINVAL);
130
131 rtm = NLMSG_DATA(m->hdr);
132
133 *flags = rtm->rtm_flags;
134
135 return 0;
136 }
137
138 int sd_rtnl_message_route_set_table(sd_netlink_message *m, unsigned char table) {
139 struct rtmsg *rtm;
140
141 assert_return(m, -EINVAL);
142 assert_return(m->hdr, -EINVAL);
143 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
144
145 rtm = NLMSG_DATA(m->hdr);
146
147 rtm->rtm_table = table;
148
149 return 0;
150 }
151
152 int sd_rtnl_message_route_get_family(sd_netlink_message *m, int *family) {
153 struct rtmsg *rtm;
154
155 assert_return(m, -EINVAL);
156 assert_return(m->hdr, -EINVAL);
157 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
158 assert_return(family, -EINVAL);
159
160 rtm = NLMSG_DATA(m->hdr);
161
162 *family = rtm->rtm_family;
163
164 return 0;
165 }
166
167 int sd_rtnl_message_route_get_type(sd_netlink_message *m, unsigned char *type) {
168 struct rtmsg *rtm;
169
170 assert_return(m, -EINVAL);
171 assert_return(m->hdr, -EINVAL);
172 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
173 assert_return(type, -EINVAL);
174
175 rtm = NLMSG_DATA(m->hdr);
176
177 *type = rtm->rtm_type;
178
179 return 0;
180 }
181
182 int sd_rtnl_message_route_set_type(sd_netlink_message *m, unsigned char type) {
183 struct rtmsg *rtm;
184
185 assert_return(m, -EINVAL);
186 assert_return(m->hdr, -EINVAL);
187 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
188
189 rtm = NLMSG_DATA(m->hdr);
190
191 rtm->rtm_type = type;
192
193 return 0;
194 }
195
196 int sd_rtnl_message_route_get_protocol(sd_netlink_message *m, unsigned char *protocol) {
197 struct rtmsg *rtm;
198
199 assert_return(m, -EINVAL);
200 assert_return(m->hdr, -EINVAL);
201 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
202 assert_return(protocol, -EINVAL);
203
204 rtm = NLMSG_DATA(m->hdr);
205
206 *protocol = rtm->rtm_protocol;
207
208 return 0;
209 }
210
211 int sd_rtnl_message_route_get_scope(sd_netlink_message *m, unsigned char *scope) {
212 struct rtmsg *rtm;
213
214 assert_return(m, -EINVAL);
215 assert_return(m->hdr, -EINVAL);
216 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
217 assert_return(scope, -EINVAL);
218
219 rtm = NLMSG_DATA(m->hdr);
220
221 *scope = rtm->rtm_scope;
222
223 return 0;
224 }
225
226 int sd_rtnl_message_route_get_tos(sd_netlink_message *m, uint8_t *tos) {
227 struct rtmsg *rtm;
228
229 assert_return(m, -EINVAL);
230 assert_return(m->hdr, -EINVAL);
231 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
232 assert_return(tos, -EINVAL);
233
234 rtm = NLMSG_DATA(m->hdr);
235
236 *tos = rtm->rtm_tos;
237
238 return 0;
239 }
240
241 int sd_rtnl_message_route_get_table(sd_netlink_message *m, unsigned char *table) {
242 struct rtmsg *rtm;
243
244 assert_return(m, -EINVAL);
245 assert_return(m->hdr, -EINVAL);
246 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
247 assert_return(table, -EINVAL);
248
249 rtm = NLMSG_DATA(m->hdr);
250
251 *table = rtm->rtm_table;
252
253 return 0;
254 }
255
256 int sd_rtnl_message_route_get_dst_prefixlen(sd_netlink_message *m, unsigned char *dst_len) {
257 struct rtmsg *rtm;
258
259 assert_return(m, -EINVAL);
260 assert_return(m->hdr, -EINVAL);
261 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
262 assert_return(dst_len, -EINVAL);
263
264 rtm = NLMSG_DATA(m->hdr);
265
266 *dst_len = rtm->rtm_dst_len;
267
268 return 0;
269 }
270
271 int sd_rtnl_message_route_get_src_prefixlen(sd_netlink_message *m, unsigned char *src_len) {
272 struct rtmsg *rtm;
273
274 assert_return(m, -EINVAL);
275 assert_return(m->hdr, -EINVAL);
276 assert_return(rtnl_message_type_is_route(m->hdr->nlmsg_type), -EINVAL);
277 assert_return(src_len, -EINVAL);
278
279 rtm = NLMSG_DATA(m->hdr);
280
281 *src_len = rtm->rtm_src_len;
282
283 return 0;
284 }
285
286 int sd_rtnl_message_new_route(sd_netlink *rtnl, sd_netlink_message **ret,
287 uint16_t nlmsg_type, int rtm_family,
288 unsigned char rtm_protocol) {
289 struct rtmsg *rtm;
290 int r;
291
292 assert_return(rtnl_message_type_is_route(nlmsg_type), -EINVAL);
293 assert_return((nlmsg_type == RTM_GETROUTE && rtm_family == AF_UNSPEC) ||
294 IN_SET(rtm_family, AF_INET, AF_INET6), -EINVAL);
295 assert_return(ret, -EINVAL);
296
297 r = message_new(rtnl, ret, nlmsg_type);
298 if (r < 0)
299 return r;
300
301 if (nlmsg_type == RTM_NEWROUTE)
302 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
303
304 rtm = NLMSG_DATA((*ret)->hdr);
305
306 rtm->rtm_family = rtm_family;
307 rtm->rtm_protocol = rtm_protocol;
308
309 return 0;
310 }
311
312 int sd_rtnl_message_new_nexthop(sd_netlink *rtnl, sd_netlink_message **ret,
313 uint16_t nlmsg_type, int nh_family,
314 unsigned char nh_protocol) {
315 struct nhmsg *nhm;
316 int r;
317
318 assert_return(rtnl_message_type_is_nexthop(nlmsg_type), -EINVAL);
319 switch (nlmsg_type) {
320 case RTM_DELNEXTHOP:
321 assert_return(nh_family == AF_UNSPEC, -EINVAL);
322 _fallthrough_;
323 case RTM_GETNEXTHOP:
324 assert_return(nh_protocol == RTPROT_UNSPEC, -EINVAL);
325 break;
326 case RTM_NEWNEXTHOP:
327 assert_return(IN_SET(nh_family, AF_UNSPEC, AF_INET, AF_INET6), -EINVAL);
328 break;
329 default:
330 assert_not_reached();
331 }
332 assert_return(ret, -EINVAL);
333
334 r = message_new(rtnl, ret, nlmsg_type);
335 if (r < 0)
336 return r;
337
338 if (nlmsg_type == RTM_NEWNEXTHOP)
339 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
340
341 nhm = NLMSG_DATA((*ret)->hdr);
342
343 nhm->nh_family = nh_family;
344 nhm->nh_scope = RT_SCOPE_UNIVERSE;
345 nhm->nh_protocol = nh_protocol;
346
347 return 0;
348 }
349
350 int sd_rtnl_message_nexthop_set_flags(sd_netlink_message *m, uint8_t flags) {
351 struct nhmsg *nhm;
352
353 assert_return(m, -EINVAL);
354 assert_return(m->hdr, -EINVAL);
355 assert_return(m->hdr->nlmsg_type == RTM_NEWNEXTHOP, -EINVAL);
356
357 nhm = NLMSG_DATA(m->hdr);
358 nhm->nh_flags = flags;
359
360 return 0;
361 }
362
363 int sd_rtnl_message_nexthop_get_flags(sd_netlink_message *m, uint8_t *ret) {
364 struct nhmsg *nhm;
365
366 assert_return(m, -EINVAL);
367 assert_return(m->hdr, -EINVAL);
368 assert_return(rtnl_message_type_is_nexthop(m->hdr->nlmsg_type), -EINVAL);
369 assert_return(ret, -EINVAL);
370
371 nhm = NLMSG_DATA(m->hdr);
372 *ret = nhm->nh_flags;
373
374 return 0;
375 }
376
377 int sd_rtnl_message_nexthop_get_family(sd_netlink_message *m, uint8_t *family) {
378 struct nhmsg *nhm;
379
380 assert_return(m, -EINVAL);
381 assert_return(m->hdr, -EINVAL);
382 assert_return(rtnl_message_type_is_nexthop(m->hdr->nlmsg_type), -EINVAL);
383 assert_return(family, -EINVAL);
384
385 nhm = NLMSG_DATA(m->hdr);
386 *family = nhm->nh_family;
387
388 return 0;
389 }
390
391 int sd_rtnl_message_nexthop_get_protocol(sd_netlink_message *m, uint8_t *protocol) {
392 struct nhmsg *nhm;
393
394 assert_return(m, -EINVAL);
395 assert_return(m->hdr, -EINVAL);
396 assert_return(rtnl_message_type_is_nexthop(m->hdr->nlmsg_type), -EINVAL);
397 assert_return(protocol, -EINVAL);
398
399 nhm = NLMSG_DATA(m->hdr);
400 *protocol = nhm->nh_protocol;
401
402 return 0;
403 }
404
405 int sd_rtnl_message_neigh_set_flags(sd_netlink_message *m, uint8_t flags) {
406 struct ndmsg *ndm;
407
408 assert_return(m, -EINVAL);
409 assert_return(m->hdr, -EINVAL);
410 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
411
412 ndm = NLMSG_DATA(m->hdr);
413 ndm->ndm_flags = flags;
414
415 return 0;
416 }
417
418 int sd_rtnl_message_neigh_set_state(sd_netlink_message *m, uint16_t state) {
419 struct ndmsg *ndm;
420
421 assert_return(m, -EINVAL);
422 assert_return(m->hdr, -EINVAL);
423 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
424
425 ndm = NLMSG_DATA(m->hdr);
426 ndm->ndm_state = state;
427
428 return 0;
429 }
430
431 int sd_rtnl_message_neigh_get_flags(sd_netlink_message *m, uint8_t *flags) {
432 struct ndmsg *ndm;
433
434 assert_return(m, -EINVAL);
435 assert_return(m->hdr, -EINVAL);
436 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
437
438 ndm = NLMSG_DATA(m->hdr);
439 *flags = ndm->ndm_flags;
440
441 return 0;
442 }
443
444 int sd_rtnl_message_neigh_get_state(sd_netlink_message *m, uint16_t *state) {
445 struct ndmsg *ndm;
446
447 assert_return(m, -EINVAL);
448 assert_return(m->hdr, -EINVAL);
449 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
450
451 ndm = NLMSG_DATA(m->hdr);
452 *state = ndm->ndm_state;
453
454 return 0;
455 }
456
457 int sd_rtnl_message_neigh_get_family(sd_netlink_message *m, int *family) {
458 struct ndmsg *ndm;
459
460 assert_return(m, -EINVAL);
461 assert_return(m->hdr, -EINVAL);
462 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
463 assert_return(family, -EINVAL);
464
465 ndm = NLMSG_DATA(m->hdr);
466
467 *family = ndm->ndm_family;
468
469 return 0;
470 }
471
472 int sd_rtnl_message_neigh_get_ifindex(sd_netlink_message *m, int *index) {
473 struct ndmsg *ndm;
474
475 assert_return(m, -EINVAL);
476 assert_return(m->hdr, -EINVAL);
477 assert_return(rtnl_message_type_is_neigh(m->hdr->nlmsg_type), -EINVAL);
478 assert_return(index, -EINVAL);
479
480 ndm = NLMSG_DATA(m->hdr);
481
482 *index = ndm->ndm_ifindex;
483
484 return 0;
485 }
486
487 int sd_rtnl_message_new_neigh(
488 sd_netlink *rtnl,
489 sd_netlink_message **ret,
490 uint16_t nlmsg_type,
491 int index,
492 int ndm_family) {
493
494 struct ndmsg *ndm;
495 int r;
496
497 assert_return(rtnl_message_type_is_neigh(nlmsg_type), -EINVAL);
498 assert_return(IN_SET(ndm_family, AF_UNSPEC, AF_INET, AF_INET6, AF_BRIDGE), -EINVAL);
499 assert_return(ret, -EINVAL);
500
501 r = message_new(rtnl, ret, nlmsg_type);
502 if (r < 0)
503 return r;
504
505 if (nlmsg_type == RTM_NEWNEIGH) {
506 if (ndm_family == AF_BRIDGE)
507 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_APPEND;
508 else
509 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_REPLACE;
510 }
511
512 ndm = NLMSG_DATA((*ret)->hdr);
513
514 ndm->ndm_family = ndm_family;
515 ndm->ndm_ifindex = index;
516
517 return 0;
518 }
519
520 int sd_rtnl_message_link_set_flags(sd_netlink_message *m, unsigned flags, unsigned change) {
521 struct ifinfomsg *ifi;
522
523 assert_return(m, -EINVAL);
524 assert_return(m->hdr, -EINVAL);
525 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
526 assert_return(change != 0, -EINVAL);
527
528 ifi = NLMSG_DATA(m->hdr);
529
530 ifi->ifi_flags = flags;
531 ifi->ifi_change = change;
532
533 return 0;
534 }
535
536 int sd_rtnl_message_link_set_type(sd_netlink_message *m, unsigned type) {
537 struct ifinfomsg *ifi;
538
539 assert_return(m, -EINVAL);
540 assert_return(m->hdr, -EINVAL);
541 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
542
543 ifi = NLMSG_DATA(m->hdr);
544
545 ifi->ifi_type = type;
546
547 return 0;
548 }
549
550 int sd_rtnl_message_link_set_family(sd_netlink_message *m, unsigned family) {
551 struct ifinfomsg *ifi;
552
553 assert_return(m, -EINVAL);
554 assert_return(m->hdr, -EINVAL);
555 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
556
557 ifi = NLMSG_DATA(m->hdr);
558
559 ifi->ifi_family = family;
560
561 return 0;
562 }
563
564 int sd_rtnl_message_new_link(sd_netlink *rtnl, sd_netlink_message **ret,
565 uint16_t nlmsg_type, int index) {
566 struct ifinfomsg *ifi;
567 int r;
568
569 assert_return(rtnl_message_type_is_link(nlmsg_type), -EINVAL);
570 assert_return(ret, -EINVAL);
571
572 r = message_new(rtnl, ret, nlmsg_type);
573 if (r < 0)
574 return r;
575
576 if (nlmsg_type == RTM_NEWLINK)
577 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
578 else if (nlmsg_type == RTM_NEWLINKPROP)
579 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL | NLM_F_APPEND;
580
581 ifi = NLMSG_DATA((*ret)->hdr);
582
583 ifi->ifi_family = AF_UNSPEC;
584 ifi->ifi_index = index;
585
586 return 0;
587 }
588
589 int sd_rtnl_message_addr_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
590 struct ifaddrmsg *ifa;
591
592 assert_return(m, -EINVAL);
593 assert_return(m->hdr, -EINVAL);
594 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
595
596 ifa = NLMSG_DATA(m->hdr);
597
598 if ((ifa->ifa_family == AF_INET && prefixlen > 32) ||
599 (ifa->ifa_family == AF_INET6 && prefixlen > 128))
600 return -ERANGE;
601
602 ifa->ifa_prefixlen = prefixlen;
603
604 return 0;
605 }
606
607 int sd_rtnl_message_addr_set_flags(sd_netlink_message *m, unsigned char flags) {
608 struct ifaddrmsg *ifa;
609
610 assert_return(m, -EINVAL);
611 assert_return(m->hdr, -EINVAL);
612 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
613
614 ifa = NLMSG_DATA(m->hdr);
615
616 ifa->ifa_flags = flags;
617
618 return 0;
619 }
620
621 int sd_rtnl_message_addr_set_scope(sd_netlink_message *m, unsigned char scope) {
622 struct ifaddrmsg *ifa;
623
624 assert_return(m, -EINVAL);
625 assert_return(m->hdr, -EINVAL);
626 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
627
628 ifa = NLMSG_DATA(m->hdr);
629
630 ifa->ifa_scope = scope;
631
632 return 0;
633 }
634
635 int sd_rtnl_message_addr_get_family(sd_netlink_message *m, int *ret_family) {
636 struct ifaddrmsg *ifa;
637
638 assert_return(m, -EINVAL);
639 assert_return(m->hdr, -EINVAL);
640 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
641 assert_return(ret_family, -EINVAL);
642
643 ifa = NLMSG_DATA(m->hdr);
644
645 *ret_family = ifa->ifa_family;
646
647 return 0;
648 }
649
650 int sd_rtnl_message_addr_get_prefixlen(sd_netlink_message *m, unsigned char *ret_prefixlen) {
651 struct ifaddrmsg *ifa;
652
653 assert_return(m, -EINVAL);
654 assert_return(m->hdr, -EINVAL);
655 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
656 assert_return(ret_prefixlen, -EINVAL);
657
658 ifa = NLMSG_DATA(m->hdr);
659
660 *ret_prefixlen = ifa->ifa_prefixlen;
661
662 return 0;
663 }
664
665 int sd_rtnl_message_addr_get_scope(sd_netlink_message *m, unsigned char *ret_scope) {
666 struct ifaddrmsg *ifa;
667
668 assert_return(m, -EINVAL);
669 assert_return(m->hdr, -EINVAL);
670 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
671 assert_return(ret_scope, -EINVAL);
672
673 ifa = NLMSG_DATA(m->hdr);
674
675 *ret_scope = ifa->ifa_scope;
676
677 return 0;
678 }
679
680 int sd_rtnl_message_addr_get_flags(sd_netlink_message *m, unsigned char *ret_flags) {
681 struct ifaddrmsg *ifa;
682
683 assert_return(m, -EINVAL);
684 assert_return(m->hdr, -EINVAL);
685 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
686 assert_return(ret_flags, -EINVAL);
687
688 ifa = NLMSG_DATA(m->hdr);
689
690 *ret_flags = ifa->ifa_flags;
691
692 return 0;
693 }
694
695 int sd_rtnl_message_addr_get_ifindex(sd_netlink_message *m, int *ret_ifindex) {
696 struct ifaddrmsg *ifa;
697
698 assert_return(m, -EINVAL);
699 assert_return(m->hdr, -EINVAL);
700 assert_return(rtnl_message_type_is_addr(m->hdr->nlmsg_type), -EINVAL);
701 assert_return(ret_ifindex, -EINVAL);
702
703 ifa = NLMSG_DATA(m->hdr);
704
705 *ret_ifindex = ifa->ifa_index;
706
707 return 0;
708 }
709
710 int sd_rtnl_message_new_addr(
711 sd_netlink *rtnl,
712 sd_netlink_message **ret,
713 uint16_t nlmsg_type,
714 int index,
715 int family) {
716
717 struct ifaddrmsg *ifa;
718 int r;
719
720 assert_return(rtnl_message_type_is_addr(nlmsg_type), -EINVAL);
721 assert_return((nlmsg_type == RTM_GETADDR && index == 0) ||
722 index > 0, -EINVAL);
723 assert_return((nlmsg_type == RTM_GETADDR && family == AF_UNSPEC) ||
724 IN_SET(family, AF_INET, AF_INET6), -EINVAL);
725 assert_return(ret, -EINVAL);
726
727 r = message_new(rtnl, ret, nlmsg_type);
728 if (r < 0)
729 return r;
730
731 ifa = NLMSG_DATA((*ret)->hdr);
732
733 ifa->ifa_index = index;
734 ifa->ifa_family = family;
735
736 return 0;
737 }
738
739 int sd_rtnl_message_new_addr_update(
740 sd_netlink *rtnl,
741 sd_netlink_message **ret,
742 int index,
743 int family) {
744 int r;
745
746 r = sd_rtnl_message_new_addr(rtnl, ret, RTM_NEWADDR, index, family);
747 if (r < 0)
748 return r;
749
750 (*ret)->hdr->nlmsg_flags |= NLM_F_REPLACE;
751
752 return 0;
753 }
754
755 int sd_rtnl_message_link_get_ifindex(sd_netlink_message *m, int *ifindex) {
756 struct ifinfomsg *ifi;
757
758 assert_return(m, -EINVAL);
759 assert_return(m->hdr, -EINVAL);
760 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
761 assert_return(ifindex, -EINVAL);
762
763 ifi = NLMSG_DATA(m->hdr);
764
765 *ifindex = ifi->ifi_index;
766
767 return 0;
768 }
769
770 int sd_rtnl_message_link_get_flags(sd_netlink_message *m, unsigned *flags) {
771 struct ifinfomsg *ifi;
772
773 assert_return(m, -EINVAL);
774 assert_return(m->hdr, -EINVAL);
775 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
776 assert_return(flags, -EINVAL);
777
778 ifi = NLMSG_DATA(m->hdr);
779
780 *flags = ifi->ifi_flags;
781
782 return 0;
783 }
784
785 int sd_rtnl_message_link_get_type(sd_netlink_message *m, unsigned short *type) {
786 struct ifinfomsg *ifi;
787
788 assert_return(m, -EINVAL);
789 assert_return(m->hdr, -EINVAL);
790 assert_return(rtnl_message_type_is_link(m->hdr->nlmsg_type), -EINVAL);
791 assert_return(type, -EINVAL);
792
793 ifi = NLMSG_DATA(m->hdr);
794
795 *type = ifi->ifi_type;
796
797 return 0;
798 }
799
800 int sd_rtnl_message_get_family(sd_netlink_message *m, int *family) {
801 assert_return(m, -EINVAL);
802 assert_return(family, -EINVAL);
803
804 assert(m->hdr);
805
806 if (rtnl_message_type_is_link(m->hdr->nlmsg_type)) {
807 struct ifinfomsg *ifi;
808
809 ifi = NLMSG_DATA(m->hdr);
810
811 *family = ifi->ifi_family;
812
813 return 0;
814 } else if (rtnl_message_type_is_route(m->hdr->nlmsg_type)) {
815 struct rtmsg *rtm;
816
817 rtm = NLMSG_DATA(m->hdr);
818
819 *family = rtm->rtm_family;
820
821 return 0;
822 } else if (rtnl_message_type_is_neigh(m->hdr->nlmsg_type)) {
823 struct ndmsg *ndm;
824
825 ndm = NLMSG_DATA(m->hdr);
826
827 *family = ndm->ndm_family;
828
829 return 0;
830 } else if (rtnl_message_type_is_addr(m->hdr->nlmsg_type)) {
831 struct ifaddrmsg *ifa;
832
833 ifa = NLMSG_DATA(m->hdr);
834
835 *family = ifa->ifa_family;
836
837 return 0;
838 } else if (rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type)) {
839 struct rtmsg *rtm;
840
841 rtm = NLMSG_DATA(m->hdr);
842
843 *family = rtm->rtm_family;
844
845 return 0;
846 } else if (rtnl_message_type_is_nexthop(m->hdr->nlmsg_type)) {
847 struct nhmsg *nhm;
848
849 nhm = NLMSG_DATA(m->hdr);
850
851 *family = nhm->nh_family;
852
853 return 0;
854 }
855
856 return -EOPNOTSUPP;
857 }
858
859 int sd_rtnl_message_new_addrlabel(
860 sd_netlink *rtnl,
861 sd_netlink_message **ret,
862 uint16_t nlmsg_type,
863 int ifindex,
864 int ifal_family) {
865
866 struct ifaddrlblmsg *addrlabel;
867 int r;
868
869 assert_return(rtnl_message_type_is_addrlabel(nlmsg_type), -EINVAL);
870 assert_return(ret, -EINVAL);
871
872 r = message_new(rtnl, ret, nlmsg_type);
873 if (r < 0)
874 return r;
875
876 if (nlmsg_type == RTM_NEWADDRLABEL)
877 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
878
879 addrlabel = NLMSG_DATA((*ret)->hdr);
880
881 addrlabel->ifal_family = ifal_family;
882 addrlabel->ifal_index = ifindex;
883
884 return 0;
885 }
886
887 int sd_rtnl_message_addrlabel_set_prefixlen(sd_netlink_message *m, unsigned char prefixlen) {
888 struct ifaddrlblmsg *addrlabel;
889
890 assert_return(m, -EINVAL);
891 assert_return(m->hdr, -EINVAL);
892 assert_return(rtnl_message_type_is_addrlabel(m->hdr->nlmsg_type), -EINVAL);
893
894 addrlabel = NLMSG_DATA(m->hdr);
895
896 if (prefixlen > 128)
897 return -ERANGE;
898
899 addrlabel->ifal_prefixlen = prefixlen;
900
901 return 0;
902 }
903
904 int sd_rtnl_message_addrlabel_get_prefixlen(sd_netlink_message *m, unsigned char *prefixlen) {
905 struct ifaddrlblmsg *addrlabel;
906
907 assert_return(m, -EINVAL);
908 assert_return(m->hdr, -EINVAL);
909 assert_return(rtnl_message_type_is_addrlabel(m->hdr->nlmsg_type), -EINVAL);
910
911 addrlabel = NLMSG_DATA(m->hdr);
912
913 *prefixlen = addrlabel->ifal_prefixlen;
914
915 return 0;
916 }
917
918 int sd_rtnl_message_new_routing_policy_rule(
919 sd_netlink *rtnl,
920 sd_netlink_message **ret,
921 uint16_t nlmsg_type,
922 int ifal_family) {
923
924 struct fib_rule_hdr *frh;
925 int r;
926
927 assert_return(rtnl_message_type_is_routing_policy_rule(nlmsg_type), -EINVAL);
928 assert_return(ret, -EINVAL);
929
930 r = message_new(rtnl, ret, nlmsg_type);
931 if (r < 0)
932 return r;
933
934 if (nlmsg_type == RTM_NEWRULE)
935 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
936
937 frh = NLMSG_DATA((*ret)->hdr);
938 frh->family = ifal_family;
939
940 return 0;
941 }
942
943 int sd_rtnl_message_routing_policy_rule_set_tos(sd_netlink_message *m, uint8_t tos) {
944 struct fib_rule_hdr *frh;
945
946 assert_return(m, -EINVAL);
947 assert_return(m->hdr, -EINVAL);
948 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
949
950 frh = NLMSG_DATA(m->hdr);
951
952 frh->tos = tos;
953
954 return 0;
955 }
956
957 int sd_rtnl_message_routing_policy_rule_get_tos(sd_netlink_message *m, uint8_t *tos) {
958 struct fib_rule_hdr *frh;
959
960 assert_return(m, -EINVAL);
961 assert_return(m->hdr, -EINVAL);
962 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
963
964 frh = NLMSG_DATA(m->hdr);
965
966 *tos = frh->tos;
967
968 return 0;
969 }
970
971 int sd_rtnl_message_routing_policy_rule_set_table(sd_netlink_message *m, uint8_t table) {
972 struct fib_rule_hdr *frh;
973
974 assert_return(m, -EINVAL);
975 assert_return(m->hdr, -EINVAL);
976 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
977
978 frh = NLMSG_DATA(m->hdr);
979
980 frh->table = table;
981
982 return 0;
983 }
984
985 int sd_rtnl_message_routing_policy_rule_get_table(sd_netlink_message *m, uint8_t *table) {
986 struct fib_rule_hdr *frh;
987
988 assert_return(m, -EINVAL);
989 assert_return(m->hdr, -EINVAL);
990 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
991
992 frh = NLMSG_DATA(m->hdr);
993
994 *table = frh->table;
995
996 return 0;
997 }
998
999 int sd_rtnl_message_routing_policy_rule_set_flags(sd_netlink_message *m, uint32_t flags) {
1000 struct fib_rule_hdr *frh;
1001
1002 assert_return(m, -EINVAL);
1003 assert_return(m->hdr, -EINVAL);
1004 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
1005
1006 frh = NLMSG_DATA(m->hdr);
1007 frh->flags = flags;
1008
1009 return 0;
1010 }
1011
1012 int sd_rtnl_message_routing_policy_rule_get_flags(sd_netlink_message *m, uint32_t *flags) {
1013 struct fib_rule_hdr *frh;
1014
1015 assert_return(m, -EINVAL);
1016 assert_return(m->hdr, -EINVAL);
1017 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
1018
1019 frh = NLMSG_DATA(m->hdr);
1020 *flags = frh->flags;
1021
1022 return 0;
1023 }
1024
1025 int sd_rtnl_message_routing_policy_rule_set_fib_type(sd_netlink_message *m, uint8_t type) {
1026 struct fib_rule_hdr *frh;
1027
1028 assert_return(m, -EINVAL);
1029 assert_return(m->hdr, -EINVAL);
1030 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
1031
1032 frh = NLMSG_DATA(m->hdr);
1033
1034 frh->action = type;
1035
1036 return 0;
1037 }
1038
1039 int sd_rtnl_message_routing_policy_rule_get_fib_type(sd_netlink_message *m, uint8_t *type) {
1040 struct fib_rule_hdr *frh;
1041
1042 assert_return(m, -EINVAL);
1043 assert_return(m->hdr, -EINVAL);
1044 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
1045
1046 frh = NLMSG_DATA(m->hdr);
1047
1048 *type = frh->action;
1049
1050 return 0;
1051 }
1052
1053 int sd_rtnl_message_routing_policy_rule_set_fib_dst_prefixlen(sd_netlink_message *m, uint8_t len) {
1054 struct fib_rule_hdr *frh;
1055
1056 assert_return(m, -EINVAL);
1057 assert_return(m->hdr, -EINVAL);
1058 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
1059
1060 frh = NLMSG_DATA(m->hdr);
1061
1062 frh->dst_len = len;
1063
1064 return 0;
1065 }
1066
1067 int sd_rtnl_message_routing_policy_rule_get_fib_dst_prefixlen(sd_netlink_message *m, uint8_t *len) {
1068 struct fib_rule_hdr *frh;
1069
1070 assert_return(m, -EINVAL);
1071 assert_return(m->hdr, -EINVAL);
1072 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
1073
1074 frh = NLMSG_DATA(m->hdr);
1075
1076 *len = frh->dst_len;
1077
1078 return 0;
1079 }
1080
1081 int sd_rtnl_message_routing_policy_rule_set_fib_src_prefixlen(sd_netlink_message *m, uint8_t len) {
1082 struct fib_rule_hdr *frh;
1083
1084 assert_return(m, -EINVAL);
1085 assert_return(m->hdr, -EINVAL);
1086 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
1087
1088 frh = NLMSG_DATA(m->hdr);
1089
1090 frh->src_len = len;
1091
1092 return 0;
1093 }
1094
1095 int sd_rtnl_message_routing_policy_rule_get_fib_src_prefixlen(sd_netlink_message *m, uint8_t *len) {
1096 struct fib_rule_hdr *frh;
1097
1098 assert_return(m, -EINVAL);
1099 assert_return(m->hdr, -EINVAL);
1100 assert_return(rtnl_message_type_is_routing_policy_rule(m->hdr->nlmsg_type), -EINVAL);
1101
1102 frh = NLMSG_DATA(m->hdr);
1103
1104 *len = frh->src_len;
1105
1106 return 0;
1107 }
1108
1109 int sd_rtnl_message_new_traffic_control(
1110 sd_netlink *rtnl,
1111 sd_netlink_message **ret,
1112 uint16_t nlmsg_type,
1113 int ifindex,
1114 uint32_t handle,
1115 uint32_t parent) {
1116
1117 struct tcmsg *tcm;
1118 int r;
1119
1120 assert_return(rtnl_message_type_is_traffic_control(nlmsg_type), -EINVAL);
1121 assert_return(ret, -EINVAL);
1122
1123 r = message_new(rtnl, ret, nlmsg_type);
1124 if (r < 0)
1125 return r;
1126
1127 if (IN_SET(nlmsg_type, RTM_NEWQDISC, RTM_NEWTCLASS))
1128 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
1129
1130 tcm = NLMSG_DATA((*ret)->hdr);
1131 tcm->tcm_ifindex = ifindex;
1132 tcm->tcm_handle = handle;
1133 tcm->tcm_parent = parent;
1134
1135 return 0;
1136 }
1137
1138 int sd_rtnl_message_traffic_control_get_ifindex(sd_netlink_message *m, int *ret) {
1139 struct tcmsg *tcm;
1140
1141 assert_return(m, -EINVAL);
1142 assert_return(m->hdr, -EINVAL);
1143 assert_return(rtnl_message_type_is_traffic_control(m->hdr->nlmsg_type), -EINVAL);
1144 assert_return(ret, -EINVAL);
1145
1146 tcm = NLMSG_DATA(m->hdr);
1147 *ret = tcm->tcm_ifindex;
1148
1149 return 0;
1150 }
1151
1152 int sd_rtnl_message_traffic_control_get_handle(sd_netlink_message *m, uint32_t *ret) {
1153 struct tcmsg *tcm;
1154
1155 assert_return(m, -EINVAL);
1156 assert_return(m->hdr, -EINVAL);
1157 assert_return(rtnl_message_type_is_traffic_control(m->hdr->nlmsg_type), -EINVAL);
1158 assert_return(ret, -EINVAL);
1159
1160 tcm = NLMSG_DATA(m->hdr);
1161 *ret = tcm->tcm_handle;
1162
1163 return 0;
1164 }
1165
1166 int sd_rtnl_message_traffic_control_get_parent(sd_netlink_message *m, uint32_t *ret) {
1167 struct tcmsg *tcm;
1168
1169 assert_return(m, -EINVAL);
1170 assert_return(m->hdr, -EINVAL);
1171 assert_return(rtnl_message_type_is_traffic_control(m->hdr->nlmsg_type), -EINVAL);
1172 assert_return(ret, -EINVAL);
1173
1174 tcm = NLMSG_DATA(m->hdr);
1175 *ret = tcm->tcm_parent;
1176
1177 return 0;
1178 }
1179
1180 int sd_rtnl_message_new_mdb(
1181 sd_netlink *rtnl,
1182 sd_netlink_message **ret,
1183 uint16_t nlmsg_type,
1184 int mdb_ifindex) {
1185
1186 struct br_port_msg *bpm;
1187 int r;
1188
1189 assert_return(rtnl_message_type_is_mdb(nlmsg_type), -EINVAL);
1190 assert_return(ret, -EINVAL);
1191
1192 r = message_new(rtnl, ret, nlmsg_type);
1193 if (r < 0)
1194 return r;
1195
1196 if (nlmsg_type == RTM_NEWMDB)
1197 (*ret)->hdr->nlmsg_flags |= NLM_F_CREATE | NLM_F_EXCL;
1198
1199 bpm = NLMSG_DATA((*ret)->hdr);
1200 bpm->family = AF_BRIDGE;
1201 bpm->ifindex = mdb_ifindex;
1202
1203 return 0;
1204 }