1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
5 #include <linux/veth.h>
10 #include "sd-netlink.h"
12 #include "alloc-util.h"
13 #include "ether-addr-util.h"
14 #include "hexdecoct.h"
15 #include "lock-util.h"
16 #include "missing_network.h"
17 #include "netif-naming-scheme.h"
18 #include "netlink-util.h"
19 #include "nspawn-network.h"
20 #include "parse-util.h"
21 #include "siphash24.h"
22 #include "socket-netlink.h"
23 #include "socket-util.h"
24 #include "stat-util.h"
25 #include "string-util.h"
27 #include "udev-util.h"
29 #define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1)
30 #define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2)
31 #define VETH_EXTRA_HOST_HASH_KEY SD_ID128_MAKE(48,c7,f6,b7,ea,9d,4c,9e,b7,28,d4,de,91,d5,bf,66)
32 #define VETH_EXTRA_CONTAINER_HASH_KEY SD_ID128_MAKE(af,50,17,61,ce,f9,4d,35,84,0d,2b,20,54,be,ce,59)
33 #define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f)
34 #define SHORTEN_IFNAME_HASH_KEY SD_ID128_MAKE(e1,90,a4,04,a8,ef,4b,51,8c,cc,c3,3a,9f,11,fc,a2)
36 static int remove_one_link(sd_netlink
*rtnl
, const char *name
) {
37 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
43 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_DELLINK
, 0);
45 return log_error_errno(r
, "Failed to allocate netlink message: %m");
47 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, name
);
49 return log_error_errno(r
, "Failed to add netlink interface name: %m");
51 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
52 if (r
== -ENODEV
) /* Already gone */
55 return log_error_errno(r
, "Failed to remove interface %s: %m", name
);
60 static int generate_mac(
61 const char *machine_name
,
62 struct ether_addr
*mac
,
71 l
= strlen(machine_name
);
72 sz
= sizeof(sd_id128_t
) + l
;
76 v
= newa(uint8_t, sz
);
78 /* fetch some persistent data unique to the host */
79 r
= sd_id128_get_machine((sd_id128_t
*) v
);
83 /* combine with some data unique (on this host) to this
84 * container instance */
85 i
= mempcpy(v
+ sizeof(sd_id128_t
), machine_name
, l
);
88 memcpy(i
, &idx
, sizeof(idx
));
91 /* Let's hash the host machine ID plus the container name. We
92 * use a fixed, but originally randomly created hash key here. */
93 result
= htole64(siphash24(v
, sz
, hash_key
.bytes
));
95 assert_cc(ETH_ALEN
<= sizeof(result
));
96 memcpy(mac
->ether_addr_octet
, &result
, ETH_ALEN
);
98 /* see eth_random_addr in the kernel */
99 mac
->ether_addr_octet
[0] &= 0xfe; /* clear multicast bit */
100 mac
->ether_addr_octet
[0] |= 0x02; /* set local assignment bit (IEEE802) */
105 static int set_alternative_ifname(sd_netlink
*rtnl
, const char *ifname
, const char *altifname
) {
114 if (strlen(altifname
) >= ALTIFNAMSIZ
)
115 return log_warning_errno(SYNTHETIC_ERRNO(ERANGE
),
116 "Alternative interface name '%s' for '%s' is too long, ignoring",
119 r
= rtnl_set_link_alternative_names_by_ifname(&rtnl
, ifname
, STRV_MAKE(altifname
));
121 return log_warning_errno(r
,
122 "Failed to set alternative interface name '%s' to '%s', ignoring: %m",
131 const char *ifname_host
,
132 const char *altifname_host
,
133 const struct ether_addr
*mac_host
,
134 const char *ifname_container
,
135 const struct ether_addr
*mac_container
) {
137 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
143 assert(ifname_container
);
144 assert(mac_container
);
146 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
148 return log_error_errno(r
, "Failed to allocate netlink message: %m");
150 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, ifname_host
);
152 return log_error_errno(r
, "Failed to add netlink interface name: %m");
154 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, mac_host
);
156 return log_error_errno(r
, "Failed to add netlink MAC address: %m");
158 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
160 return log_error_errno(r
, "Failed to open netlink container: %m");
162 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "veth");
164 return log_error_errno(r
, "Failed to open netlink container: %m");
166 r
= sd_netlink_message_open_container(m
, VETH_INFO_PEER
);
168 return log_error_errno(r
, "Failed to open netlink container: %m");
170 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, ifname_container
);
172 return log_error_errno(r
, "Failed to add netlink interface name: %m");
174 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, mac_container
);
176 return log_error_errno(r
, "Failed to add netlink MAC address: %m");
178 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
180 return log_error_errno(r
, "Failed to add netlink namespace field: %m");
182 r
= sd_netlink_message_close_container(m
);
184 return log_error_errno(r
, "Failed to close netlink container: %m");
186 r
= sd_netlink_message_close_container(m
);
188 return log_error_errno(r
, "Failed to close netlink container: %m");
190 r
= sd_netlink_message_close_container(m
);
192 return log_error_errno(r
, "Failed to close netlink container: %m");
194 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
196 return log_error_errno(r
, "Failed to add new veth interfaces (%s:%s): %m", ifname_host
, ifname_container
);
198 (void) set_alternative_ifname(rtnl
, ifname_host
, altifname_host
);
203 static int shorten_ifname(char *ifname
) {
204 char new_ifname
[IFNAMSIZ
];
208 if (strlen(ifname
) < IFNAMSIZ
) /* Name is short enough */
211 if (naming_scheme_has(NAMING_NSPAWN_LONG_HASH
)) {
214 /* Calculate 64-bit hash value */
215 h
= siphash24(ifname
, strlen(ifname
), SHORTEN_IFNAME_HASH_KEY
.bytes
);
217 /* Set the final four bytes (i.e. 32-bit) to the lower 24bit of the hash, encoded in url-safe base64 */
218 memcpy(new_ifname
, ifname
, IFNAMSIZ
- 5);
219 new_ifname
[IFNAMSIZ
- 5] = urlsafe_base64char(h
>> 18);
220 new_ifname
[IFNAMSIZ
- 4] = urlsafe_base64char(h
>> 12);
221 new_ifname
[IFNAMSIZ
- 3] = urlsafe_base64char(h
>> 6);
222 new_ifname
[IFNAMSIZ
- 2] = urlsafe_base64char(h
);
224 /* On old nspawn versions we just truncated the name, provide compatibility */
225 memcpy(new_ifname
, ifname
, IFNAMSIZ
-1);
227 new_ifname
[IFNAMSIZ
- 1] = 0;
229 /* Log the incident to make it more discoverable */
230 log_warning("Network interface name '%s' has been changed to '%s' to fit length constraints.", ifname
, new_ifname
);
232 strcpy(ifname
, new_ifname
);
236 int setup_veth(const char *machine_name
,
238 char iface_name
[IFNAMSIZ
],
240 const struct ether_addr
*provided_mac
) {
242 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
243 struct ether_addr mac_host
, mac_container
;
248 assert(machine_name
);
252 /* Use two different interface name prefixes depending whether
253 * we are in bridge mode or not. */
254 n
= strjoina(bridge
? "vb-" : "ve-", machine_name
);
255 r
= shorten_ifname(n
);
257 a
= strjoina(bridge
? "vb-" : "ve-", machine_name
);
259 if (ether_addr_is_null(provided_mac
)){
260 r
= generate_mac(machine_name
, &mac_container
, CONTAINER_HASH_KEY
, 0);
262 return log_error_errno(r
, "Failed to generate predictable MAC address for container side: %m");
264 mac_container
= *provided_mac
;
266 r
= generate_mac(machine_name
, &mac_host
, HOST_HASH_KEY
, 0);
268 return log_error_errno(r
, "Failed to generate predictable MAC address for host side: %m");
270 r
= sd_netlink_open(&rtnl
);
272 return log_error_errno(r
, "Failed to connect to netlink: %m");
274 r
= add_veth(rtnl
, pid
, n
, a
, &mac_host
, "host0", &mac_container
);
278 u
= if_nametoindex(n
); /* We don't need to use rtnl_resolve_ifname() here because the
279 * name we assigned is always the main name. */
281 return log_error_errno(errno
, "Failed to resolve interface %s: %m", n
);
283 strcpy(iface_name
, n
);
287 int setup_veth_extra(
288 const char *machine_name
,
292 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
296 assert(machine_name
);
299 if (strv_isempty(pairs
))
302 r
= sd_netlink_open(&rtnl
);
304 return log_error_errno(r
, "Failed to connect to netlink: %m");
306 STRV_FOREACH_PAIR(a
, b
, pairs
) {
307 struct ether_addr mac_host
, mac_container
;
309 r
= generate_mac(machine_name
, &mac_container
, VETH_EXTRA_CONTAINER_HASH_KEY
, idx
);
311 return log_error_errno(r
, "Failed to generate predictable MAC address for container side of extra veth link: %m");
313 r
= generate_mac(machine_name
, &mac_host
, VETH_EXTRA_HOST_HASH_KEY
, idx
);
315 return log_error_errno(r
, "Failed to generate predictable MAC address for host side of extra veth link: %m");
317 r
= add_veth(rtnl
, pid
, *a
, NULL
, &mac_host
, *b
, &mac_container
);
327 static int join_bridge(sd_netlink
*rtnl
, const char *veth_name
, const char *bridge_name
) {
328 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
335 bridge_ifi
= rtnl_resolve_interface(&rtnl
, bridge_name
);
339 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_SETLINK
, 0);
343 r
= sd_rtnl_message_link_set_flags(m
, IFF_UP
, IFF_UP
);
347 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, veth_name
);
351 r
= sd_netlink_message_append_u32(m
, IFLA_MASTER
, bridge_ifi
);
355 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
362 static int create_bridge(sd_netlink
*rtnl
, const char *bridge_name
) {
363 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
366 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
370 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, bridge_name
);
374 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
378 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "bridge");
382 r
= sd_netlink_message_close_container(m
);
386 r
= sd_netlink_message_close_container(m
);
390 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
397 int setup_bridge(const char *veth_name
, const char *bridge_name
, bool create
) {
398 _cleanup_(release_lock_file
) LockFile bridge_lock
= LOCK_FILE_INIT
;
399 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
406 r
= sd_netlink_open(&rtnl
);
408 return log_error_errno(r
, "Failed to connect to netlink: %m");
411 /* We take a system-wide lock here, so that we can safely check whether there's still a member in the
412 * bridge before removing it, without risking interference from other nspawn instances. */
414 r
= make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX
, &bridge_lock
);
416 return log_error_errno(r
, "Failed to take network zone lock: %m");
420 bridge_ifi
= join_bridge(rtnl
, veth_name
, bridge_name
);
423 if (bridge_ifi
!= -ENODEV
|| !create
|| n
> 10)
424 return log_error_errno(bridge_ifi
, "Failed to add interface %s to bridge %s: %m", veth_name
, bridge_name
);
426 /* Count attempts, so that we don't enter an endless loop here. */
429 /* The bridge doesn't exist yet. Let's create it */
430 r
= create_bridge(rtnl
, bridge_name
);
432 return log_error_errno(r
, "Failed to create bridge interface %s: %m", bridge_name
);
434 /* Try again, now that the bridge exists */
438 int remove_bridge(const char *bridge_name
) {
439 _cleanup_(release_lock_file
) LockFile bridge_lock
= LOCK_FILE_INIT
;
440 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
444 /* Removes the specified bridge, but only if it is currently empty */
446 if (isempty(bridge_name
))
449 r
= make_lock_file("/run/systemd/nspawn-network-zone", LOCK_EX
, &bridge_lock
);
451 return log_error_errno(r
, "Failed to take network zone lock: %m");
453 path
= strjoina("/sys/class/net/", bridge_name
, "/brif");
455 r
= dir_is_empty(path
, /* ignore_hidden_or_backup= */ false);
456 if (r
== -ENOENT
) /* Already gone? */
459 return log_error_errno(r
, "Can't detect if bridge %s is empty: %m", bridge_name
);
460 if (r
== 0) /* Still populated, leave it around */
463 r
= sd_netlink_open(&rtnl
);
465 return log_error_errno(r
, "Failed to connect to netlink: %m");
467 return remove_one_link(rtnl
, bridge_name
);
470 static int test_network_interface_initialized(const char *name
) {
471 _cleanup_(sd_device_unrefp
) sd_device
*d
= NULL
;
474 if (!udev_available())
477 /* udev should be around. */
479 r
= sd_device_new_from_ifname(&d
, name
);
481 return log_error_errno(r
, "Failed to get device %s: %m", name
);
483 r
= sd_device_get_is_initialized(d
);
485 return log_error_errno(r
, "Failed to determine whether interface %s is initialized: %m", name
);
487 return log_error_errno(SYNTHETIC_ERRNO(EBUSY
), "Network interface %s is not initialized yet.", name
);
489 r
= device_is_renaming(d
);
491 return log_error_errno(r
, "Failed to determine the interface %s is being renamed: %m", name
);
493 return log_error_errno(SYNTHETIC_ERRNO(EBUSY
), "Interface %s is being renamed.", name
);
498 int test_network_interfaces_initialized(char **iface_pairs
) {
500 STRV_FOREACH_PAIR(a
, b
, iface_pairs
) {
501 r
= test_network_interface_initialized(*a
);
508 int move_network_interfaces(int netns_fd
, char **iface_pairs
) {
509 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
512 if (strv_isempty(iface_pairs
))
515 r
= sd_netlink_open(&rtnl
);
517 return log_error_errno(r
, "Failed to connect to netlink: %m");
519 STRV_FOREACH_PAIR(i
, b
, iface_pairs
) {
520 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
523 ifi
= rtnl_resolve_interface_or_warn(&rtnl
, *i
);
527 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_SETLINK
, ifi
);
529 return log_error_errno(r
, "Failed to allocate netlink message: %m");
531 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_FD
, netns_fd
);
533 return log_error_errno(r
, "Failed to append namespace fd to netlink message: %m");
535 if (!streq(*b
, *i
)) {
536 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, *b
);
538 return log_error_errno(r
, "Failed to add netlink interface name: %m");
541 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
543 return log_error_errno(r
, "Failed to move interface %s to namespace: %m", *i
);
549 int setup_macvlan(const char *machine_name
, pid_t pid
, char **iface_pairs
) {
550 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
554 if (strv_isempty(iface_pairs
))
557 r
= sd_netlink_open(&rtnl
);
559 return log_error_errno(r
, "Failed to connect to netlink: %m");
561 STRV_FOREACH_PAIR(i
, b
, iface_pairs
) {
562 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
563 _cleanup_free_
char *n
= NULL
;
565 struct ether_addr mac
;
567 ifi
= rtnl_resolve_interface_or_warn(&rtnl
, *i
);
571 r
= generate_mac(machine_name
, &mac
, MACVLAN_HASH_KEY
, idx
++);
573 return log_error_errno(r
, "Failed to create MACVLAN MAC address: %m");
575 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
577 return log_error_errno(r
, "Failed to allocate netlink message: %m");
579 r
= sd_netlink_message_append_u32(m
, IFLA_LINK
, ifi
);
581 return log_error_errno(r
, "Failed to add netlink interface index: %m");
587 shortened
= shorten_ifname(n
);
589 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, n
);
591 return log_error_errno(r
, "Failed to add netlink interface name: %m");
593 r
= sd_netlink_message_append_ether_addr(m
, IFLA_ADDRESS
, &mac
);
595 return log_error_errno(r
, "Failed to add netlink MAC address: %m");
597 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
599 return log_error_errno(r
, "Failed to add netlink namespace field: %m");
601 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
603 return log_error_errno(r
, "Failed to open netlink container: %m");
605 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "macvlan");
607 return log_error_errno(r
, "Failed to open netlink container: %m");
609 r
= sd_netlink_message_append_u32(m
, IFLA_MACVLAN_MODE
, MACVLAN_MODE_BRIDGE
);
611 return log_error_errno(r
, "Failed to append macvlan mode: %m");
613 r
= sd_netlink_message_close_container(m
);
615 return log_error_errno(r
, "Failed to close netlink container: %m");
617 r
= sd_netlink_message_close_container(m
);
619 return log_error_errno(r
, "Failed to close netlink container: %m");
621 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
623 return log_error_errno(r
, "Failed to add new macvlan interfaces: %m");
626 (void) set_alternative_ifname(rtnl
, n
, *b
);
632 int setup_ipvlan(const char *machine_name
, pid_t pid
, char **iface_pairs
) {
633 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
636 if (strv_isempty(iface_pairs
))
639 r
= sd_netlink_open(&rtnl
);
641 return log_error_errno(r
, "Failed to connect to netlink: %m");
643 STRV_FOREACH_PAIR(i
, b
, iface_pairs
) {
644 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*m
= NULL
;
645 _cleanup_free_
char *n
= NULL
;
648 ifi
= rtnl_resolve_interface_or_warn(&rtnl
, *i
);
652 r
= sd_rtnl_message_new_link(rtnl
, &m
, RTM_NEWLINK
, 0);
654 return log_error_errno(r
, "Failed to allocate netlink message: %m");
656 r
= sd_netlink_message_append_u32(m
, IFLA_LINK
, ifi
);
658 return log_error_errno(r
, "Failed to add netlink interface index: %m");
664 shortened
= shorten_ifname(n
);
666 r
= sd_netlink_message_append_string(m
, IFLA_IFNAME
, n
);
668 return log_error_errno(r
, "Failed to add netlink interface name: %m");
670 r
= sd_netlink_message_append_u32(m
, IFLA_NET_NS_PID
, pid
);
672 return log_error_errno(r
, "Failed to add netlink namespace field: %m");
674 r
= sd_netlink_message_open_container(m
, IFLA_LINKINFO
);
676 return log_error_errno(r
, "Failed to open netlink container: %m");
678 r
= sd_netlink_message_open_container_union(m
, IFLA_INFO_DATA
, "ipvlan");
680 return log_error_errno(r
, "Failed to open netlink container: %m");
682 r
= sd_netlink_message_append_u16(m
, IFLA_IPVLAN_MODE
, IPVLAN_MODE_L2
);
684 return log_error_errno(r
, "Failed to add ipvlan mode: %m");
686 r
= sd_netlink_message_close_container(m
);
688 return log_error_errno(r
, "Failed to close netlink container: %m");
690 r
= sd_netlink_message_close_container(m
);
692 return log_error_errno(r
, "Failed to close netlink container: %m");
694 r
= sd_netlink_call(rtnl
, m
, 0, NULL
);
696 return log_error_errno(r
, "Failed to add new ipvlan interfaces: %m");
699 (void) set_alternative_ifname(rtnl
, n
, *b
);
705 int veth_extra_parse(char ***l
, const char *p
) {
706 _cleanup_free_
char *a
= NULL
, *b
= NULL
;
709 r
= extract_first_word(&p
, &a
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
712 if (r
== 0 || !ifname_valid(a
))
715 r
= extract_first_word(&p
, &b
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
718 if (r
== 0 || !ifname_valid(b
)) {
719 r
= free_and_strdup(&b
, a
);
727 r
= strv_push_pair(l
, a
, b
);
735 int remove_veth_links(const char *primary
, char **pairs
) {
736 _cleanup_(sd_netlink_unrefp
) sd_netlink
*rtnl
= NULL
;
739 /* In some cases the kernel might pin the veth links between host and container even after the namespace
740 * died. Hence, let's better remove them explicitly too. */
742 if (isempty(primary
) && strv_isempty(pairs
))
745 r
= sd_netlink_open(&rtnl
);
747 return log_error_errno(r
, "Failed to connect to netlink: %m");
749 remove_one_link(rtnl
, primary
);
751 STRV_FOREACH_PAIR(a
, b
, pairs
)
752 remove_one_link(rtnl
, *a
);
757 static int network_iface_pair_parse(const char* iftype
, char ***l
, const char *p
, const char* ifprefix
) {
761 _cleanup_free_
char *word
= NULL
, *a
= NULL
, *b
= NULL
;
762 const char *interface
;
764 r
= extract_first_word(&p
, &word
, NULL
, 0);
766 return log_error_errno(r
, "Failed to parse interface name: %m");
771 r
= extract_first_word(&interface
, &a
, ":", EXTRACT_DONT_COALESCE_SEPARATORS
);
773 return log_error_errno(r
, "Failed to extract first word in %s parameter: %m", iftype
);
775 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
776 "Short read while reading %s parameter: %m", iftype
);
777 if (!ifname_valid(a
))
778 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
779 "%s, interface name not valid: %s", iftype
, a
);
781 /* Here, we only check the validity of the specified second name. If it is not specified,
782 * the copied or prefixed name should be already valid, except for its length. If it is too
783 * long, then it will be shortened later. */
784 if (!isempty(interface
)) {
785 if (!ifname_valid(interface
))
786 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
787 "%s, interface name not valid: %s", iftype
, interface
);
789 b
= strdup(interface
);
791 b
= strjoin(ifprefix
, a
);
797 r
= strv_consume_pair(l
, TAKE_PTR(a
), TAKE_PTR(b
));
805 int interface_pair_parse(char ***l
, const char *p
) {
806 return network_iface_pair_parse("Network interface", l
, p
, NULL
);
809 int macvlan_pair_parse(char ***l
, const char *p
) {
810 return network_iface_pair_parse("MACVLAN network interface", l
, p
, "mv-");
813 int ipvlan_pair_parse(char ***l
, const char *p
) {
814 return network_iface_pair_parse("IPVLAN network interface", l
, p
, "iv-");