From: Yu Watanabe Date: Thu, 21 Feb 2019 07:40:34 +0000 (+0900) Subject: network: make resolving NetDev names delayed and moved to network_verify() X-Git-Tag: v242-rc1~246^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=cebe12571d368e5028b8dbd9a2c8142473f08eee;p=thirdparty%2Fsystemd.git network: make resolving NetDev names delayed and moved to network_verify() And before resolving NetDev names, check conditions in .network, and if they do not match the system environment, drop the network unit earlier. Fixes #4211. --- diff --git a/src/network/netdev/netdev.h b/src/network/netdev/netdev.h index d6524da0f3b..a82c674dfdf 100644 --- a/src/network/netdev/netdev.h +++ b/src/network/netdev/netdev.h @@ -47,6 +47,7 @@ typedef enum NetDevKind { NETDEV_KIND_FOU, NETDEV_KIND_ERSPAN, _NETDEV_KIND_MAX, + _NETDEV_KIND_TUNNEL, /* Used by config_parse_stacked_netdev() */ _NETDEV_KIND_INVALID = -1 } NetDevKind; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 36b09f86819..1437d83f73a 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -38,15 +38,15 @@ Link.AllMulticast, config_parse_tristate, Link.Unmanaged, config_parse_bool, 0, offsetof(Network, unmanaged) Link.RequiredForOnline, config_parse_bool, 0, offsetof(Network, required_for_online) Network.Description, config_parse_string, 0, offsetof(Network, description) -Network.Bridge, config_parse_netdev, 0, 0 -Network.Bond, config_parse_netdev, 0, 0 -Network.VLAN, config_parse_netdev, 0, 0 -Network.MACVLAN, config_parse_netdev, 0, 0 -Network.MACVTAP, config_parse_netdev, 0, 0 -Network.IPVLAN, config_parse_netdev, 0, 0 -Network.VXLAN, config_parse_netdev, 0, 0 -Network.Tunnel, config_parse_tunnel, 0, 0 -Network.VRF, config_parse_netdev, 0, 0 +Network.Bridge, config_parse_ifname, 0, offsetof(Network, bridge_name) +Network.Bond, config_parse_ifname, 0, offsetof(Network, bond_name) +Network.VLAN, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names) +Network.MACVLAN, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names) +Network.MACVTAP, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names) +Network.IPVLAN, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names) +Network.VXLAN, config_parse_stacked_netdev, 0, offsetof(Network, stacked_netdev_names) +Network.Tunnel, config_parse_stacked_netdev, _NETDEV_KIND_TUNNEL, offsetof(Network, stacked_netdev_names) +Network.VRF, config_parse_ifname, 0, offsetof(Network, vrf_name) Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp) Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server) Network.LinkLocalAddressing, config_parse_address_family_boolean, 0, offsetof(Network, link_local) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index dff542e1940..33bda6ca05e 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -16,6 +16,7 @@ #include "networkd-network.h" #include "parse-util.h" #include "set.h" +#include "socket-util.h" #include "stat-util.h" #include "string-table.h" #include "string-util.h" @@ -97,6 +98,82 @@ void network_apply_anonymize_if_set(Network *network) { network->dhcp_use_timezone = false; } +static int network_resolve_netdev_one(Network *network, const char *name, NetDevKind kind, NetDev **ret_netdev) { + const char *kind_string; + NetDev *netdev; + int r; + + assert(network); + assert(network->manager); + assert(network->filename); + assert(ret_netdev); + + if (!name) + return 0; + + if (kind == _NETDEV_KIND_TUNNEL) + kind_string = "tunnel"; + else { + kind_string = netdev_kind_to_string(kind); + if (!kind_string) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "%s: Invalid NetDev kind of %s, ignoring assignment.", + network->filename, name); + } + + r = netdev_get(network->manager, name, &netdev); + if (r < 0) + return log_error_errno(r, "%s: %s NetDev could not be found, ignoring assignment.", + network->filename, name); + + if (netdev->kind != kind && !(kind == _NETDEV_KIND_TUNNEL && + IN_SET(netdev->kind, + NETDEV_KIND_IPIP, + NETDEV_KIND_SIT, + NETDEV_KIND_GRE, + NETDEV_KIND_GRETAP, + NETDEV_KIND_IP6GRE, + NETDEV_KIND_IP6GRETAP, + NETDEV_KIND_VTI, + NETDEV_KIND_VTI6, + NETDEV_KIND_IP6TNL))) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), + "%s: NetDev %s is not a %s, ignoring assignment", + network->filename, name, kind_string); + + *ret_netdev = netdev_ref(netdev); + return 1; +} + +static int network_resolve_stacked_netdevs(Network *network) { + void *name, *kind; + Iterator i; + int r; + + assert(network); + + HASHMAP_FOREACH_KEY(kind, name, network->stacked_netdev_names, i) { + _cleanup_(netdev_unrefp) NetDev *netdev = NULL; + + r = network_resolve_netdev_one(network, name, PTR_TO_INT(kind), &netdev); + if (r <= 0) + continue; + + r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops); + if (r < 0) + return log_oom(); + + r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev); + if (r < 0) + return log_error_errno(r, "%s: Failed to add NetDev '%s' to network: %m", + network->filename, (const char *) name); + + netdev = NULL; + } + + return 0; +} + static int network_verify(Network *network) { Address *address; Route *route; @@ -104,6 +181,25 @@ static int network_verify(Network *network) { assert(network); assert(network->filename); + /* skip out early if configuration does not match the environment */ + if (!net_match_config(NULL, NULL, NULL, NULL, NULL, + network->match_host, network->match_virt, network->match_kernel_cmdline, + network->match_kernel_version, network->match_arch, + NULL, NULL, NULL, NULL, NULL)) + return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), + "%s: Conditions in the file do not match the system environment, skipping.", network->filename); + + (void) network_resolve_netdev_one(network, network->bond_name, NETDEV_KIND_BOND, &network->bond); + (void) network_resolve_netdev_one(network, network->bridge_name, NETDEV_KIND_BRIDGE, &network->bridge); + (void) network_resolve_netdev_one(network, network->vrf_name, NETDEV_KIND_VRF, &network->vrf); + (void) network_resolve_stacked_netdevs(network); + + /* Free unnecessary entries. */ + network->bond_name = mfree(network->bond_name); + network->bridge_name = mfree(network->bridge_name); + network->vrf_name = mfree(network->vrf_name); + network->stacked_netdev_names = hashmap_free_free_key(network->stacked_netdev_names); + if (network->bond) { /* Bonding slave does not support addressing. */ if (network->ipv6_accept_ra > 0) { @@ -395,10 +491,13 @@ void network_free(Network *network) { ordered_set_free_free(network->router_search_domains); free(network->router_dns); + free(network->bridge_name); + free(network->bond_name); + free(network->vrf_name); + hashmap_free_free_key(network->stacked_netdev_names); netdev_unref(network->bridge); netdev_unref(network->bond); netdev_unref(network->vrf); - hashmap_free_with_destructor(network->stacked_netdevs, netdev_unref); while ((route = network->static_routes)) @@ -576,7 +675,7 @@ bool network_has_static_ipv6_addresses(Network *network) { return false; } -int config_parse_netdev(const char *unit, +int config_parse_stacked_netdev(const char *unit, const char *filename, unsigned line, const char *section, @@ -586,11 +685,10 @@ int config_parse_netdev(const char *unit, const char *rvalue, void *data, void *userdata) { - Network *network = userdata; - _cleanup_free_ char *kind_string = NULL; - char *p; - NetDev *netdev; + _cleanup_free_ char *kind_string = NULL, *name = NULL; + Hashmap **h = data; NetDevKind kind; + char *p; int r; assert(filename); @@ -598,72 +696,45 @@ int config_parse_netdev(const char *unit, assert(rvalue); assert(data); - kind_string = strdup(lvalue); - if (!kind_string) - return log_oom(); - - /* the keys are CamelCase versions of the kind */ - for (p = kind_string; *p; p++) - *p = tolower(*p); + if (ltype == _NETDEV_KIND_TUNNEL) + kind = _NETDEV_KIND_TUNNEL; + else { + kind_string = strdup(lvalue); + if (!kind_string) + return log_oom(); - kind = netdev_kind_from_string(kind_string); - if (kind == _NETDEV_KIND_INVALID) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "Invalid NetDev kind: %s", lvalue); - return 0; - } + /* the keys are CamelCase versions of the kind */ + for (p = kind_string; *p; p++) + *p = tolower(*p); - r = netdev_get(network->manager, rvalue, &netdev); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "%s could not be found, ignoring assignment: %s", lvalue, rvalue); - return 0; + kind = netdev_kind_from_string(kind_string); + if (kind < 0 || IN_SET(kind, NETDEV_KIND_BRIDGE, NETDEV_KIND_BOND, NETDEV_KIND_VRF)) { + log_syntax(unit, LOG_ERR, filename, line, 0, + "Invalid NetDev kind: %s", lvalue); + return 0; + } } - if (netdev->kind != kind) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "NetDev is not a %s, ignoring assignment: %s", lvalue, rvalue); + if (!ifname_valid(rvalue)) { + log_syntax(unit, LOG_ERR, filename, line, 0, "Invalid netdev name in %s=, ignoring assignment: %s", lvalue, rvalue); return 0; } - switch (kind) { - case NETDEV_KIND_BRIDGE: - network->bridge = netdev_unref(network->bridge); - network->bridge = netdev; - - break; - case NETDEV_KIND_BOND: - network->bond = netdev_unref(network->bond); - network->bond = netdev; - - break; - case NETDEV_KIND_VRF: - network->vrf = netdev_unref(network->vrf); - network->vrf = netdev; - - break; - case NETDEV_KIND_VLAN: - case NETDEV_KIND_MACVLAN: - case NETDEV_KIND_MACVTAP: - case NETDEV_KIND_IPVLAN: - case NETDEV_KIND_VXLAN: - case NETDEV_KIND_VCAN: - r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops); - if (r < 0) - return log_oom(); + name = strdup(rvalue); + if (!name) + return log_oom(); - r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network: %m", rvalue); - return 0; - } + r = hashmap_ensure_allocated(h, &string_hash_ops); + if (r < 0) + return log_oom(); - break; - default: - assert_not_reached("Cannot parse NetDev"); + r = hashmap_put(*h, name, INT_TO_PTR(kind)); + if (r < 0) { + log_syntax(unit, LOG_ERR, filename, line, r, "Cannot add NetDev '%s' to network, ignoring assignment: %m", rvalue); + return 0; } - netdev_ref(netdev); + name = NULL; return 0; } @@ -749,63 +820,6 @@ int config_parse_domains( return 0; } -int config_parse_tunnel(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) { - Network *network = userdata; - NetDev *netdev; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(data); - - r = netdev_get(network->manager, rvalue, &netdev); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Tunnel is invalid, ignoring assignment: %s", rvalue); - return 0; - } - - if (!IN_SET(netdev->kind, - NETDEV_KIND_IPIP, - NETDEV_KIND_SIT, - NETDEV_KIND_GRE, - NETDEV_KIND_GRETAP, - NETDEV_KIND_IP6GRE, - NETDEV_KIND_IP6GRETAP, - NETDEV_KIND_VTI, - NETDEV_KIND_VTI6, - NETDEV_KIND_IP6TNL)) { - log_syntax(unit, LOG_ERR, filename, line, 0, - "NetDev is not a tunnel, ignoring assignment: %s", rvalue); - return 0; - } - - r = hashmap_ensure_allocated(&network->stacked_netdevs, &string_hash_ops); - if (r < 0) - return log_oom(); - - r = hashmap_put(network->stacked_netdevs, netdev->ifname, netdev); - if (r < 0) { - log_syntax(unit, LOG_ERR, filename, line, r, - "Cannot add VLAN '%s' to network, ignoring: %m", rvalue); - return 0; - } - - netdev_ref(netdev); - - return 0; -} - int config_parse_ipv4ll( const char* unit, const char *filename, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 5681e8d2121..6b9b155b679 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -120,6 +120,10 @@ struct Network { NetDev *bond; NetDev *vrf; Hashmap *stacked_netdevs; + char *bridge_name; + char *bond_name; + char *vrf_name; + Hashmap *stacked_netdev_names; /* DHCP Client Support */ AddressFamilyBoolean dhcp; @@ -297,7 +301,7 @@ void network_apply_anonymize_if_set(Network *network); bool network_has_static_ipv6_addresses(Network *network); -CONFIG_PARSER_PROTOTYPE(config_parse_netdev); +CONFIG_PARSER_PROTOTYPE(config_parse_stacked_netdev); CONFIG_PARSER_PROTOTYPE(config_parse_domains); CONFIG_PARSER_PROTOTYPE(config_parse_tunnel); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp);