// 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;
}
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;
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;
}
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;
}