1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "sd-netlink.h"
5 #include "format-util.h"
6 #include "memory-util.h"
7 #include "netlink-internal.h"
8 #include "netlink-util.h"
11 int rtnl_set_link_name(sd_netlink
**rtnl
, int ifindex
, const char *name
) {
12 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
13 _cleanup_strv_free_
char **alternative_names
= NULL
;
14 char old_name
[IF_NAMESIZE
+ 1] = {};
21 if (!ifname_valid(name
))
24 r
= rtnl_get_link_alternative_names(rtnl
, ifindex
, &alternative_names
);
26 log_debug_errno(r
, "Failed to get alternative names on network interface %i, ignoring: %m",
29 if (strv_contains(alternative_names
, name
)) {
30 r
= rtnl_delete_link_alternative_names(rtnl
, ifindex
, STRV_MAKE(name
));
32 return log_debug_errno(r
, "Failed to remove '%s' from alternative names on network interface %i: %m",
35 format_ifname(ifindex
, old_name
);
38 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_SETLINK
, ifindex
);
42 r
= sd_netlink_message_append_string(message
, IFLA_IFNAME
, name
);
46 r
= sd_netlink_call(*rtnl
, message
, 0, NULL
);
50 if (!isempty(old_name
)) {
51 r
= rtnl_set_link_alternative_names(rtnl
, ifindex
, STRV_MAKE(old_name
));
53 log_debug_errno(r
, "Failed to set '%s' as an alternative name on network interface %i, ignoring: %m",
60 int rtnl_set_link_properties(sd_netlink
**rtnl
, int ifindex
, const char *alias
,
61 const struct ether_addr
*mac
, uint32_t mtu
) {
62 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
68 if (!alias
&& !mac
&& mtu
== 0)
72 r
= sd_netlink_open(rtnl
);
77 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_SETLINK
, ifindex
);
82 r
= sd_netlink_message_append_string(message
, IFLA_IFALIAS
, alias
);
88 r
= sd_netlink_message_append_ether_addr(message
, IFLA_ADDRESS
, mac
);
94 r
= sd_netlink_message_append_u32(message
, IFLA_MTU
, mtu
);
99 r
= sd_netlink_call(*rtnl
, message
, 0, NULL
);
106 int rtnl_get_link_alternative_names(sd_netlink
**rtnl
, int ifindex
, char ***ret
) {
107 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
, *reply
= NULL
;
108 _cleanup_strv_free_
char **names
= NULL
;
116 r
= sd_netlink_open(rtnl
);
121 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_GETLINK
, ifindex
);
125 r
= sd_netlink_call(*rtnl
, message
, 0, &reply
);
129 r
= sd_netlink_message_read_strv(reply
, IFLA_PROP_LIST
, IFLA_ALT_IFNAME
, &names
);
130 if (r
< 0 && r
!= -ENODATA
)
133 *ret
= TAKE_PTR(names
);
138 static int rtnl_update_link_alternative_names(sd_netlink
**rtnl
, uint16_t nlmsg_type
, int ifindex
, char * const *alternative_names
) {
139 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
144 assert(IN_SET(nlmsg_type
, RTM_NEWLINKPROP
, RTM_DELLINKPROP
));
146 if (strv_isempty(alternative_names
))
150 r
= sd_netlink_open(rtnl
);
155 r
= sd_rtnl_message_new_link(*rtnl
, &message
, nlmsg_type
, ifindex
);
159 r
= sd_netlink_message_open_container(message
, IFLA_PROP_LIST
);
163 r
= sd_netlink_message_append_strv(message
, IFLA_ALT_IFNAME
, alternative_names
);
167 r
= sd_netlink_message_close_container(message
);
171 r
= sd_netlink_call(*rtnl
, message
, 0, NULL
);
178 int rtnl_set_link_alternative_names(sd_netlink
**rtnl
, int ifindex
, char * const *alternative_names
) {
179 return rtnl_update_link_alternative_names(rtnl
, RTM_NEWLINKPROP
, ifindex
, alternative_names
);
182 int rtnl_delete_link_alternative_names(sd_netlink
**rtnl
, int ifindex
, char * const *alternative_names
) {
183 return rtnl_update_link_alternative_names(rtnl
, RTM_DELLINKPROP
, ifindex
, alternative_names
);
186 int rtnl_set_link_alternative_names_by_ifname(sd_netlink
**rtnl
, const char *ifname
, char * const *alternative_names
) {
187 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
;
193 if (strv_isempty(alternative_names
))
197 r
= sd_netlink_open(rtnl
);
202 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_NEWLINKPROP
, 0);
206 r
= sd_netlink_message_append_string(message
, IFLA_IFNAME
, ifname
);
210 r
= sd_netlink_message_open_container(message
, IFLA_PROP_LIST
);
214 r
= sd_netlink_message_append_strv(message
, IFLA_ALT_IFNAME
, alternative_names
);
218 r
= sd_netlink_message_close_container(message
);
222 r
= sd_netlink_call(*rtnl
, message
, 0, NULL
);
229 int rtnl_resolve_link_alternative_name(sd_netlink
**rtnl
, const char *name
) {
230 _cleanup_(sd_netlink_unrefp
) sd_netlink
*our_rtnl
= NULL
;
231 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
, *reply
= NULL
;
239 r
= sd_netlink_open(rtnl
);
244 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_GETLINK
, 0);
248 r
= sd_netlink_message_append_string(message
, IFLA_ALT_IFNAME
, name
);
252 r
= sd_netlink_call(*rtnl
, message
, 0, &reply
);
254 return -ENODEV
; /* The device doesn't exist */
258 r
= sd_rtnl_message_link_get_ifindex(reply
, &ret
);
265 int rtnl_get_link_iftype(sd_netlink
**rtnl
, int ifindex
, unsigned short *ret
) {
266 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*message
= NULL
, *reply
= NULL
;
270 r
= sd_netlink_open(rtnl
);
275 r
= sd_rtnl_message_new_link(*rtnl
, &message
, RTM_GETLINK
, ifindex
);
279 r
= sd_netlink_call(*rtnl
, message
, 0, &reply
);
281 return -ENODEV
; /* The device does not exist */
285 return sd_rtnl_message_link_get_type(reply
, ret
);
288 int rtnl_message_new_synthetic_error(sd_netlink
*rtnl
, int error
, uint32_t serial
, sd_netlink_message
**ret
) {
289 struct nlmsgerr
*err
;
294 r
= message_new(rtnl
, ret
, NLMSG_ERROR
);
298 rtnl_message_seal(*ret
);
299 (*ret
)->hdr
->nlmsg_seq
= serial
;
301 err
= NLMSG_DATA((*ret
)->hdr
);
307 int rtnl_log_parse_error(int r
) {
308 return log_error_errno(r
, "Failed to parse netlink message: %m");
311 int rtnl_log_create_error(int r
) {
312 return log_error_errno(r
, "Failed to create netlink message: %m");
315 void rtattr_append_attribute_internal(struct rtattr
*rta
, unsigned short type
, const void *data
, size_t data_length
) {
316 size_t padding_length
;
320 assert(!data
|| data_length
> 0);
322 /* fill in the attribute */
323 rta
->rta_type
= type
;
324 rta
->rta_len
= RTA_LENGTH(data_length
);
326 /* we don't deal with the case where the user lies about the type
327 * and gives us too little data (so don't do that)
329 padding
= mempcpy(RTA_DATA(rta
), data
, data_length
);
332 /* if no data was passed, make sure we still initialize the padding
333 note that we can have data_length > 0 (used by some containers) */
334 padding
= RTA_DATA(rta
);
336 /* make sure also the padding at the end of the message is initialized */
337 padding_length
= (uint8_t *) rta
+ RTA_SPACE(data_length
) - padding
;
338 memzero(padding
, padding_length
);
341 int rtattr_append_attribute(struct rtattr
**rta
, unsigned short type
, const void *data
, size_t data_length
) {
342 struct rtattr
*new_rta
, *sub_rta
;
343 size_t message_length
;
346 assert(!data
|| data_length
> 0);
348 /* get the new message size (with padding at the end) */
349 message_length
= RTA_ALIGN(rta
? (*rta
)->rta_len
: 0) + RTA_SPACE(data_length
);
351 /* buffer should be smaller than both one page or 8K to be accepted by the kernel */
352 if (message_length
> MIN(page_size(), 8192UL))
355 /* realloc to fit the new attribute */
356 new_rta
= realloc(*rta
, message_length
);
361 /* get pointer to the attribute we are about to add */
362 sub_rta
= (struct rtattr
*) ((uint8_t *) *rta
+ RTA_ALIGN((*rta
)->rta_len
));
364 rtattr_append_attribute_internal(sub_rta
, type
, data
, data_length
);
367 (*rta
)->rta_len
= message_length
;