# #
#############################################################################*/
+#include <linux/if_link.h>
+
+#include <systemd/sd-netlink.h>
+
#include "config.h"
#include "daemon.h"
+#include "json.h"
#include "logging.h"
#include "port.h"
#include "port-vlan.h"
#include "string.h"
-static int nw_port_vlan_config_read(nw_port* port) {
- int r;
+const nw_string_table_t nw_port_vlan_proto[] = {
+ { NW_VLAN_PROTO_8021Q, "802.1Q" },
+ { NW_VLAN_PROTO_8021ad, "802.1ad" },
+ { -1, NULL },
+};
- // 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;
- }
+NW_STRING_TABLE_LOOKUP(nw_port_vlan_proto_t, nw_port_vlan_proto)
- // 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;
+static int nw_port_vlan_read_proto(nw_config* config,
+ const char* key, void* value, void* data) {
+ nw_port_vlan_proto_t* proto = (nw_port_vlan_proto_t*)value;
+
+ const char* p = nw_config_get(config, key);
+ if (p) {
+ *proto = nw_port_vlan_proto_from_string(p);
+ if (!*proto)
+ return -errno;
}
return 0;
}
-static int nw_port_vlan_config_write(nw_port* port) {
+static int nw_port_vlan_write_proto(nw_config* config,
+ const char* key, const void* value, void* data) {
+ const nw_port_vlan_proto_t* proto = (nw_port_vlan_proto_t*)value;
+
+ return nw_config_set(config, key, nw_port_vlan_proto_to_string(*proto));
+}
+
+static int nw_port_vlan_setup(nw_port* port) {
int r;
// VLAN ID
- r = nw_config_set_int(port->config, "VLAN_ID", port->vlan.id);
- if (r)
+ r = NW_CONFIG_OPTION_INT(port->config, "VLAN_ID", &port->vlan.id);
+ if (r < 0)
+ return r;
+
+ // VLAN Protocol
+ r = NW_CONFIG_OPTION(port->config, "VLAN_PROTO", &port->vlan.proto,
+ nw_port_vlan_read_proto, nw_port_vlan_write_proto, NULL);
+ if (r < 0)
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)
+ r = NW_CONFIG_OPTION_STRING(port->config, "VLAN_PARENT", &port->vlan.__parent_name);
+ if (r < 0)
return r;
return 0;
}
-nw_port_ops_t nw_port_ops_vlan = {
- // Configuration
- .config_read = nw_port_vlan_config_read,
- .config_write = nw_port_vlan_config_write,
+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;
+
+ // Set VLAN protocol
+ r = sd_netlink_message_append_u16(m, IFLA_VLAN_PROTOCOL, htobe16(port->vlan.proto));
+ if (r < 0)
+ return r;
+
+ return 0;
+}
+
+static int nw_port_vlan_to_json(nw_port* port, struct json_object* o) {
+ nw_port* parent = NULL;
+ int r;
+
+ // Add the VLAN ID
+ r = json_object_add_int64(o, "VLANId", port->vlan.id);
+ if (r < 0)
+ goto ERROR;
+
+ // Add the VLAN Protocol
+ r = json_object_add_string(o, "VLANProtocol",
+ nw_port_vlan_proto_to_string(port->vlan.proto));
+ if (r < 0)
+ goto ERROR;
+
+ // Fetch the parent
+ parent = nw_port_get_parent_port(port);
+ if (parent) {
+ r = json_object_add_string(o, "VLANParentPort", nw_port_name(parent));
+ if (r < 0)
+ goto ERROR;
+ }
+
+ERROR:
+ if (parent)
+ nw_port_unref(parent);
+
+ return r;
+}
+
+const nw_port_info_t nw_port_info_vlan = {
+ .kind = "vlan",
+
+ // Operations
+ .ops = {
+ // Configuration
+ .setup = nw_port_vlan_setup,
+
+ .get_parent_port = nw_port_get_vlan_parent,
+
+ // Link
+ .create_link = nw_port_vlan_create_link,
+
+ // JSON
+ .to_json = nw_port_vlan_to_json,
+ },
};
/*
return 0;
}
+int nw_port_set_vlan_proto(nw_port* port, const nw_port_vlan_proto_t proto) {
+ switch (proto) {
+ case NW_VLAN_PROTO_8021Q:
+ case NW_VLAN_PROTO_8021ad:
+ port->vlan.proto = proto;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
nw_port* nw_port_get_vlan_parent(nw_port* port) {
int r;