diff options
Diffstat (limited to 'src/nspawn/nspawn-network.c')
-rw-r--r-- | src/nspawn/nspawn-network.c | 157 |
1 files changed, 129 insertions, 28 deletions
diff --git a/src/nspawn/nspawn-network.c b/src/nspawn/nspawn-network.c index 29384b60b2..c71552879d 100644 --- a/src/nspawn/nspawn-network.c +++ b/src/nspawn/nspawn-network.c @@ -37,6 +37,8 @@ #define HOST_HASH_KEY SD_ID128_MAKE(1a,37,6f,c7,46,ec,45,0b,ad,a3,d5,31,06,60,5d,b1) #define CONTAINER_HASH_KEY SD_ID128_MAKE(c3,c4,f9,19,b5,57,b2,1c,e6,cf,14,27,03,9c,ee,a2) +#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) +#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) #define MACVLAN_HASH_KEY SD_ID128_MAKE(00,13,6d,bc,66,83,44,81,bb,0c,f9,51,1f,24,a6,6f) static int generate_mac( @@ -84,42 +86,32 @@ static int generate_mac( return 0; } -int setup_veth(const char *machine_name, - pid_t pid, - char iface_name[IFNAMSIZ], - bool bridge) { +static int add_veth( + sd_netlink *rtnl, + pid_t pid, + const char *ifname_host, + const struct ether_addr *mac_host, + const char *ifname_container, + const struct ether_addr *mac_container) { _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; - _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; - struct ether_addr mac_host, mac_container; - int r, i; - - /* Use two different interface name prefixes depending whether - * we are in bridge mode or not. */ - snprintf(iface_name, IFNAMSIZ - 1, "%s-%s", - bridge ? "vb" : "ve", machine_name); - - r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0); - if (r < 0) - return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m"); - - r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0); - if (r < 0) - return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m"); + int r; - r = sd_netlink_open(&rtnl); - if (r < 0) - return log_error_errno(r, "Failed to connect to netlink: %m"); + assert(rtnl); + assert(ifname_host); + assert(mac_host); + assert(ifname_container); + assert(mac_container); r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0); if (r < 0) return log_error_errno(r, "Failed to allocate netlink message: %m"); - r = sd_netlink_message_append_string(m, IFLA_IFNAME, iface_name); + r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_host); if (r < 0) return log_error_errno(r, "Failed to add netlink interface name: %m"); - r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_host); + r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_host); if (r < 0) return log_error_errno(r, "Failed to add netlink MAC address: %m"); @@ -135,11 +127,11 @@ int setup_veth(const char *machine_name, if (r < 0) return log_error_errno(r, "Failed to open netlink container: %m"); - r = sd_netlink_message_append_string(m, IFLA_IFNAME, "host0"); + r = sd_netlink_message_append_string(m, IFLA_IFNAME, ifname_container); if (r < 0) return log_error_errno(r, "Failed to add netlink interface name: %m"); - r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, &mac_container); + r = sd_netlink_message_append_ether_addr(m, IFLA_ADDRESS, mac_container); if (r < 0) return log_error_errno(r, "Failed to add netlink MAC address: %m"); @@ -161,7 +153,44 @@ int setup_veth(const char *machine_name, r = sd_netlink_call(rtnl, m, 0, NULL); if (r < 0) - return log_error_errno(r, "Failed to add new veth interfaces (host0, %s): %m", iface_name); + return log_error_errno(r, "Failed to add new veth interfaces (%s:%s): %m", ifname_host, ifname_container); + + return 0; +} + +int setup_veth(const char *machine_name, + pid_t pid, + char iface_name[IFNAMSIZ], + bool bridge) { + + _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + struct ether_addr mac_host, mac_container; + int r, i; + + assert(machine_name); + assert(pid > 0); + assert(iface_name); + + /* Use two different interface name prefixes depending whether + * we are in bridge mode or not. */ + snprintf(iface_name, IFNAMSIZ - 1, "%s-%s", + bridge ? "vb" : "ve", machine_name); + + r = generate_mac(machine_name, &mac_container, CONTAINER_HASH_KEY, 0); + if (r < 0) + return log_error_errno(r, "Failed to generate predictable MAC address for container side: %m"); + + r = generate_mac(machine_name, &mac_host, HOST_HASH_KEY, 0); + if (r < 0) + return log_error_errno(r, "Failed to generate predictable MAC address for host side: %m"); + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + r = add_veth(rtnl, pid, iface_name, &mac_host, "host0", &mac_container); + if (r < 0) + return r; i = (int) if_nametoindex(iface_name); if (i <= 0) @@ -170,6 +199,47 @@ int setup_veth(const char *machine_name, return i; } +int setup_veth_extra( + const char *machine_name, + pid_t pid, + char **pairs) { + + _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; + uint64_t idx = 0; + char **a, **b; + int r; + + assert(machine_name); + assert(pid > 0); + + if (strv_isempty(pairs)) + return 0; + + r = sd_netlink_open(&rtnl); + if (r < 0) + return log_error_errno(r, "Failed to connect to netlink: %m"); + + STRV_FOREACH_PAIR(a, b, pairs) { + struct ether_addr mac_host, mac_container; + + r = generate_mac(machine_name, &mac_container, VETH_EXTRA_CONTAINER_HASH_KEY, idx); + if (r < 0) + return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m"); + + r = generate_mac(machine_name, &mac_host, VETH_EXTRA_HOST_HASH_KEY, idx); + if (r < 0) + return log_error_errno(r, "Failed to generate predictable MAC address for container side of extra veth link: %m"); + + r = add_veth(rtnl, pid, *a, &mac_host, *b, &mac_container); + if (r < 0) + return r; + + idx ++; + } + + return 0; +} + int setup_bridge(const char *veth_name, const char *bridge_name) { _cleanup_netlink_message_unref_ sd_netlink_message *m = NULL; _cleanup_netlink_unref_ sd_netlink *rtnl = NULL; @@ -439,3 +509,34 @@ int setup_ipvlan(const char *machine_name, pid_t pid, char **ifaces) { return 0; } + +int veth_extra_parse(char ***l, const char *p) { + _cleanup_free_ char *a = NULL, *b = NULL; + int r; + + r = extract_first_word(&p, &a, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0 || isempty(a)) + return -EINVAL; + + r = extract_first_word(&p, &b, ":", EXTRACT_DONT_COALESCE_SEPARATORS); + if (r < 0) + return r; + if (r == 0 || isempty(b)) { + free(b); + b = strdup(a); + if (!b) + return -ENOMEM; + } + + if (p) + return -EINVAL; + + r = strv_push_pair(l, a, b); + if (r < 0) + return -ENOMEM; + + a = b = NULL; + return 0; +} |