diff options
author | Thierry Martin <tmartin@haproxy.com> | 2022-09-05 15:02:06 +0200 |
---|---|---|
committer | Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> | 2023-04-12 14:28:43 +0200 |
commit | 2f091b1b49543aade4aad9ec3b35b3665abac3e7 (patch) | |
tree | 9fc428bbdeec30c3870c4f7ea771486aa1668009 /src/nspawn | |
parent | Merge pull request #25608 from poettering/dissect-moar (diff) | |
download | systemd-2f091b1b49543aade4aad9ec3b35b3665abac3e7.tar.xz systemd-2f091b1b49543aade4aad9ec3b35b3665abac3e7.zip |
nspawn: container network interface naming
systemd-nspawn now optionally supports colon-separated pair of
host interface name and container interface name for --network-macvlan, --network-ipvlan and --network-interface options.
Also supported in .nspawn configuration files (i.e Interface=, MACVLAN=, IPVLAN= parameters).
man page changed for ntwk interface naming
Diffstat (limited to 'src/nspawn')
-rw-r--r-- | src/nspawn/nspawn-gperf.gperf | 6 | ||||
-rw-r--r-- | src/nspawn/nspawn-network.c | 116 | ||||
-rw-r--r-- | src/nspawn/nspawn-network.h | 12 | ||||
-rw-r--r-- | src/nspawn/nspawn-settings.c | 63 | ||||
-rw-r--r-- | src/nspawn/nspawn-settings.h | 3 | ||||
-rw-r--r-- | src/nspawn/nspawn.c | 60 |
6 files changed, 194 insertions, 66 deletions
diff --git a/src/nspawn/nspawn-gperf.gperf b/src/nspawn/nspawn-gperf.gperf index a93b8c38c9..9e1210f876 100644 --- a/src/nspawn/nspawn-gperf.gperf +++ b/src/nspawn/nspawn-gperf.gperf @@ -72,9 +72,9 @@ Files.PrivateUsersChown, config_parse_userns_chown, 0, Files.PrivateUsersOwnership, config_parse_userns_ownership, 0, offsetof(Settings, userns_ownership) Files.BindUser, config_parse_bind_user, 0, offsetof(Settings, bind_user) Network.Private, config_parse_tristate, 0, offsetof(Settings, private_network) -Network.Interface, config_parse_strv, 0, offsetof(Settings, network_interfaces) -Network.MACVLAN, config_parse_strv, 0, offsetof(Settings, network_macvlan) -Network.IPVLAN, config_parse_strv, 0, offsetof(Settings, network_ipvlan) +Network.Interface, config_parse_network_iface_pair, 0, offsetof(Settings, network_interfaces) +Network.MACVLAN, config_parse_macvlan_iface_pair, 0, offsetof(Settings, network_macvlan) +Network.IPVLAN, config_parse_ipvlan_iface_pair, 0, offsetof(Settings, network_ipvlan) Network.VirtualEthernet, config_parse_tristate, 0, offsetof(Settings, network_veth) Network.VirtualEthernetExtra, config_parse_veth_extra, 0, 0 Network.Bridge, config_parse_ifname, 0, offsetof(Settings, network_bridge) diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 143156484b..d898f0d4c9 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -463,7 +463,7 @@ int remove_bridge(const char *bridge_name) { return remove_one_link(rtnl, bridge_name); } -int test_network_interface_initialized(const char *name) { +static int test_network_interface_initialized(const char *name) { _cleanup_(sd_device_unrefp) sd_device *d = NULL; int r; @@ -491,18 +491,28 @@ int test_network_interface_initialized(const char *name) { return 0; } -int move_network_interfaces(int netns_fd, char **ifaces) { +int test_network_interfaces_initialized(char **iface_pairs) { + int r; + STRV_FOREACH_PAIR(a, b, iface_pairs) { + r = test_network_interface_initialized(*a); + if (r < 0) + return r; + } + return 0; +} + +int move_network_interfaces(int netns_fd, char **iface_pairs) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int r; - if (strv_isempty(ifaces)) + if (strv_isempty(iface_pairs)) return 0; r = sd_netlink_open(&rtnl); if (r < 0) return log_error_errno(r, "Failed to connect to netlink: %m"); - STRV_FOREACH(i, ifaces) { + STRV_FOREACH_PAIR(i, b, iface_pairs) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int ifi; @@ -518,6 +528,12 @@ int move_network_interfaces(int netns_fd, char **ifaces) { if (r < 0) return log_error_errno(r, "Failed to append namespace fd to netlink message: %m"); + if (!streq(*b, *i)) { + r = sd_netlink_message_append_string(m, IFLA_IFNAME, *b); + if (r < 0) + return log_error_errno(r, "Failed to add netlink interface name: %m"); + } + r = sd_netlink_call(rtnl, m, 0, NULL); if (r < 0) return log_error_errno(r, "Failed to move interface %s to namespace: %m", *i); @@ -526,23 +542,23 @@ int move_network_interfaces(int netns_fd, char **ifaces) { return 0; } -int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) { +int setup_macvlan(const char *machine_name, pid_t pid, char **iface_pairs) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; unsigned idx = 0; int r; - if (strv_isempty(ifaces)) + if (strv_isempty(iface_pairs)) return 0; r = sd_netlink_open(&rtnl); if (r < 0) return log_error_errno(r, "Failed to connect to netlink: %m"); - STRV_FOREACH(i, ifaces) { + STRV_FOREACH_PAIR(i, b, iface_pairs) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - _cleanup_free_ char *n = NULL, *a = NULL; + _cleanup_free_ char *n = NULL; + int shortened, ifi; struct ether_addr mac; - int ifi; ifi = rtnl_resolve_interface_or_warn(&rtnl, *i); if (ifi < 0) @@ -560,16 +576,11 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) { if (r < 0) return log_error_errno(r, "Failed to add netlink interface index: %m"); - n = strjoin("mv-", *i); + n = strdup(*b); if (!n) return log_oom(); - r = shorten_ifname(n); - if (r > 0) { - a = strjoin("mv-", *i); - if (!a) - return log_oom(); - } + shortened = shorten_ifname(n); r = sd_netlink_message_append_string(m, IFLA_IFNAME, n); if (r < 0) @@ -607,27 +618,28 @@ int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces) { if (r < 0) return log_error_errno(r, "Failed to add new macvlan interfaces: %m"); - (void) set_alternative_ifname(rtnl, n, a); + if (shortened > 0) + (void) set_alternative_ifname(rtnl, n, *b); } return 0; } -int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) { +int setup_ipvlan(const char *machine_name, pid_t pid, char **iface_pairs) { _cleanup_(sd_netlink_unrefp) sd_netlink *rtnl = NULL; int r; - if (strv_isempty(ifaces)) + if (strv_isempty(iface_pairs)) return 0; r = sd_netlink_open(&rtnl); if (r < 0) return log_error_errno(r, "Failed to connect to netlink: %m"); - STRV_FOREACH(i, ifaces) { + STRV_FOREACH_PAIR(i, b, iface_pairs) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; - _cleanup_free_ char *n = NULL, *a = NULL; - int ifi; + _cleanup_free_ char *n = NULL; + int shortened, ifi ; ifi = rtnl_resolve_interface_or_warn(&rtnl, *i); if (ifi < 0) @@ -641,16 +653,11 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) { if (r < 0) return log_error_errno(r, "Failed to add netlink interface index: %m"); - n = strjoin("iv-", *i); + n = strdup(*b); if (!n) return log_oom(); - r = shorten_ifname(n); - if (r > 0) { - a = strjoin("iv-", *i); - if (!a) - return log_oom(); - } + shortened = shorten_ifname(n); r = sd_netlink_message_append_string(m, IFLA_IFNAME, n); if (r < 0) @@ -684,7 +691,8 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) { if (r < 0) return log_error_errno(r, "Failed to add new ipvlan interfaces: %m"); - (void) set_alternative_ifname(rtnl, n, a); + if (shortened > 0) + (void) set_alternative_ifname(rtnl, n, *b); } return 0; @@ -742,3 +750,51 @@ int remove_veth_links(const char *primary, char **pairs) { return 0; } + +static int network_iface_pair_parse(const char* iftype, char ***l, const char *p, const char* ifprefix) { + _cleanup_free_ char *a = NULL, *b = NULL; + int r; + + r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return log_error_errno(r, "Failed to extract first word in %s parameter: %m", iftype); + if (r == 0) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "Short read while reading %s parameter: %m", iftype); + if (!ifname_valid(a)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "%s, interface name not valid: %s", iftype, a); + + if (isempty(p)) { + if (ifprefix) + b = strjoin(ifprefix, a); + else + b = strdup(a); + } else + b = strdup(p); + if (!b) + return log_oom(); + + if (!ifname_valid(b)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "%s, interface name not valid: %s", iftype, b); + + r = strv_push_pair(l, a, b); + if (r < 0) + return log_oom(); + + a = b = NULL; + return 0; +} + +int interface_pair_parse(char ***l, const char *p) { + return network_iface_pair_parse("Network interface", l, p, NULL); +} + +int macvlan_pair_parse(char ***l, const char *p) { + return network_iface_pair_parse("MACVLAN network interface", l, p, "mv-"); +} + +int ipvlan_pair_parse(char ***l, const char *p) { + return network_iface_pair_parse("IPVLAN network interface", l, p, "iv-"); +} diff --git a/src/nspawn/nspawn-network.h b/src/nspawn/nspawn-network.h index 5c2d983418..355d813c96 100644 --- a/src/nspawn/nspawn-network.h +++ b/src/nspawn/nspawn-network.h @@ -5,7 +5,7 @@ #include <stdbool.h> #include <sys/types.h> -int test_network_interface_initialized(const char *name); +int test_network_interfaces_initialized(char **iface_pairs); int setup_veth(const char *machine_name, pid_t pid, char iface_name[IFNAMSIZ], bool bridge); int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs); @@ -13,11 +13,15 @@ int setup_veth_extra(const char *machine_name, pid_t pid, char **pairs); int setup_bridge(const char *veth_name, const char *bridge_name, bool create); int remove_bridge(const char *bridge_name); -int setup_macvlan(const char *machine_name, pid_t pid, char **ifaces); -int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces); +int setup_macvlan(const char *machine_name, pid_t pid, char **iface_pairs); +int setup_ipvlan(const char *machine_name, pid_t pid, char **iface_pairs); -int move_network_interfaces(int netns_fd, char **ifaces); +int move_network_interfaces(int netns_fd, char **iface_pairs); int veth_extra_parse(char ***l, const char *p); int remove_veth_links(const char *primary, char **pairs); + +int interface_pair_parse(char ***l, const char *p); +int macvlan_pair_parse(char ***l, const char *p); +int ipvlan_pair_parse(char ***l, const char *p); diff --git a/src/nspawn/nspawn-settings.c b/src/nspawn/nspawn-settings.c index 05bde1c756..7500eabd18 100644 --- a/src/nspawn/nspawn-settings.c +++ b/src/nspawn/nspawn-settings.c @@ -469,6 +469,69 @@ int config_parse_veth_extra( return 0; } +int config_parse_network_iface_pair( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char*** l = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + + return interface_pair_parse(l, rvalue); +} + +int config_parse_macvlan_iface_pair( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char*** l = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + + return macvlan_pair_parse(l, rvalue); +} + +int config_parse_ipvlan_iface_pair( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + char*** l = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + + return ipvlan_pair_parse(l, rvalue); +} + int config_parse_network_zone( const char *unit, const char *filename, diff --git a/src/nspawn/nspawn-settings.h b/src/nspawn/nspawn-settings.h index 004b663e9e..0a3d975364 100644 --- a/src/nspawn/nspawn-settings.h +++ b/src/nspawn/nspawn-settings.h @@ -259,6 +259,9 @@ CONFIG_PARSER_PROTOTYPE(config_parse_tmpfs); CONFIG_PARSER_PROTOTYPE(config_parse_overlay); CONFIG_PARSER_PROTOTYPE(config_parse_inaccessible); CONFIG_PARSER_PROTOTYPE(config_parse_veth_extra); +CONFIG_PARSER_PROTOTYPE(config_parse_network_iface_pair); +CONFIG_PARSER_PROTOTYPE(config_parse_macvlan_iface_pair); +CONFIG_PARSER_PROTOTYPE(config_parse_ipvlan_iface_pair); CONFIG_PARSER_PROTOTYPE(config_parse_network_zone); CONFIG_PARSER_PROTOTYPE(config_parse_boot); CONFIG_PARSER_PROTOTYPE(config_parse_pid2); diff --git a/src/nspawn/nspawn.c b/src/nspawn/nspawn.c index 3882676216..ff6a437573 100644 --- a/src/nspawn/nspawn.c +++ b/src/nspawn/nspawn.c @@ -377,13 +377,13 @@ static int help(void) { " --private-users-ownership=auto\n\n" "%3$sNetworking:%4$s\n" " --private-network Disable network in container\n" - " --network-interface=INTERFACE\n" + " --network-interface=HOSTIF[:CONTAINERIF]\n" " Assign an existing network interface to the\n" " container\n" - " --network-macvlan=INTERFACE\n" + " --network-macvlan=HOSTIF[:CONTAINERIF]\n" " Create a macvlan network interface based on an\n" " existing network interface to the container\n" - " --network-ipvlan=INTERFACE\n" + " --network-ipvlan=HOSTIF[:CONTAINERIF]\n" " Create an ipvlan network interface based on an\n" " existing network interface to the container\n" " -n --network-veth Add a virtual Ethernet connection between host\n" @@ -924,51 +924,28 @@ static int parse_argv(int argc, char *argv[]) { break; case ARG_NETWORK_INTERFACE: - if (!ifname_valid(optarg)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Network interface name not valid: %s", optarg); - - r = test_network_interface_initialized(optarg); + r = interface_pair_parse(&arg_network_interfaces, optarg); if (r < 0) return r; - if (strv_extend(&arg_network_interfaces, optarg) < 0) - return log_oom(); - arg_private_network = true; arg_settings_mask |= SETTING_NETWORK; break; case ARG_NETWORK_MACVLAN: - - if (!ifname_valid(optarg)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "MACVLAN network interface name not valid: %s", optarg); - - r = test_network_interface_initialized(optarg); + r = macvlan_pair_parse(&arg_network_macvlan, optarg); if (r < 0) return r; - if (strv_extend(&arg_network_macvlan, optarg) < 0) - return log_oom(); - arg_private_network = true; arg_settings_mask |= SETTING_NETWORK; break; case ARG_NETWORK_IPVLAN: - - if (!ifname_valid(optarg)) - return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "IPVLAN network interface name not valid: %s", optarg); - - r = test_network_interface_initialized(optarg); + r = ipvlan_pair_parse(&arg_network_ipvlan, optarg); if (r < 0) return r; - if (strv_extend(&arg_network_ipvlan, optarg) < 0) - return log_oom(); - _fallthrough_; case ARG_PRIVATE_NETWORK: arg_private_network = true; @@ -1894,6 +1871,23 @@ static int verify_arguments(void) { return 0; } +static int verify_network_interfaces_initialized(void) { + int r; + r = test_network_interfaces_initialized(arg_network_interfaces); + if (r < 0) + return r; + + r = test_network_interfaces_initialized(arg_network_macvlan); + if (r < 0) + return r; + + r = test_network_interfaces_initialized(arg_network_ipvlan); + if (r < 0) + return r; + + return 0; +} + int userns_lchown(const char *p, uid_t uid, gid_t gid) { assert(p); @@ -5288,6 +5282,10 @@ static int run_container( _exit(EXIT_FAILURE); } + /* Reverse network interfaces pair list so that interfaces get their initial name back. + * This is about ensuring interfaces get their old name back when being moved back. */ + arg_network_interfaces = strv_reverse(arg_network_interfaces); + r = move_network_interfaces(parent_netns_fd, arg_network_interfaces); if (r < 0) log_error_errno(r, "Failed to move network interfaces back to parent network namespace: %m"); @@ -5506,6 +5504,10 @@ static int run(int argc, char *argv[]) { if (r < 0) goto finish; + r = verify_network_interfaces_initialized(); + if (r < 0) + goto finish; + /* Reapply environment settings. */ (void) detect_unified_cgroup_hierarchy_from_environment(); |