#include "config.h"
#include "link.h"
#include "logging.h"
-#include "string.h"
#include "port.h"
-
-struct nw_port {
- nw_daemon* daemon;
- int nrefs;
-
- // Link
- nw_link* link;
-
- char name[IF_NAMESIZE];
- nw_port_type_t type;
-
- // Configuration
- nw_config *config;
-
- // Common attributes
- nw_address_t address;
-};
+#include "port-dummy.h"
+#include "port-vlan.h"
+#include "stats-collector.h"
+#include "string.h"
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 },
};
return 0;
}
-static nw_port_type_t nw_port_setup_type(nw_port* port) {
- const char* type = nw_config_get(port->config, "TYPE");
- if (!type)
- return NW_PORT_UNKNOWN;
-
- return nw_port_type_from_string(type);
-}
-
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)
if (r)
goto ERROR;
- // Determine type
- port->type = nw_port_setup_type(port);
- if (!port->type) {
- ERROR("Could not determine type of port %s\n", port->name);
- goto ERROR;
- }
-
// Perform some common initialization
r = nw_port_setup_common(port);
if (r)
goto ERROR;
// Call any custom initialization
- switch (port->type) {
- // These do not need any special initialization
- case NW_PORT_DUMMY:
- case NW_PORT_UNKNOWN:
- break;
+ if (port->ops.config_read) {
+ r = port->ops.config_read(port);
+ if (r)
+ goto ERROR;
}
ERROR:
return r;
}
-int nw_port_create(nw_port** port, nw_daemon* daemon, const char* name) {
+int nw_port_create(nw_port** port, nw_daemon* daemon, nw_port_type_t type, const char* name) {
int r;
// Allocate a new object
// Initialize reference counter
p->nrefs = 1;
+ // Store the type
+ p->type = type;
+
+ // Set operations
+ switch (p->type) {
+ case NW_PORT_DUMMY:
+ p->ops = nw_port_ops_dummy;
+ break;
+
+ case NW_PORT_VLAN:
+ p->ops = nw_port_ops_vlan;
+ break;
+ }
+
// Store the name
r = nw_string_set(p->name, name);
if (r)
return r;
}
+int nw_port_create_from_config(nw_port** port, nw_daemon* daemon,
+ const char* name, const char* path) {
+ nw_config* config = NULL;
+ int r;
+
+ // Initialize the configuration
+ r = nw_config_create(&config, path);
+ if (r)
+ goto ERROR;
+
+ // Fetch the type
+ const char* type = nw_config_get(config, "TYPE");
+ if (!type) {
+ ERROR("Port configuration %s has no TYPE\n", path);
+ r = 1;
+ goto ERROR;
+ }
+
+ // Create a new port
+ r = nw_port_create(port, daemon, nw_port_type_from_string(type), name);
+ if (r)
+ goto ERROR;
+
+ERROR:
+ if (config)
+ nw_config_unref(config);
+
+ return r;
+}
+
nw_port* nw_port_ref(nw_port* port) {
port->nrefs++;
return NULL;
}
+int nw_port_destroy(nw_port* port) {
+ int r;
+
+ DEBUG("Destroying port %s\n", port->name);
+
+ // Destroy the physical link (if exists)
+ if (port->link) {
+ r = nw_link_destroy(port->link);
+ if (r)
+ return r;
+ }
+
+ // Dereference the port from other ports
+ r = nw_daemon_ports_walk(port->daemon, __nw_port_drop_port, port);
+ if (r)
+ return r;
+
+ // Dereference the port from other zones
+ r = nw_daemon_zones_walk(port->daemon, __nw_zone_drop_port, port);
+ if (r)
+ return r;
+
+ // Destroy the configuration
+ r = nw_config_destroy(port->config);
+ if (r)
+ return r;
+
+ // Reset type
+ port->type = NW_PORT_UNKNOWN;
+
+ return 0;
+}
+
+int __nw_port_drop_port(nw_daemon* daemon, nw_port* port, void* data) {
+ nw_port* dropped_port = (nw_port*)data;
+ int r;
+
+ switch (port->type) {
+ case NW_PORT_VLAN:
+ if (port->vlan.parent == dropped_port) {
+ r = nw_port_set_vlan_parent(port, NULL);
+ if (r)
+ return r;
+ }
+ break;
+
+ case NW_PORT_DUMMY:
+ case NW_PORT_UNKNOWN:
+ break;
+ }
+
+ return 0;
+}
+
int nw_port_save(nw_port* port) {
int r;
+ // Call the custom handler
+ if (port->ops.config_write) {
+ r = port->ops.config_write(port);
+ if (r)
+ goto ERROR;
+ }
+
+ // Write the configuration
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) {
return nw_config_get_bool(port->config, "DISABLED");
}
+static int nw_port_create_link(nw_port* port) {
+ int r;
+
+ // Fail if the function isn't set
+ if (!port->ops.create_link) {
+ errno = ENOTSUP;
+ return -errno;
+ }
+
+ // Create the link
+ r = port->ops.create_link(port);
+ if (r)
+ ERROR("Could not create link %s: %m\n", port->name);
+
+ return r;
+}
+
int nw_port_reconfigure(nw_port* port) {
int r;
return 0;
}
+ // If there is no link, we will try to create it
+ if (!port->link) {
+ r = nw_port_create_link(port);
+ if (r)
+ return r;
+ }
+
// XXX TODO
+
+ return 0;
}
int nw_port_has_carrier(nw_port* port) {
return nw_link_has_carrier(port->link);
}
+
+/*
+ Stats
+*/
+
+const struct rtnl_link_stats64* nw_port_get_stats64(nw_port* port) {
+ if (!port->link)
+ return NULL;
+
+ return nw_link_get_stats64(port->link);
+}
+
+int __nw_port_update_stats(nw_daemon* daemon, nw_port* port, void* data) {
+ nw_link* link = (nw_link*)data;
+
+ // Emit stats if link matches
+ if (port->link == link)
+ return nw_stats_collector_emit_port_stats(daemon, port);
+
+ return 0;
+}
+
+int nw_port_update_stats(nw_port* port) {
+ if (port->link)
+ return nw_link_update_stats(port->link);
+
+ return 0;
+}
+
+int nw_port_check_type(nw_port* port, const nw_port_type_t type) {
+ if (port->type == type)
+ return 0;
+
+ errno = ENOTSUP;
+ return -errno;
+}