]> git.ipfire.org Git - network.git/blobdiff - src/networkd/port.c
port: Implement reading/writing VLAN settings
[network.git] / src / networkd / port.c
index aad62106a60cb7cfc0d4bec79c06e2061ab65d31..a240c6118a6b0af501b23eef7aba7f32c8520b81 100644 (file)
@@ -40,21 +40,32 @@ struct nw_port {
        // Link
        nw_link* link;
 
-       char name[IF_NAMESIZE];
        nw_port_type_t type;
+       char name[IF_NAMESIZE];
 
        // Configuration
        nw_config *config;
 
        // Common attributes
        nw_address_t address;
+
+       // VLAN settings
+       struct nw_port_vlan {
+               nw_port* parent;
+               int id;
+
+               // If the parent has not been read from the configuration we will
+               // save the name and try to find it later.
+               char __parent_name[IF_NAMESIZE];
+       } vlan;
 };
 
 static const struct nw_port_type_map {
        nw_port_type_t type;
        const char* name;
 } nw_port_type_map[] = {
-       { NW_PORT_DUMMY, "dummy" },
+       { NW_PORT_DUMMY,   "dummy" },
+       { NW_PORT_VLAN,    "vlan" },
        { NW_PORT_UNKNOWN, NULL },
 };
 
@@ -128,6 +139,28 @@ static int nw_port_setup_common(nw_port* port) {
        return 0;
 }
 
+static int nw_port_setup_vlan(nw_port* port) {
+       int r;
+
+       // VLAN ID
+       int id = nw_config_get_int(port->config, "VLAN_ID", NW_VLAN_ID_INVALID);
+       if (id) {
+               r = nw_port_set_vlan_id(port, id);
+               if (r)
+                       return r;
+       }
+
+       // Parent Port
+       const char* parent = nw_config_get(port->config, "VLAN_PARENT");
+       if (parent) {
+               r = nw_string_set(port->vlan.__parent_name, parent);
+               if (r)
+                       return r;
+       }
+
+       return 0;
+}
+
 static int nw_port_set_link(nw_port* port, nw_link* link) {
        // Do nothing if the same link is being re-assigned
        if (port->link == link)
@@ -183,6 +216,12 @@ static int nw_port_setup(nw_port* port) {
 
        // Call any custom initialization
        switch (port->type) {
+               case NW_PORT_VLAN:
+                       r = nw_port_setup_vlan(port);
+                       if (r)
+                               goto ERROR;
+                       break;
+
                // These do not need any special initialization
                case NW_PORT_DUMMY:
                case NW_PORT_UNKNOWN:
@@ -275,14 +314,50 @@ nw_port* nw_port_unref(nw_port* port) {
        return NULL;
 }
 
+static int nw_port_save_vlan(nw_port* port) {
+       int r;
+
+       // VLAN ID
+       r = nw_config_set_int(port->config, "VLAN_ID", port->vlan.id);
+       if (r)
+               return r;
+
+       // Parent Port
+       r = nw_config_set(port->config, "VLAN_PARENT",
+               (port->vlan.parent) ? nw_port_name(port->vlan.parent) : port->vlan.__parent_name);
+       if (r)
+               return r;
+
+       return 0;
+}
+
 int nw_port_save(nw_port* port) {
        int r;
 
+       switch (port->type) {
+               // VLAN
+               case NW_PORT_VLAN:
+                       r = nw_port_save_vlan(port);
+                       if (r)
+                               goto ERROR;
+                       break;
+
+               // These types do not have any special settings
+               case NW_PORT_DUMMY:
+               case NW_PORT_UNKNOWN:
+                       break;
+       }
+
        r = nw_config_write(port->config);
        if (r)
                return r;
 
        return 0;
+
+ERROR:
+       ERROR("Could not save configuration for port %s: %m\n", port->name);
+
+       return 1;
 }
 
 const char* nw_port_name(nw_port* port) {
@@ -404,3 +479,90 @@ int nw_port_update_stats(nw_port* port) {
 
        return 0;
 }
+
+static int nw_port_check_type(nw_port* port, const nw_port_type_t type) {
+       if (port->type == type)
+               return 0;
+
+       errno = ENOTSUP;
+       return -errno;
+}
+
+/*
+       VLAN
+*/
+int nw_port_get_vlan_id(nw_port* port) {
+       int r;
+
+       // Check type
+       r = nw_port_check_type(port, NW_PORT_VLAN);
+       if (r < 0)
+               return r;
+
+       return port->vlan.id;
+}
+
+int nw_port_set_vlan_id(nw_port* port, int id) {
+       int r;
+
+       // Check type
+       r = nw_port_check_type(port, NW_PORT_VLAN);
+       if (r < 0)
+               return r;
+
+       // Check if the VLAN ID is within range
+       if (id < NW_VLAN_ID_MIN || id > NW_VLAN_ID_MAX)
+               return -EINVAL;
+
+       // Store the ID
+       port->vlan.id = id;
+
+       DEBUG("Port %s: Set VLAN ID to %d\n", port->name, port->vlan.id);
+
+       return 0;
+}
+
+nw_port* nw_port_get_vlan_parent(nw_port* port) {
+       int r;
+
+       // Check type
+       r = nw_port_check_type(port, NW_PORT_VLAN);
+       if (r < 0)
+               return NULL;
+
+       // Try to find a reference to the parent if none exists
+       if (!port->vlan.parent && *port->vlan.__parent_name)
+               port->vlan.parent = nw_daemon_get_port_by_name(port->daemon, port->vlan.__parent_name);
+
+       if (port->vlan.parent)
+               return nw_port_ref(port->vlan.parent);
+
+       // No port found
+       return NULL;
+}
+
+int nw_port_set_vlan_parent(nw_port* port, nw_port* parent) {
+       int r;
+
+       // Check type
+       r = nw_port_check_type(port, NW_PORT_VLAN);
+       if (r < 0)
+               return r;
+
+       // Reset the former parent name
+       nw_string_empty(port->vlan.__parent_name);
+
+       // Dereference the former parent
+       if (port->vlan.parent) {
+               nw_port_unref(port->vlan.parent);
+               port->vlan.parent = NULL;
+       }
+
+       // Store the new parent
+       if (parent)
+               port->vlan.parent = nw_port_ref(parent);
+
+       DEBUG("Port %s: Set VLAN parent to %s\n", port->name, nw_port_name(port->vlan.parent));
+
+       return 0;
+}