summaryrefslogtreecommitdiff
path: root/interface.c
diff options
context:
space:
mode:
authorHans Dedecker <dedeckeh@gmail.com>2014-02-11 08:30:51 +0000
committerSteven Barth <steven@midlink.org>2014-02-27 12:15:32 +0100
commitf35b76c61baf68dc5dd8440fc06d860f8dfacc44 (patch)
treec04889155d11b42469756d1744f716b7f0dfab25 /interface.c
parent3d26347d0042313be3c9347f8d82c4ccea67fe68 (diff)
downloadnetifd-f35b76c61baf68dc5dd8440fc06d860f8dfacc44.tar.gz
netifd: Link layer state awareness support on interface level
The link layer state is monitored for a given interface; an interface will be setup when both enabled and link layer active. Likewise an interface will be teared down when either disabled or link layer down. Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
Diffstat (limited to 'interface.c')
-rw-r--r--interface.c130
1 files changed, 100 insertions, 30 deletions
diff --git a/interface.c b/interface.c
index b2c8baf..f0fd43f 100644
--- a/interface.c
+++ b/interface.c
@@ -207,6 +207,9 @@ mark_interface_down(struct interface *iface)
{
enum interface_state state = iface->state;
+ if (state == IFS_DOWN)
+ return;
+
iface->state = IFS_DOWN;
if (state == IFS_UP)
interface_event(iface, IFEV_DOWN);
@@ -219,42 +222,112 @@ mark_interface_down(struct interface *iface)
void
__interface_set_down(struct interface *iface, bool force)
{
- if (iface->state == IFS_DOWN ||
- iface->state == IFS_TEARDOWN)
+ switch (iface->state) {
+ case IFS_UP:
+ interface_event(iface, IFEV_DOWN);
+ case IFS_SETUP:
+ iface->state = IFS_TEARDOWN;
+ interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, force);
+ if (force)
+ interface_flush_state(iface);
+
+ if (iface->dynamic)
+ vlist_delete(&interfaces, &iface->node);
+ break;
+
+ case IFS_DOWN:
+ if (iface->main_dev.dev)
+ device_release(&iface->main_dev);
+ case IFS_TEARDOWN:
+ default:
+ break;
+ }
+}
+
+static int
+__interface_set_up(struct interface *iface)
+{
+ int ret;
+
+ netifd_log_message(L_NOTICE, "Interface '%s' is setting up now\n", iface->name);
+
+ iface->state = IFS_SETUP;
+ ret = interface_proto_event(iface->proto, PROTO_CMD_SETUP, false);
+ if (ret)
+ mark_interface_down(iface);
+
+ return ret;
+}
+
+static void
+interface_check_state(struct interface *iface)
+{
+ switch (iface->state) {
+ case IFS_UP:
+ if (!iface->enabled || !iface->link_state) {
+ mark_interface_down(iface);
+ interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, false);
+ }
+ break;
+ case IFS_DOWN:
+ if (iface->enabled && iface->link_state && !config_init)
+ __interface_set_up(iface);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+interface_set_enabled(struct interface *iface, bool new_state)
+{
+ if (iface->enabled == new_state)
return;
- if (iface->state == IFS_UP)
- interface_event(iface, IFEV_DOWN);
- iface->state = IFS_TEARDOWN;
- interface_proto_event(iface->proto, PROTO_CMD_TEARDOWN, force);
- if (force)
- interface_flush_state(iface);
+ netifd_log_message(L_NOTICE, "Interface '%s' is %s\n", iface->name, new_state ? "enabled" : "disabled");
+ iface->enabled = new_state;
+ interface_check_state(iface);
+}
- if (iface->dynamic)
- vlist_delete(&interfaces, &iface->node);
+static void
+interface_set_link_state(struct interface *iface, bool new_state)
+{
+ if (iface->link_state == new_state)
+ return;
+
+ netifd_log_message(L_NOTICE, "Interface '%s' has link connectivity %s\n", iface->name, new_state ? "" : "loss");
+ iface->link_state = new_state;
+ interface_check_state(iface);
}
static void
interface_cb(struct device_user *dep, enum device_event ev)
{
struct interface *iface;
- bool new_state;
+ bool new_state = false;
iface = container_of(dep, struct interface, main_dev);
switch (ev) {
case DEV_EVENT_ADD:
new_state = true;
- break;
case DEV_EVENT_REMOVE:
- new_state = false;
+ interface_set_available(iface, new_state);
+ if (!new_state && dep->dev->external)
+ interface_set_main_dev(iface, NULL);
+ break;
+ case DEV_EVENT_UP:
+ new_state = true;
+ case DEV_EVENT_DOWN:
+ interface_set_enabled(iface, new_state);
+ break;
+ case DEV_EVENT_LINK_UP:
+ new_state = true;
+ case DEV_EVENT_LINK_DOWN:
+ interface_set_link_state(iface, new_state);
break;
default:
- return;
+ break;
}
-
- interface_set_available(iface, new_state);
- if (!new_state && dep->dev->external)
- interface_set_main_dev(iface, NULL);
}
void
@@ -684,7 +757,7 @@ interface_set_l3_dev(struct interface *iface, struct device *dev)
void
interface_set_main_dev(struct interface *iface, struct device *dev)
{
- bool set_l3 = (iface->main_dev.dev == iface->l3_dev.dev);
+ bool set_l3 = (!dev || iface->main_dev.dev == iface->l3_dev.dev);
bool claimed = iface->l3_dev.claimed;
if (iface->main_dev.dev == dev)
@@ -694,8 +767,10 @@ interface_set_main_dev(struct interface *iface, struct device *dev)
interface_set_l3_dev(iface, dev);
device_add_user(&iface->main_dev, dev);
- if (!dev)
+ if (!dev) {
+ interface_set_link_state(iface, false);
return;
+ }
if (claimed)
device_claim(&iface->l3_dev);
@@ -794,18 +869,13 @@ interface_set_up(struct interface *iface)
if (iface->main_dev.dev) {
ret = device_claim(&iface->main_dev);
- if (ret)
- return ret;
- }
-
- iface->state = IFS_SETUP;
- ret = interface_proto_event(iface->proto, PROTO_CMD_SETUP, false);
- if (ret) {
- mark_interface_down(iface);
- return ret;
+ if (!ret)
+ interface_check_state(iface);
}
+ else
+ ret = __interface_set_up(iface);
- return 0;
+ return ret;
}
int