]> git.proxmox.com Git - systemd.git/blobdiff - src/network/netdev/netdev.c
New upstream version 240
[systemd.git] / src / network / netdev / netdev.c
index 82ce88402f1ae402e0c0099aa8f2fbbd28de399d..f0e9d002468b8b7ddd858e0a839e2666b21854bb 100644 (file)
@@ -16,6 +16,7 @@
 #include "stat-util.h"
 #include "string-table.h"
 #include "string-util.h"
+#include "strv.h"
 
 #include "netdev/bridge.h"
 #include "netdev/bond.h"
@@ -33,6 +34,7 @@
 #include "netdev/vxcan.h"
 #include "netdev/wireguard.h"
 #include "netdev/netdevsim.h"
+#include "netdev/fou-tunnel.h"
 
 const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_BRIDGE] = &bridge_vtable,
@@ -61,6 +63,8 @@ const NetDevVTable * const netdev_vtable[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_VXCAN] = &vxcan_vtable,
         [NETDEV_KIND_WIREGUARD] = &wireguard_vtable,
         [NETDEV_KIND_NETDEVSIM] = &netdevsim_vtable,
+        [NETDEV_KIND_FOU] = &foutnl_vtable,
+        [NETDEV_KIND_ERSPAN] = &erspan_vtable,
 };
 
 static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
@@ -90,45 +94,74 @@ static const char* const netdev_kind_table[_NETDEV_KIND_MAX] = {
         [NETDEV_KIND_VXCAN] = "vxcan",
         [NETDEV_KIND_WIREGUARD] = "wireguard",
         [NETDEV_KIND_NETDEVSIM] = "netdevsim",
+        [NETDEV_KIND_FOU] = "fou",
+        [NETDEV_KIND_ERSPAN] = "erspan",
 };
 
 DEFINE_STRING_TABLE_LOOKUP(netdev_kind, NetDevKind);
-DEFINE_CONFIG_PARSE_ENUM(config_parse_netdev_kind, netdev_kind, NetDevKind, "Failed to parse netdev kind");
 
-static void netdev_cancel_callbacks(NetDev *netdev) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
-        netdev_join_callback *callback;
+int config_parse_netdev_kind(
+                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) {
+
+        NetDevKind k, *kind = data;
+
+        assert(rvalue);
+        assert(data);
+
+        k = netdev_kind_from_string(rvalue);
+        if (k < 0) {
+                log_syntax(unit, LOG_ERR, filename, line, 0, "Failed to parse netdev kind, ignoring assignment: %s", rvalue);
+                return 0;
+        }
 
-        if (!netdev || !netdev->manager)
-                return;
+        if (*kind != _NETDEV_KIND_INVALID && *kind != k) {
+                log_syntax(unit, LOG_ERR, filename, line, 0,
+                           "Specified netdev kind is different from the previous value '%s', ignoring assignment: %s",
+                           netdev_kind_to_string(*kind), rvalue);
+                return 0;
+        }
 
-        rtnl_message_new_synthetic_error(netdev->manager->rtnl, -ENODEV, 0, &m);
+        *kind = k;
 
-        while ((callback = netdev->callbacks)) {
-                if (m) {
-                        assert(callback->link);
-                        assert(callback->callback);
-                        assert(netdev->manager);
-                        assert(netdev->manager->rtnl);
+        return 0;
+}
 
-                        callback->callback(netdev->manager->rtnl, m, callback->link);
-                }
+static void netdev_callbacks_clear(NetDev *netdev) {
+        netdev_join_callback *callback;
 
+        if (!netdev)
+                return;
+
+        while ((callback = netdev->callbacks)) {
                 LIST_REMOVE(callbacks, netdev->callbacks, callback);
                 link_unref(callback->link);
                 free(callback);
         }
 }
 
-static void netdev_free(NetDev *netdev) {
-        if (!netdev)
-                return;
-
-        netdev_cancel_callbacks(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) {
+        assert(netdev);
+
+        netdev_callbacks_clear(netdev);
+
+        netdev_detach_from_manager(netdev);
+
         free(netdev->filename);
 
         free(netdev->description);
@@ -153,22 +186,10 @@ static void netdev_free(NetDev *netdev) {
             NETDEV_VTABLE(netdev)->done)
                 NETDEV_VTABLE(netdev)->done(netdev);
 
-        free(netdev);
+        return mfree(netdev);
 }
 
-NetDev *netdev_unref(NetDev *netdev) {
-        if (netdev && (-- netdev->n_ref <= 0))
-                netdev_free(netdev);
-
-        return NULL;
-}
-
-NetDev *netdev_ref(NetDev *netdev) {
-        if (netdev)
-                assert_se(++ netdev->n_ref >= 2);
-
-        return netdev;
-}
+DEFINE_TRIVIAL_REF_UNREF_FUNC(NetDev, netdev, netdev_free);
 
 void netdev_drop(NetDev *netdev) {
         if (!netdev || netdev->state == NETDEV_STATE_LINGER)
@@ -178,7 +199,9 @@ void netdev_drop(NetDev *netdev) {
 
         log_netdev_debug(netdev, "netdev removed");
 
-        netdev_cancel_callbacks(netdev);
+        netdev_callbacks_clear(netdev);
+
+        netdev_detach_from_manager(netdev);
 
         netdev_unref(netdev);
 
@@ -206,12 +229,12 @@ int netdev_get(Manager *manager, const char *name, NetDev **ret) {
 static int netdev_enter_failed(NetDev *netdev) {
         netdev->state = NETDEV_STATE_FAILED;
 
-        netdev_cancel_callbacks(netdev);
+        netdev_callbacks_clear(netdev);
 
         return 0;
 }
 
-static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_handler_t callback) {
+static int netdev_enslave_ready(NetDev *netdev, Link* link, link_netlink_message_handler_t callback) {
         _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
         int r;
 
@@ -238,7 +261,8 @@ static int netdev_enslave_ready(NetDev *netdev, Link* link, sd_netlink_message_h
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not append IFLA_MASTER attribute: %m");
 
-        r = sd_netlink_call_async(netdev->manager->rtnl, req, callback, link, 0, NULL);
+        r = netlink_call_async(netdev->manager->rtnl, NULL, req, callback,
+                               link_netlink_destroy_callback, link);
         if (r < 0)
                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
@@ -282,10 +306,10 @@ static int netdev_enter_ready(NetDev *netdev) {
 }
 
 /* callback for netdev's created without a backing Link */
-static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *userdata) {
-        _cleanup_(netdev_unrefp) NetDev *netdev = userdata;
+static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, NetDev *netdev) {
         int r;
 
+        assert(netdev);
         assert(netdev->state != _NETDEV_STATE_INVALID);
 
         r = sd_netlink_message_get_errno(m);
@@ -303,7 +327,7 @@ static int netdev_create_handler(sd_netlink *rtnl, sd_netlink_message *m, void *
         return 1;
 }
 
-int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
+static int netdev_enslave(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
         int r;
 
         assert(netdev);
@@ -325,13 +349,14 @@ int netdev_enslave(NetDev *netdev, Link *link, sd_netlink_message_handler_t call
                 /* the netdev is not yet read, save this request for when it is */
                 netdev_join_callback *cb;
 
-                cb = new0(netdev_join_callback, 1);
+                cb = new(netdev_join_callback, 1);
                 if (!cb)
                         return log_oom();
 
-                cb->callback = callback;
-                cb->link = link;
-                link_ref(link);
+                *cb = (netdev_join_callback) {
+                        .callback = callback,
+                        .link = link_ref(link),
+                };
 
                 LIST_PREPEND(callbacks, netdev->callbacks, cb);
 
@@ -478,8 +503,7 @@ int netdev_get_mac(const char *ifname, struct ether_addr **ret) {
         return 0;
 }
 
-static int netdev_create(NetDev *netdev, Link *link,
-                         sd_netlink_message_handler_t callback) {
+static int netdev_create(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
         int r;
 
         assert(netdev);
@@ -546,13 +570,15 @@ static int netdev_create(NetDev *netdev, Link *link,
                         return log_netdev_error_errno(netdev, r, "Could not append IFLA_LINKINFO attribute: %m");
 
                 if (link) {
-                        r = sd_netlink_call_async(netdev->manager->rtnl, m, callback, link, 0, NULL);
+                        r = netlink_call_async(netdev->manager->rtnl, NULL, m, callback,
+                                               link_netlink_destroy_callback, link);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
                         link_ref(link);
                 } else {
-                        r = sd_netlink_call_async(netdev->manager->rtnl, m, netdev_create_handler, netdev, 0, NULL);
+                        r = netlink_call_async(netdev->manager->rtnl, NULL, m, netdev_create_handler,
+                                               netdev_destroy_callback, netdev);
                         if (r < 0)
                                 return log_netdev_error_errno(netdev, r, "Could not send rtnetlink message: %m");
 
@@ -568,7 +594,7 @@ static int netdev_create(NetDev *netdev, Link *link,
 }
 
 /* the callback must be called, possibly after a timeout, as otherwise the Link will hang */
-int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callback) {
+int netdev_join(NetDev *netdev, Link *link, link_netlink_message_handler_t callback) {
         int r;
 
         assert(netdev);
@@ -596,7 +622,7 @@ int netdev_join(NetDev *netdev, Link *link, sd_netlink_message_handler_t callbac
         return 0;
 }
 
-static int netdev_load_one(Manager *manager, const char *filename) {
+int netdev_load_one(Manager *manager, const char *filename) {
         _cleanup_(netdev_unrefp) NetDev *netdev_raw = NULL, *netdev = NULL;
         _cleanup_fclose_ FILE *file = NULL;
         const char *dropin_dirname;
@@ -619,13 +645,15 @@ static int netdev_load_one(Manager *manager, const char *filename) {
                 return 0;
         }
 
-        netdev_raw = new0(NetDev, 1);
+        netdev_raw = new(NetDev, 1);
         if (!netdev_raw)
                 return log_oom();
 
-        netdev_raw->n_ref = 1;
-        netdev_raw->kind = _NETDEV_KIND_INVALID;
-        netdev_raw->state = _NETDEV_STATE_INVALID; /* an invalid state means done() of the implementation won't be called on destruction */
+        *netdev_raw = (NetDev) {
+                .n_ref = 1,
+                .kind = _NETDEV_KIND_INVALID,
+                .state = _NETDEV_STATE_INVALID, /* an invalid state means done() of the implementation won't be called on destruction */
+        };
 
         dropin_dirname = strjoina(basename(filename), ".d");
         r = config_parse_many(filename, network_dirs, dropin_dirname,
@@ -669,10 +697,10 @@ static int netdev_load_one(Manager *manager, const char *filename) {
         if (NETDEV_VTABLE(netdev)->init)
                 NETDEV_VTABLE(netdev)->init(netdev);
 
-        r = config_parse(NULL, filename, file,
-                         NETDEV_VTABLE(netdev)->sections,
-                         config_item_perf_lookup, network_netdev_gperf_lookup,
-                         CONFIG_PARSE_WARN, netdev);
+        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);
         if (r < 0)
                 return r;
 
@@ -693,6 +721,10 @@ static int netdev_load_one(Manager *manager, const char *filename) {
                         return log_error_errno(r, "Failed to generate predictable MAC address for %s: %m", netdev->ifname);
         }
 
+        r = hashmap_ensure_allocated(&netdev->manager->netdevs, &string_hash_ops);
+        if (r < 0)
+                return r;
+
         r = hashmap_put(netdev->manager->netdevs, netdev->ifname, netdev);
         if (r < 0)
                 return r;
@@ -758,14 +790,12 @@ static int netdev_load_one(Manager *manager, const char *filename) {
 
 int netdev_load(Manager *manager) {
         _cleanup_strv_free_ char **files = NULL;
-        NetDev *netdev;
         char **f;
         int r;
 
         assert(manager);
 
-        while ((netdev = hashmap_first(manager->netdevs)))
-                netdev_unref(netdev);
+        hashmap_clear_with_destructor(manager->netdevs, netdev_unref);
 
         r = conf_files_list_strv(&files, ".netdev", NULL, 0, network_dirs);
         if (r < 0)