]> git.ipfire.org Git - people/ms/network.git/commitdiff
ports: Implement creating links from ports
authorMichael Tremer <michael.tremer@ipfire.org>
Sun, 4 Jun 2023 16:26:44 +0000 (16:26 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Sun, 4 Jun 2023 16:26:44 +0000 (16:26 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/networkd/port-dummy.c
src/networkd/port-vlan.c
src/networkd/port.c
src/networkd/port.h

index cc4b649db4deec9ca6df8da8eaa732384226d614..09367d830bfae6558c96f1b61d9599bc10cc53ea 100644 (file)
 #                                                                             #
 #############################################################################*/
 
-#include "port.h"
 #include "port-dummy.h"
 
 nw_port_ops_t nw_port_ops_dummy = {
-       // There is no special configuration
-       .config_read = NULL,
-       .config_write = NULL,
+       .kind = "dummy",
 };
index c9581f68d3a8171e8fd35c68f8314431ccfbcebb..edf91d91d1ad5a3f26ef12bc922b519d57af2eb6 100644 (file)
@@ -18,6 +18,8 @@
 #                                                                             #
 #############################################################################*/
 
+#include <systemd/sd-netlink.h>
+
 #include "config.h"
 #include "daemon.h"
 #include "logging.h"
@@ -64,10 +66,28 @@ static int nw_port_vlan_config_write(nw_port* port) {
        return 0;
 }
 
+static int nw_port_vlan_create_link(nw_port* port, sd_netlink_message* m) {
+       int r;
+
+       // Set VLAN ID
+       r = sd_netlink_message_append_u16(m, IFLA_VLAN_ID, port->vlan.id);
+       if (r < 0)
+               return r;
+
+       return 0;
+}
+
 nw_port_ops_t nw_port_ops_vlan = {
+       .kind = "vlan",
+
        // Configuration
        .config_read = nw_port_vlan_config_read,
        .config_write = nw_port_vlan_config_write,
+
+       .get_parent_port = nw_port_get_vlan_parent,
+
+       // Link
+       .create_link = nw_port_vlan_create_link,
 };
 
 /*
index b3b7d668914ba025ade34a98b6f10d2b5cb27335..a7cbab63c0c6775cbdadb81e76a14c8817d5caaa 100644 (file)
@@ -72,7 +72,7 @@ static int nw_port_setup_address(nw_port* port) {
        // Read ADDRESS from configuration
        const char* s = nw_config_get(port->config, "ADDRESS");
        if (!s) {
-               ERROR("Port %s: Address isn't set\n", port->name);
+               ERROR("Port %s: Address is not set\n", port->name);
                goto ERROR;
        }
 
@@ -271,6 +271,16 @@ nw_port* nw_port_unref(nw_port* port) {
        return NULL;
 }
 
+/*
+       This is a helper function for when we pass a reference to the event loop
+       it will have to dereference the port instance later.
+*/
+static void __nw_port_unref(void* data) {
+       nw_port* port = (nw_port*)data;
+
+       nw_port_unref(port);
+}
+
 int nw_port_destroy(nw_port* port) {
        int r;
 
@@ -395,6 +405,17 @@ int __nw_port_drop_link(nw_daemon* daemon, nw_port* port, void* data) {
        return 0;
 }
 
+static nw_link* nw_port_get_link(nw_port* port) {
+       // Fetch the link if not set
+       if (!port->link)
+               port->link = nw_daemon_get_link_by_name(port->daemon, port->name);
+
+       if (!port->link)
+               return NULL;
+
+       return nw_link_ref(port->link);
+}
+
 const nw_address_t* nw_port_get_address(nw_port* port) {
        return &port->address;
 }
@@ -403,19 +424,129 @@ static int nw_port_is_disabled(nw_port* port) {
        return nw_config_get_bool(port->config, "DISABLED");
 }
 
+static nw_link* nw_port_get_parent_link(nw_port* port) {
+       nw_port* parent = NULL;
+       nw_link* link = NULL;
+
+       // Do nothing if not implemented
+       if (!port->ops.get_parent_port)
+               goto ERROR;
+
+       // Fetch the parent
+       parent = port->ops.get_parent_port(port);
+       if (!parent)
+               goto ERROR;
+
+       // Fetch the link
+       link = nw_port_get_link(parent);
+
+ERROR:
+       if (parent)
+               nw_port_unref(parent);
+
+       return link;
+}
+
+static int __nw_port_create_link(sd_netlink* rtnl, sd_netlink_message* m, void* data) {
+       nw_port* port = (nw_port*)data;
+       int r;
+
+       // Check if the operation was successful
+       r = sd_netlink_message_get_errno(m);
+       if (r < 0) {
+               ERROR("Could not create port %s: %s\n", port->name, strerror(-r));
+               // XXX We should extract the error message
+
+               return 0;
+       }
+
+       DEBUG("Successfully created %s\n", port->name);
+
+       return 0;
+}
+
 static int nw_port_create_link(nw_port* port) {
+       sd_netlink_message* m = NULL;
+       nw_link* link = NULL;
        int r;
 
-       // Fail if the function isn't set
-       if (!port->ops.create_link) {
-               errno = ENOTSUP;
-               return -errno;
+       sd_netlink* rtnl = nw_daemon_get_rtnl(port->daemon);
+
+       // Create a new link
+       r = sd_rtnl_message_new_link(rtnl, &m, RTM_NEWLINK, 0);
+       if (r < 0) {
+               ERROR("Could not create netlink message: %m\n");
+               goto ERROR;
        }
 
-       // Create the link
-       r = port->ops.create_link(port);
-       if (r)
-               ERROR("Could not create link %s: %m\n", port->name);
+       // Set the name
+       r = sd_netlink_message_append_string(m, IFLA_IFNAME, port->name);
+       if (r < 0) {
+               ERROR("Could not set port name: %s\n", strerror(-r));
+               goto ERROR;
+       }
+
+       // XXX Set common things like MAC address, etc.
+
+       // Fetch the parent link
+       link = nw_port_get_parent_link(port);
+       if (link) {
+               r = sd_netlink_message_append_u32(m, IFLA_LINK, nw_link_ifindex(link));
+               if (r < 0)
+                       goto ERROR;
+       }
+
+       // Open an IFLA_LINKINFO container
+       r = sd_netlink_message_open_container(m, IFLA_LINKINFO);
+       if (r < 0)
+               goto ERROR;
+
+       // Run the custom setup
+       if (port->ops.create_link) {
+               r = sd_netlink_message_open_container_union(m, IFLA_INFO_DATA, port->ops.kind);
+               if (r < 0) {
+                       ERROR("Could not open IFLA_INFO_DATA container: %s\n", strerror(-r));
+                       goto ERROR;
+               }
+
+               r = port->ops.create_link(port, m);
+               if (r) {
+                       ERROR("Could not create port %s: %m\n", port->name);
+                       goto ERROR;
+               }
+
+               // Close the container
+               r = sd_netlink_message_close_container(m);
+               if (r < 0)
+                       goto ERROR;
+
+       // Just set IFLA_INFO_KIND if there is no custom function
+       } else {
+               r = sd_netlink_message_append_string(m, IFLA_INFO_KIND, port->ops.kind);
+               if (r < 0)
+                       goto ERROR;
+       }
+
+       // Close the container
+       r = sd_netlink_message_close_container(m);
+       if (r < 0)
+               goto ERROR;
+
+       // Send the message
+       r = sd_netlink_call_async(rtnl, NULL, m, __nw_port_create_link,
+               __nw_port_unref, nw_port_ref(port), -1, NULL);
+       if (r < 0) {
+               ERROR("Could not send netlink message: %s\n", strerror(-r));
+               goto ERROR;
+       }
+
+       r = 0;
+
+ERROR:
+       if (m)
+               sd_netlink_message_unref(m);
+       if (link)
+               nw_link_unref(link);
 
        return r;
 }
index 5253d694bca215823128020c59b2f7bd7ab7cb61..d44ecb689360767491ec50753e041435cacc4e24 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef NETWORKD_PORT_H
 #define NETWORKD_PORT_H
 
+#include <systemd/sd-netlink.h>
+
 #ifndef IF_NAMESIZE
 #define IF_NAMESIZE 16
 #endif
@@ -45,12 +47,18 @@ typedef struct nw_port nw_port;
 #include "daemon.h"
 
 typedef struct nw_port_ops {
+       // IFLA_INFO_KIND/IFLA_INFO_DATA
+       const char* kind;
+
        // Configuration
        int (*config_read)(nw_port* port);
        int (*config_write)(nw_port* port);
 
+       // Get Parent Port
+       nw_port* (*get_parent_port)(nw_port* port);
+
        // Link
-       int (*create_link)(nw_port* port);
+       int (*create_link)(nw_port* port, sd_netlink_message* message);
        int (*destroy_link)(nw_port* port);
 } nw_port_ops_t;