]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/network/netdev/netdev.c
network: do not abort execution when NetDev.Name= conflicts
[thirdparty/systemd.git] / src / network / netdev / netdev.c
index f0e9d002468b8b7ddd858e0a839e2666b21854bb..df05cb465bd5e3dbc4e33a2bca89b21e63b606fc 100644 (file)
@@ -7,34 +7,34 @@
 #include "conf-parser.h"
 #include "fd-util.h"
 #include "list.h"
-#include "netlink-util.h"
-#include "network-internal.h"
-#include "netdev/netdev.h"
-#include "networkd-manager.h"
-#include "networkd-link.h"
-#include "siphash24.h"
-#include "stat-util.h"
-#include "string-table.h"
-#include "string-util.h"
-#include "strv.h"
-
-#include "netdev/bridge.h"
 #include "netdev/bond.h"
+#include "netdev/bridge.h"
+#include "netdev/dummy.h"
+#include "netdev/fou-tunnel.h"
 #include "netdev/geneve.h"
-#include "netdev/vlan.h"
-#include "netdev/macvlan.h"
 #include "netdev/ipvlan.h"
-#include "netdev/vxlan.h"
+#include "netdev/l2tp-tunnel.h"
+#include "netdev/macvlan.h"
+#include "netdev/netdev.h"
+#include "netdev/netdevsim.h"
 #include "netdev/tunnel.h"
 #include "netdev/tuntap.h"
+#include "netdev/vcan.h"
 #include "netdev/veth.h"
-#include "netdev/dummy.h"
+#include "netdev/vlan.h"
 #include "netdev/vrf.h"
-#include "netdev/vcan.h"
 #include "netdev/vxcan.h"
+#include "netdev/vxlan.h"
 #include "netdev/wireguard.h"
-#include "netdev/netdevsim.h"
-#include "netdev/fou-tunnel.h"
+#include "netlink-util.h"
+#include "network-internal.h"
+#include "networkd-link.h"
+#include "networkd-manager.h"
+#include "siphash24.h"
+#include "stat-util.h"
+#include "string-table.h"
+#include "string-util.h"
+#include "strv.h"
 
 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_BRIDGE] = &bridge_vtable,
@@ -65,6 +65,7 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_NETDEVSIM] = &netdevsim_vtable,
         [NETDEV_KIND_FOU] = &foutnl_vtable,
         [NETDEV_KIND_ERSPAN] = &erspan_vtable,
+        [NETDEV_KIND_L2TP] = &l2tptnl_vtable,
 };
 
 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
@@ -96,6 +97,7 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_NETDEVSIM] = "netdevsim",
         [NETDEV_KIND_FOU] = "fou",
         [NETDEV_KIND_ERSPAN] = "erspan",
+        [NETDEV_KIND_L2TP] = "l2tp",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
@@ -148,11 +150,16 @@ static void netdev_callbacks_clear(NetDev *netdev) {
         }
 }
 
+bool netdev_is_managed(NetDev *netdev) {
+        if (!netdev || !netdev->manager || !netdev->ifname)
+                return false;
+
+        return hashmap_get(netdev->manager->netdevs, netdev->ifname) == netdev;
+}
+
 static void netdev_detach_from_manager(NetDev *netdev) {
         if (netdev->ifname && netdev->manager)
                 hashmap_remove(netdev->manager->netdevs, netdev->ifname);
-
-        netdev->manager = NULL;
 }
 
 static NetDev *netdev_free(NetDev *netdev) {
@@ -167,12 +174,7 @@ static NetDev *netdev_free(NetDev *netdev) {
         free(netdev->description);
         free(netdev->ifname);
         free(netdev->mac);
-
-        condition_free_list(netdev->match_host);
-        condition_free_list(netdev->match_virt);
-        condition_free_list(netdev->match_kernel_cmdline);
-        condition_free_list(netdev->match_kernel_version);
-        condition_free_list(netdev->match_arch);
+        condition_free_list(netdev->conditions);
 
         /* Invoke the per-kind done() destructor, but only if the state field is initialized. We conditionalize that
          * because we parse .netdev files twice: once to determine the kind (with a short, minimal NetDev structure
@@ -476,7 +478,7 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
 
         l = strlen(ifname);
         sz = sizeof(sd_id128_t) + l;
-        v = alloca(sz);
+        v = newa(uint8_t, sz);
 
         /* fetch some persistent data unique to the machine */
         r = sd_id128_get_machine((sd_id128_t*) v);
@@ -593,6 +595,14 @@ static int netdev_create(NetDev *netdev, Link *link, link_netlink_message_handle
         return 0;
 }
 
+static int netdev_create_after_configured(NetDev *netdev, Link *link) {
+        assert(netdev);
+        assert(link);
+        assert(NETDEV_VTABLE(netdev)->create_after_configured);
+
+        return NETDEV_VTABLE(netdev)->create_after_configured(netdev, link);
+}
+
 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
 int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
         int r;
@@ -600,9 +610,8 @@ int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callb
         assert(netdev);
         assert(netdev->manager);
         assert(netdev->manager->rtnl);
-        assert(NETDEV_VTABLE(netdev));
 
-        switch (NETDEV_VTABLE(netdev)->create_type) {
+        switch (netdev_get_create_type(netdev)) {
         case NETDEV_CREATE_MASTER:
                 r = netdev_enslave(netdev, link, callback);
                 if (r < 0)
@@ -615,6 +624,11 @@ int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callb
                         return r;
 
                 break;
+        case NETDEV_CREATE_AFTER_CONFIGURED:
+                r = netdev_create_after_configured(netdev, link);
+                if (r < 0)
+                        return r;
+                break;
         default:
                 assert_not_reached("Can not join independent netdev");
         }
@@ -656,7 +670,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
         };
 
         dropin_dirname = strjoina(basename(filename), ".d");
-        r = config_parse_many(filename, network_dirs, dropin_dirname,
+        r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
                               "Match\0NetDev\0",
                               config_item_perf_lookup, network_netdev_gperf_lookup,
                               CONFIG_PARSE_WARN|CONFIG_PARSE_RELAXED, netdev_raw);
@@ -664,12 +678,10 @@ int netdev_load_one(Manager *manager, const char *filename) {
                 return r;
 
         /* skip out early if configuration does not match the environment */
-        if (net_match_config(NULL, NULL, NULL, NULL, NULL,
-                             netdev_raw->match_host, netdev_raw->match_virt,
-                             netdev_raw->match_kernel_cmdline, netdev_raw->match_kernel_version,
-                             netdev_raw->match_arch,
-                             NULL, NULL, NULL, NULL, NULL, NULL) <= 0)
+        if (!condition_test_list(netdev_raw->conditions, NULL, NULL, NULL)) {
+                log_debug("%s: Conditions in the file do not match the system environment, skipping.", filename);
                 return 0;
+        }
 
         if (netdev_raw->kind == _NETDEV_KIND_INVALID) {
                 log_warning("NetDev has no Kind configured in %s. Ignoring", filename);
@@ -697,7 +709,7 @@ int netdev_load_one(Manager *manager, const char *filename) {
         if (NETDEV_VTABLE(netdev)->init)
                 NETDEV_VTABLE(netdev)->init(netdev);
 
-        r = config_parse_many(filename, network_dirs, dropin_dirname,
+        r = config_parse_many(filename, NETWORK_DIRS, dropin_dirname,
                               NETDEV_VTABLE(netdev)->sections,
                               config_item_perf_lookup, network_netdev_gperf_lookup,
                               CONFIG_PARSE_WARN, netdev);
@@ -726,6 +738,19 @@ int netdev_load_one(Manager *manager, const char *filename) {
                 return r;
 
         r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
+        if (r == -EEXIST) {
+                NetDev *n = hashmap_get(netdev->manager->netdevs, netdev->ifname);
+
+                assert(n);
+                log_netdev_warning_errno(netdev, r,
+                                         "The setting Name=%s in %s conflicts with the one in %s, ignoring",
+                                         netdev->ifname, netdev->filename, n->filename);
+
+                /* Clear ifname before netdev_free() is called. Otherwise, the NetDev object 'n' is
+                 * removed from the hashmap 'manager->netdevs'. */
+                netdev->ifname = mfree(netdev->ifname);
+                return 0;
+        }
         if (r < 0)
                 return r;
 
@@ -733,16 +758,10 @@ int netdev_load_one(Manager *manager, const char *filename) {
 
         log_netdev_debug(netdev, "loaded %s", netdev_kind_to_string(netdev->kind));
 
-        switch (NETDEV_VTABLE(netdev)->create_type) {
-        case NETDEV_CREATE_MASTER:
-        case NETDEV_CREATE_INDEPENDENT:
+        if (IN_SET(netdev_get_create_type(netdev), NETDEV_CREATE_MASTER, NETDEV_CREATE_INDEPENDENT)) {
                 r = netdev_create(netdev, NULL, NULL);
                 if (r < 0)
                         return r;
-
-                break;
-        default:
-                break;
         }
 
         switch (netdev->kind) {
@@ -773,6 +792,9 @@ int netdev_load_one(Manager *manager, const char *filename) {
         case NETDEV_KIND_IP6TNL:
                 independent = IP6TNL(netdev)->independent;
                 break;
+        case NETDEV_KIND_ERSPAN:
+                independent = ERSPAN(netdev)->independent;
+                break;
         default:
                 break;
         }
@@ -797,11 +819,11 @@ int netdev_load(Manager *manager) {
 
         hashmap_clear_with_destructor(manager->netdevs, netdev_unref);
 
-        r = conf_files_list_strv(&files, ".netdev", NULL, 0, network_dirs);
+        r = conf_files_list_strv(&files, ".netdev", NULL, 0, NETWORK_DIRS);
         if (r < 0)
                 return log_error_errno(r, "Failed to enumerate netdev files: %m");
 
-        STRV_FOREACH_BACKWARDS(f, files) {
+        STRV_FOREACH(f, files) {
                 r = netdev_load_one(manager, *f);
                 if (r < 0)
                         return r;