From 240e331b2043ae254c6468ed3ce2ec6d8caf98db Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Sun, 4 Jun 2023 16:26:44 +0000 Subject: [PATCH] ports: Implement creating links from ports Signed-off-by: Michael Tremer --- src/networkd/port-dummy.c | 5 +- src/networkd/port-vlan.c | 20 +++++ src/networkd/port.c | 149 +++++++++++++++++++++++++++++++++++--- src/networkd/port.h | 10 ++- 4 files changed, 170 insertions(+), 14 deletions(-) diff --git a/src/networkd/port-dummy.c b/src/networkd/port-dummy.c index cc4b649d..09367d83 100644 --- a/src/networkd/port-dummy.c +++ b/src/networkd/port-dummy.c @@ -18,11 +18,8 @@ # # #############################################################################*/ -#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", }; diff --git a/src/networkd/port-vlan.c b/src/networkd/port-vlan.c index c9581f68..edf91d91 100644 --- a/src/networkd/port-vlan.c +++ b/src/networkd/port-vlan.c @@ -18,6 +18,8 @@ # # #############################################################################*/ +#include + #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, }; /* diff --git a/src/networkd/port.c b/src/networkd/port.c index b3b7d668..a7cbab63 100644 --- a/src/networkd/port.c +++ b/src/networkd/port.c @@ -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; } diff --git a/src/networkd/port.h b/src/networkd/port.h index 5253d694..d44ecb68 100644 --- a/src/networkd/port.h +++ b/src/networkd/port.h @@ -21,6 +21,8 @@ #ifndef NETWORKD_PORT_H #define NETWORKD_PORT_H +#include + #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; -- 2.47.3