# #
#############################################################################*/
+#include <linux/if.h>
#include <stddef.h>
#include <stdlib.h>
+#include <string.h>
#include <systemd/sd-netlink.h>
#include "link.h"
#include "links.h"
#include "logging.h"
+#include "string.h"
struct nw_link {
- struct nw_daemon* daemon;
+ nw_daemon* daemon;
int nrefs;
// Interface Index
int ifindex;
+
+ // Interface Name
+ char ifname[IFNAMSIZ];
+
+ // MTU
+ uint32_t mtu;
+ uint32_t min_mtu;
+ uint32_t max_mtu;
+
+ // Flags
+ unsigned int flags;
+ uint8_t operstate;
};
-int nw_link_create(struct nw_link** link, struct nw_daemon* daemon, int ifindex) {
+int nw_link_create(nw_link** link, nw_daemon* daemon, int ifindex) {
// Allocate a new object
- struct nw_link* l = calloc(1, sizeof(*l));
+ nw_link* l = calloc(1, sizeof(*l));
if (!l)
return 1;
return 0;
}
-static void nw_link_free(struct nw_link* link) {
+static void nw_link_free(nw_link* link) {
DEBUG("Freeing link (ifindex = %d)\n", link->ifindex);
if (link->daemon)
nw_daemon_unref(link->daemon);
}
-struct nw_link* nw_link_ref(struct nw_link* link) {
+nw_link* nw_link_ref(nw_link* link) {
link->nrefs++;
return link;
}
-struct nw_link* nw_link_unref(struct nw_link* link) {
+nw_link* nw_link_unref(nw_link* link) {
if (--link->nrefs > 0)
return link;
return NULL;
}
-int nw_link_ifindex(struct nw_link* link) {
+int nw_link_ifindex(nw_link* link) {
return link->ifindex;
}
+// Carrier
+
+int nw_link_has_carrier(nw_link* link) {
+ return link->operstate == IF_OPER_UP;
+}
+
+static int nw_link_carrier_gained(nw_link* link) {
+ return 0; // XXX TODO
+}
+
+static int nw_link_carrier_lost(nw_link* link) {
+ return 0; // XXX TODO
+}
+
+static int nw_link_update_ifname(nw_link* link, sd_netlink_message* message) {
+ const char* ifname = NULL;
+ int r;
+
+ r = sd_netlink_message_read_string(message, IFLA_IFNAME, &ifname);
+ if (r < 0) {
+ ERROR("Could not read link name for link %d: %m\n", link->ifindex);
+ return 1;
+ }
+
+ // Do nothing if the name is already set
+ if (strcmp(link->ifname, ifname) == 0)
+ return 0;
+
+ // Otherwise update the name
+ r = nw_string_set(link->ifname, ifname);
+ if (r) {
+ ERROR("Could not set link name: %m\n");
+ return 1;
+ }
+
+ DEBUG("Link %d has been renamed to '%s'\n", link->ifindex, link->ifname);
+
+ return 0;
+}
+
+static int nw_link_update_mtu(nw_link* link, sd_netlink_message* message) {
+ uint32_t mtu = 0;
+ uint32_t min_mtu = 0;
+ uint32_t max_mtu = 0;
+ int r;
+
+ // Read the MTU
+ r = sd_netlink_message_read_u32(message, IFLA_MTU, &mtu);
+ if (r < 0) {
+ ERROR("Could not read MTU for link %d: %m\n", link->ifindex);
+ return r;
+ }
+
+ // Read the minimum MTU
+ r = sd_netlink_message_read_u32(message, IFLA_MIN_MTU, &min_mtu);
+ if (r < 0) {
+ ERROR("Could not read the minimum MTU for link %d: %m\n", link->ifindex);
+ return r;
+ }
+
+ // Read the maximum MTU
+ r = sd_netlink_message_read_u32(message, IFLA_MAX_MTU, &max_mtu);
+ if (r < 0) {
+ ERROR("Could not read the maximum MTU for link %d: %m\n", link->ifindex);
+ return r;
+ }
+
+ // Set the maximum MTU to infinity
+ if (!max_mtu)
+ max_mtu = UINT32_MAX;
+
+ // Store min/max MTU
+ link->min_mtu = min_mtu;
+ link->max_mtu = max_mtu;
+
+ // End here, if the MTU has not been changed
+ if (link->mtu == mtu)
+ return 0;
+
+ DEBUG("Link %d: MTU has changed to %" PRIu32 " (min: %" PRIu32 ", max: %" PRIu32 ")\n",
+ link->ifindex, link->mtu, link->min_mtu, link->max_mtu);
+
+ // Store MTU
+ link->mtu = mtu;
+
+ return 0;
+}
+
+static int nw_link_update_flags(nw_link* link, sd_netlink_message* message) {
+ unsigned int flags = 0;
+ uint8_t operstate = 0;
+ int r;
+
+ // Fetch flags
+ r = sd_rtnl_message_link_get_flags(message, &flags);
+ if (r < 0) {
+ return DEBUG("Could not read link flags: %m\n");
+ return 1;
+ }
+
+ // Fetch operstate
+ r = sd_netlink_message_read_u8(message, IFLA_OPERSTATE, &operstate);
+ if (r < 1) {
+ ERROR("Could not read operstate: %m\n");
+ return 1;
+ }
+
+ // End here if there have been no changes
+ if (link->flags == flags && link->operstate == operstate)
+ return 0;
+
+ // XXX We should log any changes here
+
+ // Fetch current carrier state
+ const int had_carrier = nw_link_has_carrier(link);
+
+ // Store the new flags & operstate
+ link->flags = flags;
+ link->operstate = operstate;
+
+ // Notify if carrier was gained or lost
+ if (!had_carrier && nw_link_has_carrier(link)) {
+ r = nw_link_carrier_gained(link);
+ if (r < 0)
+ return r;
+
+ } else if (had_carrier && !nw_link_has_carrier(link)) {
+ r = nw_link_carrier_lost(link);
+ if (r < 0)
+ return r;
+ }
+
+ return 0;
+}
+
+/*
+ This function is called whenever anything changes, so that we can
+ update our internal link object.
+*/
+static int nw_link_update(nw_link* link, sd_netlink_message* message) {
+ int r;
+
+ // Update the interface name
+ r = nw_link_update_ifname(link, message);
+ if (r)
+ return r;
+
+ // Update the MTU
+ r = nw_link_update_mtu(link, message);
+ if (r)
+ return r;
+
+ // Update flags
+ r = nw_link_update_flags(link, message);
+ if (r)
+ return r;
+
+ return 0;
+}
+
int nw_link_process(sd_netlink* rtnl, sd_netlink_message* message, void* data) {
- struct nw_links* links = NULL;
- struct nw_link* link = NULL;
+ nw_links* links = NULL;
+ nw_link* link = NULL;
const char* ifname = NULL;
int ifindex;
uint16_t type;
int r;
- struct nw_daemon* daemon = (struct nw_daemon*)data;
+ nw_daemon* daemon = (nw_daemon*)data;
// Fetch links
links = nw_daemon_links(daemon);
ERROR("Could not create link: %m\n");
goto ERROR;
}
- }
- // TODO Import any data from the netlink message
+ // Add it to the list
+ r = nw_links_add_link(links, link);
+ if (r)
+ goto ERROR;
+ }
- // Add it to the list
- r = nw_links_add_link(links, link);
+ // Import any data from the netlink message
+ r = nw_link_update(link, message);
if (r)
goto ERROR;