]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: make resolving NetDev names delayed and moved to network_verify()
authorYu Watanabe <watanabe.yu+github@gmail.com>
Thu, 21 Feb 2019 07:40:34 +0000 (16:40 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 26 Feb 2019 01:06:23 +0000 (10:06 +0900)
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.

src/network/netdev/netdev.h
src/network/networkd-network-gperf.gperf
src/network/networkd-network.c
src/network/networkd-network.h

index d6524da0f3ba611e11c2181d380ad6bb08f2c2be..a82c674dfdfc08cbf6190f48da7b005e86f0b501 100644 (file)
@@ -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;
 
index 36b09f8681969a8792f52cc312bf403926fedef4..1437d83f73a6934e0800352445d5c8721fc34410 100644 (file)
@@ -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)
index dff542e1940797ab6b933a576710ddd88c424a93..33bda6ca05eb4b0c629e03f6866a074cb67dc8a4 100644 (file)
@@ -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,
index 5681e8d2121262d0a5355ff7d9eb2a47ea147340..6b9b155b679dde03ec83c345e6e58f645d670a6b 100644 (file)
@@ -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);