summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Ovsienko <linux@pilot.org.ua>2007-11-12 14:55:01 +0000
committerDenis Ovsienko <linux@pilot.org.ua>2007-11-12 14:55:01 +0000
commit6ce80bdb2523ad82cef813f6d8a7e0d4daa8cfae (patch)
treed0b0fc8725c9f120cdcc16fa7f711d8104051815
parent3a02d1f7fb778a1ea4f45d037f13dfcd126e2337 (diff)
+ fixed bug #418 (changing address on an existing interface doesn't cause existing static routes to be revalidated)
-rw-r--r--lib/ChangeLog16
-rw-r--r--lib/linklist.c1
-rw-r--r--lib/workqueue.c24
-rw-r--r--lib/workqueue.h11
-rw-r--r--zebra/ChangeLog7
-rw-r--r--zebra/connected.c15
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 <lorenzo@colitti.com>
* 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 ();
}