1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "sd-netlink.h"
5 #include "ether-addr-util.h"
8 #include "iovec-util.h"
10 #include "memory-util.h"
11 #include "netlink-internal.h"
12 #include "netlink-util.h"
13 #include "parse-util.h"
14 #include "process-util.h"
15 #include "socket-util.h"
16 #include "string-util.h"
19 static int parse_newlink_message(
20 sd_netlink_message
*message
,
22 char ***ret_altnames
) {
24 _cleanup_strv_free_
char **altnames
= NULL
;
30 r
= sd_netlink_message_get_type(message
, &type
);
33 if (type
!= RTM_NEWLINK
)
36 r
= sd_rtnl_message_link_get_ifindex(message
, &ifindex
);
43 r
= sd_netlink_message_read_strv(message
, IFLA_PROP_LIST
, IFLA_ALT_IFNAME
, &altnames
);
44 if (r
< 0 && r
!= -ENODATA
)
49 r
= sd_netlink_message_read_string_strdup(message
, IFLA_IFNAME
, ret_name
);
55 *ret_altnames
= TAKE_PTR(altnames
);
60 int rtnl_resolve_ifname_full(
62 ResolveInterfaceNameFlag flags
,
65 char ***ret_altnames
) {
67 _cleanup_(sd_netlink_unrefp
) sd_netlink
*our_rtnl
= NULL
;
73 /* This is similar to if_nametoindex(), but also resolves alternative names and decimal formatted
74 * ifindex too. Returns ifindex, and optionally provides the main interface name and alternative
80 r
= sd_netlink_open(rtnl
);
85 /* First, use IFLA_IFNAME */
86 if (FLAGS_SET(flags
, RESOLVE_IFNAME_MAIN
) && ifname_valid(name
)) {
87 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
, *reply
= NULL
;
89 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_GETLINK
, 0);
93 r
= sd_netlink_message_append_string(message
, IFLA_IFNAME
, name
);
97 r
= sd_netlink_call(*rtnl
, message
, 0, &reply
);
99 return parse_newlink_message(reply
, ret_name
, ret_altnames
);
104 /* Next, try IFLA_ALT_IFNAME */
105 if (FLAGS_SET(flags
, RESOLVE_IFNAME_ALTERNATIVE
) &&
106 ifname_valid_full(name
, IFNAME_VALID_ALTERNATIVE
)) {
107 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
, *reply
= NULL
;
109 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_GETLINK
, 0);
113 r
= sd_netlink_message_append_string(message
, IFLA_ALT_IFNAME
, name
);
117 r
= sd_netlink_call(*rtnl
, message
, 0, &reply
);
119 return parse_newlink_message(reply
, ret_name
, ret_altnames
);
120 /* The kernels older than 76c9ac0ee878f6693d398d3a95ccaf85e1f597a6 (v5.5) return -EINVAL. */
121 if (!IN_SET(r
, -ENODEV
, -EINVAL
))
125 /* Finally, assume the string is a decimal formatted ifindex. */
126 if (FLAGS_SET(flags
, RESOLVE_IFNAME_NUMERIC
)) {
129 ifindex
= parse_ifindex(name
);
133 return rtnl_get_ifname_full(rtnl
, ifindex
, ret_name
, ret_altnames
);
139 int rtnl_resolve_interface_or_warn(sd_netlink
**rtnl
, const char *name
) {
144 r
= rtnl_resolve_interface(rtnl
, name
);
146 return log_error_errno(r
, "Failed to resolve interface \"%s\": %m", name
);
150 static int set_link_name(sd_netlink
*rtnl
, int ifindex
, const char *name
) {
151 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
158 /* Assign the requested name. */
160 r
= sd_rtnl_message_new_link(rtnl
, &message
, RTM_SETLINK
, ifindex
);
164 r
= sd_netlink_message_append_string(message
, IFLA_IFNAME
, name
);
168 return sd_netlink_call(rtnl
, message
, 0, NULL
);
171 int rtnl_rename_link(sd_netlink
**rtnl
, const char *orig_name
, const char *new_name
) {
172 _cleanup_(sd_netlink_unrefp
) sd_netlink
*our_rtnl
= NULL
;
178 /* This does not check alternative names. Callers must check the requested name is not used as an
179 * alternative name. */
181 if (streq(orig_name
, new_name
))
184 if (!ifname_valid(new_name
))
190 r
= sd_netlink_open(rtnl
);
195 ifindex
= rtnl_resolve_ifname(rtnl
, orig_name
);
199 return set_link_name(*rtnl
, ifindex
, new_name
);
202 int rtnl_set_link_name(sd_netlink
**rtnl
, int ifindex
, const char *name
, char* const *alternative_names
) {
203 _cleanup_strv_free_
char **original_altnames
= NULL
, **new_altnames
= NULL
;
204 bool altname_deleted
= false;
209 if (isempty(name
) && strv_isempty(alternative_names
))
212 if (name
&& !ifname_valid(name
))
215 _cleanup_(sd_netlink_unrefp
) sd_netlink
*our_rtnl
= NULL
;
219 /* If the requested name is already assigned as an alternative name, then first drop it. */
220 r
= rtnl_get_link_alternative_names(rtnl
, ifindex
, &original_altnames
);
222 log_debug_errno(r
, "Failed to get alternative names on network interface %i, ignoring: %m",
226 if (strv_contains(original_altnames
, name
)) {
227 r
= rtnl_delete_link_alternative_names(rtnl
, ifindex
, STRV_MAKE(name
));
229 return log_debug_errno(r
, "Failed to remove '%s' from alternative names on network interface %i: %m",
232 altname_deleted
= true;
235 r
= set_link_name(*rtnl
, ifindex
, name
);
240 /* Filter out already assigned names from requested alternative names. Also, dedup the request. */
241 STRV_FOREACH(a
, alternative_names
) {
242 if (streq_ptr(name
, *a
))
245 if (strv_contains(original_altnames
, *a
))
248 if (strv_contains(new_altnames
, *a
))
251 if (!ifname_valid_full(*a
, IFNAME_VALID_ALTERNATIVE
))
254 r
= strv_extend(&new_altnames
, *a
);
259 strv_sort(new_altnames
);
261 /* Finally, assign alternative names. */
262 r
= rtnl_set_link_alternative_names(rtnl
, ifindex
, new_altnames
);
263 if (r
== -EEXIST
) /* Already assigned to another interface? */
264 STRV_FOREACH(a
, new_altnames
) {
265 r
= rtnl_set_link_alternative_names(rtnl
, ifindex
, STRV_MAKE(*a
));
267 log_debug_errno(r
, "Failed to assign '%s' as an alternative name on network interface %i, ignoring: %m",
271 log_debug_errno(r
, "Failed to assign alternative names on network interface %i, ignoring: %m", ifindex
);
276 if (altname_deleted
) {
277 int q
= rtnl_set_link_alternative_names(rtnl
, ifindex
, STRV_MAKE(name
));
279 log_debug_errno(q
, "Failed to restore '%s' as an alternative name on network interface %i, ignoring: %m",
286 int rtnl_set_link_properties(
290 const struct hw_addr_data
*hw_addr
,
295 uint32_t gso_max_size
,
296 size_t gso_max_segments
) {
303 (!hw_addr
|| hw_addr
->length
== 0) &&
306 txqueuelen
== UINT32_MAX
&&
309 gso_max_segments
== 0)
312 _cleanup_(sd_netlink_unrefp
) sd_netlink
*our_rtnl
= NULL
;
316 r
= sd_netlink_open(rtnl
);
321 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
322 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_SETLINK
, ifindex
);
327 r
= sd_netlink_message_append_string(message
, IFLA_IFALIAS
, alias
);
332 if (hw_addr
&& hw_addr
->length
> 0) {
333 r
= netlink_message_append_hw_addr(message
, IFLA_ADDRESS
, hw_addr
);
339 r
= sd_netlink_message_append_u32(message
, IFLA_NUM_TX_QUEUES
, txqueues
);
345 r
= sd_netlink_message_append_u32(message
, IFLA_NUM_RX_QUEUES
, rxqueues
);
350 if (txqueuelen
< UINT32_MAX
) {
351 r
= sd_netlink_message_append_u32(message
, IFLA_TXQLEN
, txqueuelen
);
357 r
= sd_netlink_message_append_u32(message
, IFLA_MTU
, mtu
);
362 if (gso_max_size
> 0) {
363 r
= sd_netlink_message_append_u32(message
, IFLA_GSO_MAX_SIZE
, gso_max_size
);
368 if (gso_max_segments
> 0) {
369 r
= sd_netlink_message_append_u32(message
, IFLA_GSO_MAX_SEGS
, gso_max_segments
);
374 r
= sd_netlink_call(*rtnl
, message
, 0, NULL
);
381 static int rtnl_update_link_alternative_names(
385 char* const *alternative_names
) {
390 assert(IN_SET(nlmsg_type
, RTM_NEWLINKPROP
, RTM_DELLINKPROP
));
392 if (strv_isempty(alternative_names
))
395 _cleanup_(sd_netlink_unrefp
) sd_netlink
*our_rtnl
= NULL
;
399 r
= sd_netlink_open(rtnl
);
404 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
405 r
= sd_rtnl_message_new_link(*rtnl
, &message
, nlmsg_type
, ifindex
);
409 r
= sd_netlink_message_open_container(message
, IFLA_PROP_LIST
);
413 r
= sd_netlink_message_append_strv(message
, IFLA_ALT_IFNAME
, (const char**) alternative_names
);
417 r
= sd_netlink_message_close_container(message
);
421 r
= sd_netlink_call(*rtnl
, message
, 0, NULL
);
428 int rtnl_set_link_alternative_names(sd_netlink
**rtnl
, int ifindex
, char* const *alternative_names
) {
429 return rtnl_update_link_alternative_names(rtnl
, RTM_NEWLINKPROP
, ifindex
, alternative_names
);
432 int rtnl_delete_link_alternative_names(sd_netlink
**rtnl
, int ifindex
, char* const *alternative_names
) {
433 return rtnl_update_link_alternative_names(rtnl
, RTM_DELLINKPROP
, ifindex
, alternative_names
);
436 int rtnl_set_link_alternative_names_by_ifname(
439 char* const *alternative_names
) {
446 if (strv_isempty(alternative_names
))
449 _cleanup_(sd_netlink_unrefp
) sd_netlink
*our_rtnl
= NULL
;
453 r
= sd_netlink_open(rtnl
);
458 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
459 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_NEWLINKPROP
, 0);
463 r
= sd_netlink_message_append_string(message
, IFLA_IFNAME
, ifname
);
467 r
= sd_netlink_message_open_container(message
, IFLA_PROP_LIST
);
471 r
= sd_netlink_message_append_strv(message
, IFLA_ALT_IFNAME
, (const char**) alternative_names
);
475 r
= sd_netlink_message_close_container(message
);
479 r
= sd_netlink_call(*rtnl
, message
, 0, NULL
);
486 int rtnl_get_link_info_full(
490 char ***ret_altnames
,
491 unsigned short *ret_iftype
,
494 struct hw_addr_data
*ret_hw_addr
,
495 struct hw_addr_data
*ret_permanent_hw_addr
) {
497 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
, *reply
= NULL
;
498 _cleanup_(sd_netlink_unrefp
) sd_netlink
*our_rtnl
= NULL
;
499 struct hw_addr_data addr
= HW_ADDR_NULL
, perm_addr
= HW_ADDR_NULL
;
500 _cleanup_free_
char *name
= NULL
, *kind
= NULL
;
501 _cleanup_strv_free_
char **altnames
= NULL
;
502 unsigned short iftype
;
511 r
= sd_netlink_open(rtnl
);
516 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_GETLINK
, ifindex
);
520 r
= sd_netlink_call(*rtnl
, message
, 0, &reply
);
522 return -ENODEV
; /* The device does not exist */
526 r
= parse_newlink_message(reply
, ret_name
? &name
: NULL
, ret_altnames
? &altnames
: NULL
);
533 r
= sd_rtnl_message_link_get_type(reply
, &iftype
);
539 r
= sd_rtnl_message_link_get_flags(reply
, &flags
);
545 r
= sd_netlink_message_enter_container(reply
, IFLA_LINKINFO
);
547 r
= sd_netlink_message_read_string_strdup(reply
, IFLA_INFO_KIND
, &kind
);
548 if (r
< 0 && r
!= -ENODATA
)
551 r
= sd_netlink_message_exit_container(reply
);
558 r
= netlink_message_read_hw_addr(reply
, IFLA_ADDRESS
, &addr
);
559 if (r
< 0 && r
!= -ENODATA
)
563 if (ret_permanent_hw_addr
) {
564 r
= netlink_message_read_hw_addr(reply
, IFLA_PERM_ADDRESS
, &perm_addr
);
565 if (r
< 0 && r
!= -ENODATA
)
570 *ret_name
= TAKE_PTR(name
);
572 *ret_altnames
= TAKE_PTR(altnames
);
574 *ret_iftype
= iftype
;
578 *ret_kind
= TAKE_PTR(kind
);
581 if (ret_permanent_hw_addr
)
582 *ret_permanent_hw_addr
= perm_addr
;
586 int rtnl_log_parse_error(int r
) {
587 return log_error_errno(r
, "Failed to parse netlink message: %m");
590 int rtnl_log_create_error(int r
) {
591 return log_error_errno(r
, "Failed to create netlink message: %m");
594 void rtattr_append_attribute_internal(struct rtattr
*rta
, unsigned short type
, const void *data
, size_t data_length
) {
595 size_t padding_length
;
599 assert(!data
|| data_length
> 0);
601 /* fill in the attribute */
602 rta
->rta_type
= type
;
603 rta
->rta_len
= RTA_LENGTH(data_length
);
605 /* we don't deal with the case where the user lies about the type
606 * and gives us too little data (so don't do that)
608 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
611 /* if no data was passed, make sure we still initialize the padding
612 note that we can have data_length > 0 (used by some containers) */
613 padding
= RTA_DATA(rta
);
615 /* make sure also the padding at the end of the message is initialized */
616 padding_length
= (uint8_t *) rta
+ RTA_SPACE(data_length
) - padding
;
617 memzero(padding
, padding_length
);
620 int rtattr_append_attribute(struct rtattr
**rta
, unsigned short type
, const void *data
, size_t data_length
) {
621 struct rtattr
*new_rta
, *sub_rta
;
622 size_t message_length
;
625 assert(!data
|| data_length
> 0);
627 /* get the new message size (with padding at the end) */
628 message_length
= RTA_ALIGN(rta
? (*rta
)->rta_len
: 0) + RTA_SPACE(data_length
);
630 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
631 if (message_length
> MIN(page_size(), 8192UL))
634 /* realloc to fit the new attribute */
635 new_rta
= realloc(*rta
, message_length
);
640 /* get pointer to the attribute we are about to add */
641 sub_rta
= (struct rtattr
*) ((uint8_t *) *rta
+ RTA_ALIGN((*rta
)->rta_len
));
643 rtattr_append_attribute_internal(sub_rta
, type
, data
, data_length
);
646 (*rta
)->rta_len
= message_length
;
651 bool netlink_pid_changed(sd_netlink
*nl
) {
652 /* We don't support people creating an nl connection and
653 * keeping it around over a fork(). Let's complain. */
654 return ASSERT_PTR(nl
)->original_pid
!= getpid_cached();
657 static int socket_open(int family
) {
660 fd
= socket(AF_NETLINK
, SOCK_RAW
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, family
);
664 return fd_move_above_stdio(fd
);
667 int netlink_open_family(sd_netlink
**ret
, int family
) {
668 _cleanup_close_
int fd
= -EBADF
;
671 fd
= socket_open(family
);
675 r
= sd_netlink_open_fd(ret
, fd
);
683 static bool serial_used(sd_netlink
*nl
, uint32_t serial
) {
687 hashmap_contains(nl
->reply_callbacks
, UINT32_TO_PTR(serial
)) ||
688 hashmap_contains(nl
->rqueue_by_serial
, UINT32_TO_PTR(serial
)) ||
689 hashmap_contains(nl
->rqueue_partial_by_serial
, UINT32_TO_PTR(serial
));
692 void netlink_seal_message(sd_netlink
*nl
, sd_netlink_message
*m
) {
696 assert(!netlink_pid_changed(nl
));
700 /* Avoid collisions with outstanding requests */
704 /* Don't use seq == 0, as that is used for broadcasts, so we would get confused by replies to
706 nl
->serial
= nl
->serial
== UINT32_MAX
? 1 : nl
->serial
+ 1;
708 } while (serial_used(nl
, picked
));
710 m
->hdr
->nlmsg_seq
= picked
;
714 static int socket_writev_message(sd_netlink
*nl
, sd_netlink_message
**m
, size_t msgcount
) {
715 _cleanup_free_
struct iovec
*iovs
= NULL
;
720 assert(msgcount
> 0);
722 iovs
= new(struct iovec
, msgcount
);
726 for (size_t i
= 0; i
< msgcount
; i
++) {
728 assert(m
[i
]->hdr
->nlmsg_len
> 0);
730 iovs
[i
] = IOVEC_MAKE(m
[i
]->hdr
, m
[i
]->hdr
->nlmsg_len
);
733 k
= writev(nl
->fd
, iovs
, msgcount
);
740 int sd_netlink_sendv(
742 sd_netlink_message
**messages
,
744 uint32_t **ret_serial
) {
746 _cleanup_free_
uint32_t *serials
= NULL
;
749 assert_return(nl
, -EINVAL
);
750 assert_return(!netlink_pid_changed(nl
), -ECHILD
);
751 assert_return(messages
, -EINVAL
);
752 assert_return(msgcount
> 0, -EINVAL
);
755 serials
= new(uint32_t, msgcount
);
760 for (size_t i
= 0; i
< msgcount
; i
++) {
761 assert_return(!messages
[i
]->sealed
, -EPERM
);
763 netlink_seal_message(nl
, messages
[i
]);
765 serials
[i
] = message_get_serial(messages
[i
]);
768 r
= socket_writev_message(nl
, messages
, msgcount
);
773 *ret_serial
= TAKE_PTR(serials
);