device_remove_user(&alias->dep);
alias->dev.hidden = !dev;
if (dev) {
- alias->dev.ifindex = dev->ifindex;
+ device_set_ifindex(&alias->dev, dev->ifindex);
strcpy(alias->dev.ifname, dev->ifname);
device_broadcast_event(&alias->dev, DEV_EVENT_UPDATE_IFNAME);
device_add_user(&alias->dep, dev);
static void alias_device_cb(struct device_user *dep, enum device_event ev)
{
struct alias_device *alias;
- bool present = false;
+ bool new_state = false;
alias = container_of(dep, struct alias_device, dep);
switch (ev) {
case DEV_EVENT_ADD:
- present = true;
+ new_state = true;
case DEV_EVENT_REMOVE:
- device_set_present(&alias->dev, present);
+ device_set_present(&alias->dev, new_state);
+ break;
+ case DEV_EVENT_LINK_UP:
+ new_state = true;
+ case DEV_EVENT_LINK_DOWN:
+ device_set_link(&alias->dev, new_state);
+ break;
+ case DEV_EVENT_UPDATE_IFINDEX:
+ device_set_ifindex(&alias->dev, dep->dev->ifindex);
break;
default:
device_broadcast_event(&alias->dev, ev);
{
enum interface_state state = iface->state;
+ if (state == IFS_DOWN)
+ return;
+
iface->state = IFS_DOWN;
if (state == IFS_UP)
interface_event(iface, IFEV_DOWN);
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
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)
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);
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
static void vlan_dev_cb(struct device_user *dep, enum device_event ev)
{
struct vlan_device *vldev;
+ bool new_state = false;
vldev = container_of(dep, struct vlan_device, dep);
switch(ev) {
case DEV_EVENT_ADD:
- device_set_present(&vldev->dev, true);
- break;
+ new_state = true;
case DEV_EVENT_REMOVE:
- device_set_present(&vldev->dev, false);
+ device_set_present(&vldev->dev, new_state);
+ break;
+ case DEV_EVENT_LINK_UP:
+ new_state = true;
+ case DEV_EVENT_LINK_DOWN:
+ device_set_link(&vldev->dev, new_state);
break;
case DEV_EVENT_UPDATE_IFNAME:
vlan_dev_set_name(vldev, dep->dev);
if (!create)
return NULL;
+ D(DEVICE, "Create vlan device '%s.%d'\n", dev->ifname, id);
+
vldev = calloc(1, sizeof(*vldev));
vldev->id = id;