From 6ce80bdb2523ad82cef813f6d8a7e0d4daa8cfae Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 12 Nov 2007 14:55:01 +0000 Subject: + fixed bug #418 (changing address on an existing interface doesn't cause existing static routes to be revalidated) --- lib/ChangeLog | 16 ++++++++++++++++ lib/linklist.c | 1 + lib/workqueue.c | 24 +++++++++++++++++++----- lib/workqueue.h | 11 +++++------ zebra/ChangeLog | 7 +++++++ zebra/connected.c | 15 +++++++++++++++ 6 files changed, 63 insertions(+), 11 deletions(-) diff --git a/lib/ChangeLog b/lib/ChangeLog index 0725f795..bd66f071 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,19 @@ +2007-11-12 Denis Ovsienko + + * linklist.c: (listnode_add_after) Don't forget to increment list + items counter. + * workqueue.h: Changed working queue flags from enum into integer + and introduced WQ_AIM_HEAD flag to indicate our will to insert + new data before the list head. + * workqueue.[ch]: (work_queue_schedule, show_work_queues, + work_queue_plug, work_queue_unplug) Adjust to the new flags style. + * workqueue.[ch]: (work_queue_aim_head) new function to control the + WQ_AIM_HEAD flag + * workqueue.[ch]: (work_queue_new) Explicitly set both WQ flags + during new WQ initialization. + * workqueue.[ch]: (work_queue_add) If WQ_AIM_HEAD indicates a need + to place the new data into list head, do it. + 2007-10-22 Lorenzo Colitti * smux.c: (smux_stop) Avoid cancelling a defunct thread pointer diff --git a/lib/linklist.c b/lib/linklist.c index 11e16a8a..983da2d1 100644 --- a/lib/linklist.c +++ b/lib/linklist.c @@ -158,6 +158,7 @@ listnode_add_after (struct list *list, struct listnode *pp, void *val) pp->next = nn; } + list->count++; } diff --git a/lib/workqueue.c b/lib/workqueue.c index a0f48bc8..8880b9e2 100644 --- a/lib/workqueue.c +++ b/lib/workqueue.c @@ -66,6 +66,8 @@ work_queue_new (struct thread_master *m, const char *queue_name) new->name = XSTRDUP (MTYPE_WORK_QUEUE_NAME, queue_name); new->master = m; + SET_FLAG (new->flags, WQ_UNPLUGGED); + UNSET_FLAG (new->flags, WQ_AIM_HEAD); if ( (new->items = list_new ()) == NULL) { @@ -103,7 +105,7 @@ static inline int work_queue_schedule (struct work_queue *wq, unsigned int delay) { /* if appropriate, schedule work queue thread */ - if ( (wq->flags == WQ_UNPLUGGED) + if ( CHECK_FLAG (wq->flags, WQ_UNPLUGGED) && (wq->thread == NULL) && (listcount (wq->items) > 0) ) { @@ -129,7 +131,10 @@ work_queue_add (struct work_queue *wq, void *data) } item->data = data; - listnode_add (wq->items, item); + if (CHECK_FLAG (wq->flags, WQ_AIM_HEAD)) + listnode_add_after (wq->items, NULL, item); + else + listnode_add (wq->items, item); work_queue_schedule (wq, wq->spec.hold); @@ -186,7 +191,7 @@ DEFUN(show_work_queues, for (ALL_LIST_ELEMENTS_RO ((&work_queues), node, wq)) { vty_out (vty,"%c %8d %5d %8ld %7d %6d %6u %s%s", - (wq->flags == WQ_PLUGGED ? 'P' : ' '), + (CHECK_FLAG (wq->flags, WQ_UNPLUGGED) ? ' ' : 'P'), listcount (wq->items), wq->spec.hold, wq->runs, @@ -211,7 +216,7 @@ work_queue_plug (struct work_queue *wq) wq->thread = NULL; - wq->flags = WQ_PLUGGED; + UNSET_FLAG (wq->flags, WQ_UNPLUGGED); } /* unplug queue, schedule it again, if appropriate @@ -220,12 +225,21 @@ work_queue_plug (struct work_queue *wq) void work_queue_unplug (struct work_queue *wq) { - wq->flags = WQ_UNPLUGGED; + SET_FLAG (wq->flags, WQ_UNPLUGGED); /* if thread isnt already waiting, add one */ work_queue_schedule (wq, wq->spec.hold); } +void +work_queue_aim_head (struct work_queue *wq, const unsigned aim_head) +{ + if (aim_head) + SET_FLAG (wq->flags, WQ_AIM_HEAD); + else + UNSET_FLAG (wq->flags, WQ_AIM_HEAD); +} + /* timer thread to process a work queue * will reschedule itself if required, * otherwise work_queue_item_add diff --git a/lib/workqueue.h b/lib/workqueue.h index 7e0e78ab..3150c32e 100644 --- a/lib/workqueue.h +++ b/lib/workqueue.h @@ -47,11 +47,8 @@ struct work_queue_item unsigned short ran; /* # of times item has been run */ }; -enum work_queue_flags -{ - WQ_UNPLUGGED = 0, - WQ_PLUGGED = 1, -}; +#define WQ_UNPLUGGED (1 << 0) /* available for draining */ +#define WQ_AIM_HEAD (1 << 1) /* add new items before list head, not after tail */ struct work_queue { @@ -101,7 +98,7 @@ struct work_queue } cycles; /* cycle counts */ /* private state */ - enum work_queue_flags flags; /* user set flag */ + u_int16_t flags; /* user set flag */ }; /* User API */ @@ -122,6 +119,8 @@ extern void work_queue_add (struct work_queue *, void *); extern void work_queue_plug (struct work_queue *wq); /* unplug the queue, allow it to be drained again */ extern void work_queue_unplug (struct work_queue *wq); +/* control the value for WQ_AIM_HEAD flag */ +extern void work_queue_aim_head (struct work_queue *wq, const unsigned); /* Helpers, exported for thread.c and command.c */ extern int work_queue_run (struct thread *); diff --git a/zebra/ChangeLog b/zebra/ChangeLog index e152729d..3ce7b9ea 100644 --- a/zebra/ChangeLog +++ b/zebra/ChangeLog @@ -1,3 +1,10 @@ +2007-11-12 Denis Ovsienko + + * connected.c: (connected_up_ipv4, connected_down_ipv4, + connected_up_ipv6, connected_down_ipv6) Collect all changed + connected routes closest possible to the RIB work queue, so + that the rest can be revalidated correctly. + 2007-10-24 Denis Ovsienko * kernel_socket.c: (rtm_read) we used to ignore own messages, diff --git a/zebra/connected.c b/zebra/connected.c index 53aa2543..8bf1d337 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -35,6 +35,7 @@ #include "zebra/redistribute.h" #include "zebra/interface.h" #include "zebra/connected.h" +extern struct zebra_t zebrad; /* withdraw a connected address */ static void @@ -187,8 +188,15 @@ connected_up_ipv4 (struct interface *ifp, struct connected *ifc) if (prefix_ipv4_any (&p)) return; + /* Always push arriving/departing connected routes into the head of + * the working queue to make possible proper validation of the rest + * of the RIB queue (which will contain the whole RIB after the first + * call to rib_update()). + */ + work_queue_aim_head (zebrad.ribq, 1); rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex, RT_TABLE_MAIN, ifp->metric, 0); + work_queue_aim_head (zebrad.ribq, 0); rib_update (); } @@ -293,7 +301,10 @@ connected_down_ipv4 (struct interface *ifp, struct connected *ifc) if (prefix_ipv4_any (&p)) return; + /* Same logic as for connected_up_ipv4(): push the changes into the head. */ + work_queue_aim_head (zebrad.ribq, 1); rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + work_queue_aim_head (zebrad.ribq, 0); rib_update (); } @@ -338,8 +349,10 @@ connected_up_ipv6 (struct interface *ifp, struct connected *ifc) return; #endif + work_queue_aim_head (zebrad.ribq, 1); rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, ifp->metric, 0); + work_queue_aim_head (zebrad.ribq, 0); rib_update (); } @@ -413,7 +426,9 @@ connected_down_ipv6 (struct interface *ifp, struct connected *ifc) if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix)) return; + work_queue_aim_head (zebrad.ribq, 1); rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0); + work_queue_aim_head (zebrad.ribq, 0); rib_update (); } -- cgit v1.2.1