From 2f7d32a6371c97716578b6a6d910df673d1db1f9 Mon Sep 17 00:00:00 2001 From: Hans Dedecker Date: Mon, 7 Apr 2014 13:30:51 +0200 Subject: [PATCH] netifd: Rework hotplug event queueing in case of congestion In case of event congestion (e.g. when several interfaces become active in a short notice) : -hotplug events will be handled on a first come first served basis (before it was lifo) -drop a new ifupdate event in favour of an already queued ifup event (before the ifup event was overwritten by the ifupdate event resulting in some hotplug scripts "missing" the ifup event) Additonal the event flow has been documented Signed-off-by: Hans Dedecker Signed-off-by: Joeri Barbarien --- interface-event.c | 73 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 58 insertions(+), 15 deletions(-) diff --git a/interface-event.c b/interface-event.c index c524ee2..82c274d 100644 --- a/interface-event.c +++ b/interface-event.c @@ -30,6 +30,7 @@ static void task_complete(struct uloop_process *proc, int ret); static struct uloop_process task = { .cb = task_complete, }; +char *eventnames[] = {"ifdown", "ifup", "ifupdate"}; static void run_cmd(const char *ifname, const char *device, enum interface_event event, @@ -48,7 +49,6 @@ run_cmd(const char *ifname, const char *device, enum interface_event event, return; } - char *eventnames[] = {"ifdown", "ifup", "ifupdate"}; setenv("ACTION", eventnames[event], 1); setenv("INTERFACE", ifname, 1); if (device) @@ -86,7 +86,8 @@ call_hotplug(void) if (current_ev == IFEV_UP && current->l3_dev.dev) device = current->l3_dev.dev->ifname; - D(SYSTEM, "Call hotplug handler for interface '%s' (%s)\n", current->name, device ? device : "none"); + D(SYSTEM, "Call hotplug handler for interface '%s', event '%s' (%s)\n", + current->name, eventnames[current_ev], device ? device : "none"); run_cmd(current->name, device, current_ev, current->updated); } @@ -109,24 +110,66 @@ task_complete(struct uloop_process *proc, int ret) static void interface_queue_event(struct interface *iface, enum interface_event ev) { - enum interface_event last_ev; - - D(SYSTEM, "Queue hotplug handler for interface '%s'\n", iface->name); + D(SYSTEM, "Queue hotplug handler for interface '%s', event '%s'\n", + iface->name, eventnames[ev]); if (ev == IFEV_UP || ev == IFEV_DOWN) netifd_ubus_interface_event(iface, ev == IFEV_UP); netifd_ubus_interface_notify(iface, ev != IFEV_DOWN); - if (current == iface) - last_ev = current_ev; - else - last_ev = iface->hotplug_ev; - - iface->hotplug_ev = ev; - if ((last_ev == ev && ev != IFEV_UPDATE) && !list_empty(&iface->hotplug_list)) - list_del_init(&iface->hotplug_list); - else if ((last_ev != ev || ev == IFEV_UPDATE) && list_empty(&iface->hotplug_list)) - list_add(&iface->hotplug_list, &pending); + if (current == iface) { + /* an event for iface is being processed */ + if (!list_empty(&iface->hotplug_list)) { + /* an additional event for iface is pending */ + if ((ev != current_ev || ev == IFEV_UPDATE) && + !(iface->hotplug_ev == IFEV_UP && ev == IFEV_UPDATE)) { + /* if incoming event is different from the one + * being handled or if it is an update, + * overwrite pending event, but never + * overwrite an ifup with an ifupdate */ + iface->hotplug_ev = ev; + } + else if (ev == current_ev && ev != IFEV_UPDATE) { + /* if incoming event is not an ifupdate + * and is the same as the one that is + * being handled, remove it from the + * pending list */ + list_del_init(&iface->hotplug_list); + } + } + else { + /* no additional event for iface is pending */ + if (ev != current_ev || ev == IFEV_UPDATE) { + /* only add the interface to the pending list if + * the event is different from the one being + * handled or if it is an update */ + iface->hotplug_ev = ev; + /* Handle hotplug calls FIFO */ + list_add_tail(&iface->hotplug_list, &pending); + } + } + } + else { + /* currently not handling an event or handling an event + * for another interface */ + if (!list_empty(&iface->hotplug_list)) { + /* an event for iface is pending */ + if (!(iface->hotplug_ev == IFEV_UP && + ev == IFEV_UPDATE)) { + /* overwrite pending event, unless the incoming + * event is an ifupdate while the pending one + * is an ifup */ + iface->hotplug_ev = ev; + } + } + else { + /* an event for the interface is not yet pending, + * queue it */ + iface->hotplug_ev = ev; + /* Handle hotplug calls FIFO */ + list_add_tail(&iface->hotplug_list, &pending); + } + } if (!task.pending && !current) call_hotplug(); -- 2.30.2