From 27b472533bc8bb0fdb37dcda7596c385d3b9f414 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Sun, 2 Jul 2006 16:38:54 +0000 Subject: [zebra] Fix CID #104, check addr for null, and #18, check nexthop type args 2006-07-02 Paul Jakma * rt_netlink.c: (netlink_interface_addr) Fix CID #104, can not proceed if addr is NULL. * zebra_rib.c: (static_add_ipv6) Fix CID #18, double check required arguments are supplied for the given nexthop type. --- zebra/zebra_rib.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 330bce77..9851cf44 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -2145,6 +2145,14 @@ static_add_ipv6 (struct prefix *p, u_char type, struct in6_addr *gate, stable = vrf_static_table (AFI_IP6, SAFI_UNICAST, vrf_id); if (! stable) return -1; + + if (!gate && + (type == STATIC_IPV6_GATEWAY || type == STATIC_IPV6_GATEWAY_IFNAME)) + return -1; + + if (!ifname && + (type == STATIC_IPV6_GATEWAY_IFNAME || type == STATIC_IPV6_IFNAME)) + return -1; /* Lookup static route prefix. */ rn = route_node_get (stable, p); -- cgit v1.2.3 From 171eee31edbddbd8906447dc8725e0513227d013 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 27 Jul 2006 16:11:02 +0000 Subject: [zebra] Connected routes must always be added to main table 2006-07-27 Rumen Svobodnikov * connected.c: (connected_up_ipv4) interface connected routes always go to table main (or otherwise they cannot be used by linux as nexthops) * zserv.c: (zread_ipv4_add) send route to the correct routing table * zebra_rib.c (static_install_ipv4) set routing table --- zebra/zebra_rib.c | 1 + 1 file changed, 1 insertion(+) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 9851cf44..665e5673 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1482,6 +1482,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) rib->distance = si->distance; rib->metric = 0; rib->nexthop_num = 0; + rib->table = zebrad.rtm_table_default; switch (si->type) { -- cgit v1.2.3 From 457eb9af72e6e7aa85c26b65ba4d053f9ecbffac Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 27 Jul 2006 19:59:58 +0000 Subject: [zebra] Add test rig code, for testing the zebra RIB 2006-07-27 Paul Jakma * {ioctl,kernel}_null.c: Dummy/Null kernel method implementations, useful for testing zebra code that calls such methods. * {redistribute,misc}_null.c: Dummy/Null methods, as above. But for zclient, and for various misc functions. * test_main.c: Test harness for zebra, currently just to test the RIB. * Makefile.am: Build testzebra using above. * zebra_rib.c: Add a global for the workqueue hold time, useful for testing. --- zebra/zebra_rib.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 665e5673..7373c6d8 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -42,6 +42,12 @@ /* Default rtm_table for all clients */ extern struct zebra_t zebrad; +/* Hold time for RIB process, should be very minimal. + * it is useful to able to set it otherwise for testing, hence exported + * as global here for test-rig code. + */ +int rib_process_hold_time = 10; + /* Each route type's string and default distance value. */ struct { @@ -1120,6 +1126,7 @@ rib_queue_init (struct zebra_t *zebra) zebra->ribq->spec.del_item_data = &rib_queue_qnode_del; /* XXX: TODO: These should be runtime configurable via vty */ zebra->ribq->spec.max_retries = 3; + zebra->ribq->spec.hold = rib_process_hold_time; return; } -- cgit v1.2.3 From 6d691129594f87958ecaf4169b2e1f62f90d3616 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Thu, 27 Jul 2006 21:49:00 +0000 Subject: [zebra] Bug #268, Fix race between add/delete of routes, sanitise rib queueing 2006-07-27 Paul Jakma * rib.h: (struct rib) Add a route_node rn_status flag field, this has to be copied every time head RIB of a route_node changes. Remove the rib lock field, not needed - see below. Add a status field for RIB-private flags. * zebra_rib.c: Add a global for the workqueue hold time, useful for testing. (general) Fix for bug #268. Problem originally detailed by Simon Bryden in [quagga-dev 4001]. Essentially, add/delete of a RIB must happen /before/ the queue. Best-path selection (ie rib_process) and reaping of freed RIBs can then be done after queueing. Only the route_node is queued - no important RIB state (i.e. whether a RIB is to be deleted) is queued. (struct zebra_queue_node_t) Disappears, no longer need to track multiple things on the queue, only the route_node. (rib_{lock,unlock}) removed, RIBs no longer need to be refcounted, no longer queued. (rib_queue_qnode_del) Removed, deleted RIBs no longer deleted via the queue. (rib_queue_add_qnode) deleted (rib_queue_add) Only the route_node is queued for best-path selection, we can check whether it is already queued or not and avoid queueing same node twice - struct rib * argument is not needed. (rib_link/unlink) (un)link RIB from route_node. (rib_{add,del}node) Front-end to updates of a RIB. (rib_process) Reap any deleted RIBs via rib_unlink. Unset the route_node 'QUEUED' flag. (General) Remove calls to rib_queue_add where add/del node was called - not needed, update calls where not. Ignore RIB_ENTRY_REMOVEd ribs in loops through route_nodes --- zebra/zebra_rib.c | 421 ++++++++++++++++++++++++++++++++---------------------- 1 file changed, 251 insertions(+), 170 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 7373c6d8..acad065a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -66,12 +66,6 @@ struct {ZEBRA_ROUTE_ISIS, 115}, {ZEBRA_ROUTE_BGP, 20 /* IBGP is 200. */} }; - -struct zebra_queue_node_t -{ - struct route_node *node; - struct rib *del; -}; /* Vector for routing table. */ vector vrf_vector; @@ -791,37 +785,6 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) -static struct rib * -rib_lock (struct rib *rib) -{ - assert (rib->lock >= 0); - - rib->lock++; - return rib; -} - -static struct rib * -rib_unlock (struct rib *rib) -{ - struct nexthop *nexthop; - struct nexthop *next; - - assert (rib->lock > 0); - rib->lock--; - - if (rib->lock == 0) - { - for (nexthop = rib->nexthop; nexthop; nexthop = next) - { - next = nexthop->next; - nexthop_free (nexthop); - } - XFREE (MTYPE_RIB, rib); - return NULL; - } - return rib; -} - static void rib_install_kernel (struct route_node *rn, struct rib *rib) { @@ -885,37 +848,50 @@ rib_uninstall (struct route_node *rn, struct rib *rib) } } +static void rib_unlink (struct route_node *, struct rib *); + /* Core function for processing routing information base. */ static wq_item_status rib_process (struct work_queue *wq, void *data) { - struct zebra_queue_node_t *qnode = data; struct rib *rib; struct rib *next; struct rib *fib = NULL; struct rib *select = NULL; - struct rib *del = qnode->del; - struct route_node *rn = qnode->node; + struct rib *del = NULL; + struct route_node *rn = data; int installed = 0; struct nexthop *nexthop = NULL; assert (rn); - /* possibly should lock and unlock rib on each iteration. however, for - * now, we assume called functions are synchronous and dont delete RIBs - * (as the work-queue deconstructor for this function is supposed to be - * the canonical 'delete' path for RIBs). Further if called functions - * below were to made asynchronous they should themselves acquire any - * locks/refcounts as needed and not depend on this caller to do it for - * them - */ for (rib = rn->info; rib; rib = next) { next = rib->next; /* Currently installed rib. */ if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - fib = rib; + { + assert (fib == NULL); + fib = rib; + } + + /* Unlock removed routes, so they'll be freed, bar the FIB entry, + * which we need to do do further work with below. + */ + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + { + if (rib != fib) + { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: rn %p, removing rib %p", __func__, rn, rib); + rib_unlink (rn, rib); + } + else + del = rib; + + continue; + } /* Skip unreachable nexthop. */ if (! nexthop_active_update (rn, rib, 0)) @@ -968,19 +944,12 @@ rib_process (struct work_queue *wq, void *data) select = rib; } - /* Deleted route check. */ - if (del && CHECK_FLAG (del->flags, ZEBRA_FLAG_SELECTED)) - fib = del; - - /* We possibly should lock fib and select here However, all functions - * below are 'inline' and not asynchronous And if any were to be - * converted, they should manage references themselves really.. See - * previous comment above. - */ - /* Same route is selected. */ if (select && select == fib) { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: Updating existing route, select %p, fib %p", + __func__, select, fib); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { redistribute_delete (&rn->p, select); @@ -1011,12 +980,14 @@ rib_process (struct work_queue *wq, void *data) if (! installed) rib_install_kernel (rn, select); } - return WQ_SUCCESS; + goto end; } /* Uninstall old rib from forwarding table. */ if (fib) { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: Removing existing route, fib %p", __func__, fib); redistribute_delete (&rn->p, fib); if (! RIB_SYSTEM_ROUTE (fib)) rib_uninstall_kernel (rn, fib); @@ -1029,6 +1000,8 @@ rib_process (struct work_queue *wq, void *data) /* Install new rib into forwarding table. */ if (select) { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: Adding route, select %p", __func__, select); /* Set real nexthop. */ nexthop_active_update (rn, select, 1); @@ -1038,73 +1011,68 @@ rib_process (struct work_queue *wq, void *data) redistribute_add (&rn->p, select); } - return WQ_SUCCESS; + /* FIB route was removed, should be deleted */ + if (del) + { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: Deleting fib %p, rn %p", __func__, del, rn); + rib_unlink (rn, del); + } +end: + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_debug ("%s: rn %p dequeued", __func__, rn); + if (rn->info) + UNSET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED); + route_unlock_node (rn); /* rib queue lock */ + return WQ_SUCCESS; } -/* Add work queue item to work queue and schedule processing */ +/* Add route_node to work queue and schedule processing */ static void -rib_queue_add_qnode (struct zebra_t *zebra, struct zebra_queue_node_t *qnode) +rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { - route_lock_node (qnode->node); + assert (zebra && rn); - if (IS_ZEBRA_DEBUG_EVENT) - zlog_info ("rib_queue_add_qnode: work queue added"); + /* Pointless to queue a route_node with no RIB entries to add or remove */ + if (!rn->info) + { + zlog_debug ("%s: called for route_node (%p, %d) with no ribs", + __func__, rn, rn->lock); + zlog_backtrace(LOG_DEBUG); + return; + } + + /* Route-table node already queued, so nothing to do */ + if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED)) + { + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_debug ("%s: rn %p already queued", __func__, rn); + return; + } - assert (zebra && qnode && qnode->node); + route_lock_node (rn); /* rib queue lock */ + + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_info ("%s: work queue added", __func__); + + assert (zebra); - if (qnode->del) - rib_lock (qnode->del); - if (zebra->ribq == NULL) { - zlog_err ("rib_queue_add_qnode: ribq work_queue does not exist!"); - route_unlock_node (qnode->node); + zlog_err ("%s: work_queue does not exist!", __func__); + route_unlock_node (rn); return; } - work_queue_add (zebra->ribq, qnode); - - return; -} + work_queue_add (zebra->ribq, rn); -/* Add route node and rib to work queue and schedule processing */ -static void -rib_queue_add (struct zebra_t *zebra, struct route_node *rn, struct rib *del) -{ - struct zebra_queue_node_t *qnode; - - assert (zebra && rn); - - qnode = (struct zebra_queue_node_t *) - XCALLOC (MTYPE_RIB_QUEUE, sizeof (struct zebra_queue_node_t)); - - if (qnode == NULL) - { - zlog_err ("rib_queue_add: failed to allocate queue node memory, %s", - strerror (errno)); - return; - } - - qnode->node = rn; - qnode->del = del; - - rib_queue_add_qnode (zebra, qnode); + SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED); - return; -} + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_debug ("%s: rn %p queued", __func__, rn); -/* free zebra_queue_node_t */ -static void -rib_queue_qnode_del (struct work_queue *wq, void *data) -{ - struct zebra_queue_node_t *qnode = data; - route_unlock_node (qnode->node); - - if (qnode->del) - rib_unlock (qnode->del); - - XFREE (MTYPE_RIB_QUEUE, qnode); + return; } /* initialise zebra rib work queue */ @@ -1114,16 +1082,15 @@ rib_queue_init (struct zebra_t *zebra) assert (zebra); if (! (zebra->ribq = work_queue_new (zebra->master, - "zebra_rib_work_queue"))) + "route_node processing"))) { - zlog_err ("rib_queue_init: could not initialise work queue!"); + zlog_err ("%s: could not initialise work queue!", __func__); return; } /* fill in the work queue spec */ zebra->ribq->spec.workfunc = &rib_process; zebra->ribq->spec.errorfunc = NULL; - zebra->ribq->spec.del_item_data = &rib_queue_qnode_del; /* XXX: TODO: These should be runtime configurable via vty */ zebra->ribq->spec.max_retries = 3; zebra->ribq->spec.hold = rib_process_hold_time; @@ -1131,38 +1098,135 @@ rib_queue_init (struct zebra_t *zebra) return; } +/* RIB updates are processed via a queue of pointers to route_nodes. + * + * The queue length is bounded by the maximal size of the routing table, + * as a route_node will not be requeued, if already queued. + * + * RIBs are submitted via rib_addnode and rib_delnode, which set + * minimal state and then submit route_node to queue for best-path + * selection later. Order of add/delete state changes are preserved for + * any given RIB. + * + * Deleted RIBs are reaped during best-path selection. + * + * rib_addnode + * |-> rib_link or unset RIB_ENTRY_REMOVE |->Update kernel with + * |-> rib_addqueue | best RIB, if required + * | | + * |-> .......................... -> rib_process + * | | + * |-> rib_addqueue |-> rib_unlink + * |-> set RIB_ENTRY_REMOVE | + * rib_delnode (RIB freed) + * + * + * Queueing state for a route_node is kept in the head RIB entry, this + * state must be preserved as and when the head RIB entry of a + * route_node is changed by rib_unlink / rib_link. A small complication, + * but saves having to allocate a dedicated object for this. + * + * Refcounting (aka "locking" throughout the GNU Zebra and Quagga code): + * + * - route_nodes: refcounted by: + * - RIBs attached to route_node: + * - managed by: rib_link/unlink + * - route_node processing queue + * - managed by: rib_addqueue, rib_process. + * + */ + /* Add RIB to head of the route node. */ static void -rib_addnode (struct route_node *rn, struct rib *rib) +rib_link (struct route_node *rn, struct rib *rib) { struct rib *head; assert (rib && rn); - rib_lock (rib); - route_lock_node (rn); - + route_lock_node (rn); /* rn route table reference */ + + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: rn %p, rib %p", __func__, rn, rib); + head = rn->info; if (head) - head->prev = rib; + { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: new head, rn_status copied over", __func__); + head->prev = rib; + /* Transfer the rn status flags to the new head RIB */ + rib->rn_status = head->rn_status; + } rib->next = head; rn->info = rib; + rib_queue_add (&zebrad, rn); } static void -rib_delnode (struct route_node *rn, struct rib *rib) +rib_addnode (struct route_node *rn, struct rib *rib) { + /* RIB node has been un-removed before route-node is processed. + * route_node must hence already be on the queue for processing.. + */ + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: rn %p, un-removed rib %p", + __func__, rn, rib); + UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED); + return; + } + rib_link (rn, rib); +} + +static void +rib_unlink (struct route_node *rn, struct rib *rib) +{ + struct nexthop *nexthop, *next; + assert (rn && rib); - + + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: rn %p, rib %p", + __func__, rn, rib); + if (rib->next) rib->next->prev = rib->prev; + if (rib->prev) rib->prev->next = rib->next; else - rn->info = rib->next; - - rib_unlock (rib); - route_unlock_node (rn); + { + rn->info = rib->next; + + if (rn->info) + { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: rn %p, rib %p, new head copy", + __func__, rn, rib); + rib->next->rn_status = rib->rn_status; + } + } + + /* free RIB and nexthops */ + for (nexthop = rib->nexthop; nexthop; nexthop = next) + { + next = nexthop->next; + nexthop_free (nexthop); + } + XFREE (MTYPE_RIB, rib); + + route_unlock_node (rn); /* rn route table reference */ +} + +static void +rib_delnode (struct route_node *rn, struct rib *rib) +{ + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: rn %p, rib %p, removing", __func__, rn, rib); + SET_FLAG (rib->status, RIB_ENTRY_REMOVED); + rib_queue_add (&zebrad, rn); } int @@ -1201,6 +1265,9 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, withdraw. */ for (rib = rn->info; rib; rib = rib->next) { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + if (rib->type != type) continue; if (rib->type != ZEBRA_ROUTE_CONNECT) @@ -1211,7 +1278,8 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Duplicate connected route comes in. */ else if ((nexthop = rib->nexthop) && nexthop->type == NEXTHOP_TYPE_IFINDEX && - nexthop->ifindex == ifindex) + nexthop->ifindex == ifindex && + !CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { rib->refcnt++; return 0 ; @@ -1247,9 +1315,6 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Link new rib to node.*/ rib_addnode (rn, rib); - /* Process this route node. */ - rib_queue_add (&zebrad, rn, same); - /* Free implicit route.*/ if (same) rib_delnode (rn, same); @@ -1291,6 +1356,9 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) withdraw. */ for (same = rn->info; same; same = same->next) { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + if (same->type == rib->type && same->table == rib->table && same->type != ZEBRA_ROUTE_CONNECT) break; @@ -1304,9 +1372,6 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) /* Link new rib to node.*/ rib_addnode (rn, rib); - /* Process this route node. */ - rib_queue_add (&zebrad, rn, same); - /* Free implicit route.*/ if (same) rib_delnode (rn, same); @@ -1368,6 +1433,9 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, /* Lookup same type route. */ for (rib = rn->info; rib; rib = rib->next) { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) fib = rib; @@ -1432,9 +1500,6 @@ rib_delete_ipv4 (int type, int flags, struct prefix_ipv4 *p, } } - /* Process changes. */ - rib_queue_add (&zebrad, rn, same); - if (same) rib_delnode (rn, same); @@ -1458,8 +1523,13 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) /* Lookup existing route */ rn = route_node_get (table, p); for (rib = rn->info; rib; rib = rib->next) - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) - break; + { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + } if (rib) { @@ -1478,7 +1548,6 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) nexthop_blackhole_add (rib); break; } - rib_queue_add (&zebrad, rn, NULL); } else { @@ -1489,7 +1558,6 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) rib->distance = si->distance; rib->metric = 0; rib->nexthop_num = 0; - rib->table = zebrad.rtm_table_default; switch (si->type) { @@ -1509,9 +1577,6 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) /* Link this rib to the tree. */ rib_addnode (rn, rib); - - /* Process this prefix. */ - rib_queue_add (&zebrad, rn, NULL); } } @@ -1552,8 +1617,13 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) return; for (rib = rn->info; rib; rib = rib->next) - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) - break; + { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + } if (! rib) { @@ -1575,17 +1645,14 @@ static_uninstall_ipv4 (struct prefix *p, struct static_ipv4 *si) /* Check nexthop. */ if (rib->nexthop_num == 1) - { - rib_queue_add (&zebrad, rn, rib); - rib_delnode (rn, rib); - } + rib_delnode (rn, rib); else { if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) rib_uninstall (rn, rib); nexthop_delete (rib, nexthop); nexthop_free (nexthop); - rib_queue_add (&zebrad, rn, NULL); + rib_queue_add (&zebrad, rn); } /* Unlock node. */ route_unlock_node (rn); @@ -1811,6 +1878,9 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, withdraw. */ for (rib = rn->info; rib; rib = rib->next) { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + if (rib->type != type) continue; if (rib->type != ZEBRA_ROUTE_CONNECT) @@ -1857,9 +1927,6 @@ rib_add_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* Link new rib to node.*/ rib_addnode (rn, rib); - /* Process this route node. */ - rib_queue_add (&zebrad, rn, same); - /* Free implicit route.*/ if (same) rib_delnode (rn, same); @@ -1914,6 +1981,9 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, /* Lookup same type route. */ for (rib = rn->info; rib; rib = rib->next) { + if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) fib = rib; @@ -1978,9 +2048,6 @@ rib_delete_ipv6 (int type, int flags, struct prefix_ipv6 *p, } } - /* Process changes. */ - rib_queue_add (&zebrad, rn, same); - if (same) rib_delnode (rn, same); @@ -2004,8 +2071,13 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) /* Lookup existing route */ rn = route_node_get (table, p); for (rib = rn->info; rib; rib = rib->next) - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) - break; + { + if (CHECK_FLAG(rib->status, RIB_ENTRY_REMOVED)) + continue; + + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + } if (rib) { @@ -2025,7 +2097,6 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); break; } - rib_queue_add (&zebrad, rn, NULL); } else { @@ -2055,9 +2126,6 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) /* Link this rib to the tree. */ rib_addnode (rn, rib); - - /* Process this prefix. */ - rib_queue_add (&zebrad, rn, NULL); } } @@ -2099,8 +2167,14 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) return; for (rib = rn->info; rib; rib = rib->next) - if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) - break; + { + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + + if (rib->type == ZEBRA_ROUTE_STATIC && rib->distance == si->distance) + break; + } + if (! rib) { route_unlock_node (rn); @@ -2123,7 +2197,6 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) if (rib->nexthop_num == 1) { rib_delnode (rn, rib); - rib_queue_add (&zebrad, rn, rib); } else { @@ -2131,7 +2204,7 @@ static_uninstall_ipv6 (struct prefix *p, struct static_ipv6 *si) rib_uninstall (rn, rib); nexthop_delete (rib, nexthop); nexthop_free (nexthop); - rib_queue_add (&zebrad, rn, NULL); + rib_queue_add (&zebrad, rn); } /* Unlock node. */ route_unlock_node (rn); @@ -2291,13 +2364,13 @@ rib_update (void) if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rn->info) - rib_queue_add (&zebrad, rn, NULL); + rib_queue_add (&zebrad, rn); table = vrf_table (AFI_IP6, SAFI_UNICAST, 0); if (table) for (rn = route_top (table); rn; rn = route_next (rn)) if (rn->info) - rib_queue_add (&zebrad, rn, NULL); + rib_queue_add (&zebrad, rn); } /* Interface goes up. */ @@ -2328,6 +2401,9 @@ rib_weed_table (struct route_table *table) { next = rib->next; + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + if (rib->table != zebrad.rtm_table_default && rib->table != RT_TABLE_MAIN) rib_delnode (rn, rib); @@ -2357,6 +2433,9 @@ rib_sweep_table (struct route_table *table) { next = rib->next; + if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + continue; + if (rib->type == ZEBRA_ROUTE_KERNEL && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELFROUTE)) { @@ -2385,9 +2464,11 @@ rib_close_table (struct route_table *table) if (table) for (rn = route_top (table); rn; rn = route_next (rn)) for (rib = rn->info; rib; rib = rib->next) - if (! RIB_SYSTEM_ROUTE (rib) - && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) - rib_uninstall_kernel (rn, rib); + { + if (! RIB_SYSTEM_ROUTE (rib) + && CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED)) + rib_uninstall_kernel (rn, rib); + } } /* Close all RIB tables. */ -- cgit v1.2.3 From 3c0755dc9772deccff2ba6e9dc0511a9af2b9d1b Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Fri, 8 Dec 2006 00:53:14 +0000 Subject: [zebra] Changes of nexthops of static routes didnt take effect 2006-12-08 Piotr Chytla * zebra_rib.c: (static_install_ipv{4,6}) Case where existing RIB is updated must explicitely rib_addqueue the route_node, to ensure the update actually takes effect. --- zebra/zebra_rib.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index acad065a..02c73d12 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1103,20 +1103,20 @@ rib_queue_init (struct zebra_t *zebra) * The queue length is bounded by the maximal size of the routing table, * as a route_node will not be requeued, if already queued. * - * RIBs are submitted via rib_addnode and rib_delnode, which set - * minimal state and then submit route_node to queue for best-path - * selection later. Order of add/delete state changes are preserved for - * any given RIB. + * RIBs are submitted via rib_addnode or rib_delnode which set minimal + * state, or static_install_ipv{4,6} (when an existing RIB is updated) + * and then submit route_node to queue for best-path selection later. + * Order of add/delete state changes are preserved for any given RIB. * * Deleted RIBs are reaped during best-path selection. * * rib_addnode * |-> rib_link or unset RIB_ENTRY_REMOVE |->Update kernel with - * |-> rib_addqueue | best RIB, if required - * | | - * |-> .......................... -> rib_process - * | | - * |-> rib_addqueue |-> rib_unlink + * |-------->| | best RIB, if required + * | | + * static_install->|->rib_addqueue...... -> rib_process + * | | + * |-------->| |-> rib_unlink * |-> set RIB_ENTRY_REMOVE | * rib_delnode (RIB freed) * @@ -1548,6 +1548,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) nexthop_blackhole_add (rib); break; } + rib_queue_add (&zebrad, rn); } else { @@ -1704,7 +1705,7 @@ static_add_ipv4 (struct prefix *p, struct in_addr *gate, const char *ifname, } } - /* Distance chaged. */ + /* Distance changed. */ if (update) static_delete_ipv4 (p, gate, ifname, update->distance, vrf_id); @@ -2097,6 +2098,7 @@ static_install_ipv6 (struct prefix *p, struct static_ipv6 *si) nexthop_ipv6_ifname_add (rib, &si->ipv6, si->ifname); break; } + rib_queue_add (&zebrad, rn); } else { -- cgit v1.2.3 From 7514fb7739f74311830e9ddd1381d0d228224f61 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 2 May 2007 16:05:35 +0000 Subject: [zebra] Routemap support on received routes, with 'set src' command (linux) 2007-05-01 David L Stevens * (general) These changes collectively add route-map and prefix-list support to zebra and fix a bug in "show route-map" (with no argument). * doc/main.texi: added route-map, prefix-list, ip protocol and set src documentation * lib/command.h: added PROTOCOL_NODE type * lib/log.c: (proto_name2num) new function, protocol name to number translation. * lib/routemap.c: (vty_show_route_map) fixed "show route-map" without route-map name * lib/routemap.h: added RMAP_ZEBRA type * lib/zebra.h: added proto_name2num() prototype * vtysh/extract.pl.in: added VTYSH_ZEBRA flag for route-map and plist * vtysh/Makefile.am: added zebra_routemap.c * vtysh/vtysh.h: added VTYSH_ZEBRA flag to VTYSH_RMAP * zebra/connected.c: (connected_up_ipv4) added src preference argument to rib_add_ipv4() * zebra/kernel_socket.c: (rtm_read) ditto * zebra/main.c: added prefix list initialization * zebra/Makefile.am: added zebra_routemap.c source file * zebra/rib.h: added generic address union "g_addr" and use in existing places that had an explicit union. Added "src" to struct nexthop. Added preferred src arg to nexthop_ipv4_add and rib_add_ipv4. * zebra/rt_netlink.c: (netlink_routing_table) set preferred source on netlink messages. (netlink_route_change) ditto (netlink_route_multipath) ditto. * zebra/rtread_getmsg.c: (handle_route_entry) added (NULL) src to rib_add_ipv4() call. * zebra/rtread_proc.c: (proc_route_read) ditto * zebra/zebra_rib.c: (nexthop_ipv4_add) add src argument. (nexthop_ipv4_ifindex_add) ditto (rib_add_ipv4) ditto (nexthop_active_check) Add route-map processing. * zebra/zebra_routemap.c: new file for zebra route-map commands. * zebra/zebra_vty.c: (ip_protocol_cmd) Apply route-map to protocol (vty_show_ip_route_detail) added "src" printing (vty_show_ip_route) ditto (show_ip_protocol_cmd) new command, list routemaps. (config_write_protocol) write out routemap protocl config. (zebra_vty_init) Install the new routemap protocol commands. * zebra/zserv.c: (zread_ipv4_add) added (NULL) src arg (zebra_init) init zebra route-maps. * zebra/zserv.h: add zebra_route_map_init --- zebra/zebra_rib.c | 57 +++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 10 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 02c73d12..693b3331 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -32,6 +32,8 @@ #include "linklist.h" #include "thread.h" #include "workqueue.h" +#include "prefix.h" +#include "routemap.h" #include "zebra/rib.h" #include "zebra/rt.h" @@ -233,7 +235,7 @@ nexthop_ifname_add (struct rib *rib, char *ifname) } struct nexthop * -nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4) +nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4, struct in_addr *src) { struct nexthop *nexthop; @@ -241,6 +243,8 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4) memset (nexthop, 0, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IPV4; nexthop->gate.ipv4 = *ipv4; + if (src) + nexthop->src.ipv4 = *src; nexthop_add (rib, nexthop); @@ -249,7 +253,7 @@ nexthop_ipv4_add (struct rib *rib, struct in_addr *ipv4) static struct nexthop * nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, - unsigned int ifindex) + struct in_addr *src, unsigned int ifindex) { struct nexthop *nexthop; @@ -257,6 +261,8 @@ nexthop_ipv4_ifindex_add (struct rib *rib, struct in_addr *ipv4, memset (nexthop, 0, sizeof (struct nexthop)); nexthop->type = NEXTHOP_TYPE_IPV4_IFINDEX; nexthop->gate.ipv4 = *ipv4; + if (src) + nexthop->src.ipv4 = *src; nexthop->ifindex = ifindex; nexthop_add (rib, nexthop); @@ -685,12 +691,20 @@ rib_match_ipv6 (struct in6_addr *addr) } #endif /* HAVE_IPV6 */ +#define RIB_SYSTEM_ROUTE(R) \ + ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) + static int nexthop_active_check (struct route_node *rn, struct rib *rib, struct nexthop *nexthop, int set) { struct interface *ifp; + route_map_result_t ret = RMAP_MATCH; + extern char *proto_rm[AFI_MAX][ZEBRA_ROUTE_MAX+1]; + struct route_map *rmap; + int family; + family = 0; switch (nexthop->type) { case NEXTHOP_TYPE_IFINDEX: @@ -700,8 +714,9 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, else UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; - case NEXTHOP_TYPE_IFNAME: case NEXTHOP_TYPE_IPV6_IFNAME: + family = AFI_IP6; + case NEXTHOP_TYPE_IFNAME: ifp = if_lookup_by_name (nexthop->ifname); if (ifp && if_is_up (ifp)) { @@ -718,6 +733,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, break; case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: + family = AFI_IP; if (nexthop_active_ipv4 (rib, nexthop, set, rn)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else @@ -725,12 +741,14 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, break; #ifdef HAVE_IPV6 case NEXTHOP_TYPE_IPV6: + family = AFI_IP6; if (nexthop_active_ipv6 (rib, nexthop, set, rn)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); break; case NEXTHOP_TYPE_IPV6_IFINDEX: + family = AFI_IP6; if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) { ifp = if_lookup_by_index (nexthop->ifindex); @@ -754,6 +772,26 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, default: break; } + if (! CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) + return 0; + + if (RIB_SYSTEM_ROUTE(rib) || + (family == AFI_IP && rn->p.family != AF_INET) || + (family == AFI_IP6 && rn->p.family != AF_INET6)) + return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + + rmap = 0; + if (rib->type >= 0 && rib->type < ZEBRA_ROUTE_MAX && + proto_rm[family][rib->type]) + rmap = route_map_lookup_by_name (proto_rm[family][rib->type]); + if (!rmap && proto_rm[family][ZEBRA_ROUTE_MAX]) + rmap = route_map_lookup_by_name (proto_rm[family][ZEBRA_ROUTE_MAX]); + if (rmap) { + ret = route_map_apply(rmap, &rn->p, RMAP_ZEBRA, nexthop); + } + + if (ret == RMAP_DENYMATCH) + UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); } @@ -782,8 +820,6 @@ nexthop_active_update (struct route_node *rn, struct rib *rib, int set) } -#define RIB_SYSTEM_ROUTE(R) \ - ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) static void rib_install_kernel (struct route_node *rn, struct rib *rib) @@ -1231,7 +1267,8 @@ rib_delnode (struct route_node *rn, struct rib *rib) int rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, - struct in_addr *gate, unsigned int ifindex, u_int32_t vrf_id, + struct in_addr *gate, struct in_addr *src, + unsigned int ifindex, u_int32_t vrf_id, u_int32_t metric, u_char distance) { struct rib *rib; @@ -1300,9 +1337,9 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, if (gate) { if (ifindex) - nexthop_ipv4_ifindex_add (rib, gate, ifindex); + nexthop_ipv4_ifindex_add (rib, gate, src, ifindex); else - nexthop_ipv4_add (rib, gate); + nexthop_ipv4_add (rib, gate, src); } else nexthop_ifindex_add (rib, ifindex); @@ -1539,7 +1576,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) switch (si->type) { case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->gate.ipv4); + nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); break; case STATIC_IPV4_IFNAME: nexthop_ifname_add (rib, si->gate.ifname); @@ -1563,7 +1600,7 @@ static_install_ipv4 (struct prefix *p, struct static_ipv4 *si) switch (si->type) { case STATIC_IPV4_GATEWAY: - nexthop_ipv4_add (rib, &si->gate.ipv4); + nexthop_ipv4_add (rib, &si->gate.ipv4, NULL); break; case STATIC_IPV4_IFNAME: nexthop_ifname_add (rib, si->gate.ifname); -- cgit v1.2.3 From 0b8c4f1d811170224e467b305137ac94861daee6 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Wed, 27 Jun 2007 11:12:38 +0000 Subject: [zebra] rib loop check for RIB_ENTRY_REMOVED checks wrong var 2007-06-25 Denis Ovsienko * zebra_rib.c: (rib_add_ipv4_multipath) Loop through RIB is using 'same' variable, but RIB_ENTRY_REMOVED check is testing the constant 'rib' variable, fix. Impact unknown at this point. --- zebra/zebra_rib.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 693b3331..a85c49fd 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1393,7 +1393,7 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) withdraw. */ for (same = rn->info; same; same = same->next) { - if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) + if (CHECK_FLAG (same->status, RIB_ENTRY_REMOVED)) continue; if (same->type == rib->type && same->table == rib->table -- cgit v1.2.3 From 93bdadae74a9b391152f5511dbced6f08fad6d94 Mon Sep 17 00:00:00 2001 From: Paul Jakma Date: Mon, 6 Aug 2007 19:25:11 +0000 Subject: [zebra] Add extra debug logging for RIB and RIB queueing 2007-08-06 Denis Ovsienko * zebra_rib.c: (general) Add extra debug logging for RIB and RIB queue. --- zebra/zebra_rib.c | 70 ++++++++++++++++++++++++++++++++++++++++--------------- 1 file changed, 51 insertions(+), 19 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index a85c49fd..7a63c1c1 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -898,9 +898,13 @@ rib_process (struct work_queue *wq, void *data) struct route_node *rn = data; int installed = 0; struct nexthop *nexthop = NULL; + char buf[INET_ADDRSTRLEN]; assert (rn); + if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) + inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + for (rib = rn->info; rib; rib = next) { next = rib->next; @@ -920,7 +924,8 @@ rib_process (struct work_queue *wq, void *data) if (rib != fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: rn %p, removing rib %p", __func__, rn, rib); + zlog_debug ("%s: %s/%d: rn %p, removing rib %p", __func__, + buf, rn->p.prefixlen, rn, rib); rib_unlink (rn, rib); } else @@ -984,8 +989,8 @@ rib_process (struct work_queue *wq, void *data) if (select && select == fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: Updating existing route, select %p, fib %p", - __func__, select, fib); + zlog_debug ("%s: %s/%d: Updating existing route, select %p, fib %p", + __func__, buf, rn->p.prefixlen, select, fib); if (CHECK_FLAG (select->flags, ZEBRA_FLAG_CHANGED)) { redistribute_delete (&rn->p, select); @@ -1023,7 +1028,8 @@ rib_process (struct work_queue *wq, void *data) if (fib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: Removing existing route, fib %p", __func__, fib); + zlog_debug ("%s: %s/%d: Removing existing route, fib %p", __func__, + buf, rn->p.prefixlen, fib); redistribute_delete (&rn->p, fib); if (! RIB_SYSTEM_ROUTE (fib)) rib_uninstall_kernel (rn, fib); @@ -1037,7 +1043,8 @@ rib_process (struct work_queue *wq, void *data) if (select) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: Adding route, select %p", __func__, select); + zlog_debug ("%s: %s/%d: Adding route, select %p", __func__, buf, + rn->p.prefixlen, select); /* Set real nexthop. */ nexthop_active_update (rn, select, 1); @@ -1051,13 +1058,14 @@ rib_process (struct work_queue *wq, void *data) if (del) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: Deleting fib %p, rn %p", __func__, del, rn); + zlog_debug ("%s: %s/%d: Deleting fib %p, rn %p", __func__, buf, + rn->p.prefixlen, del, rn); rib_unlink (rn, del); } end: if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: rn %p dequeued", __func__, rn); + zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn); if (rn->info) UNSET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED); route_unlock_node (rn); /* rib queue lock */ @@ -1068,8 +1076,12 @@ end: static void rib_queue_add (struct zebra_t *zebra, struct route_node *rn) { + char buf[INET_ADDRSTRLEN]; assert (zebra && rn); + if (IS_ZEBRA_DEBUG_RIB_Q) + inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + /* Pointless to queue a route_node with no RIB entries to add or remove */ if (!rn->info) { @@ -1083,14 +1095,15 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED)) { if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: rn %p already queued", __func__, rn); + zlog_debug ("%s: %s/%d: rn %p already queued", __func__, buf, + rn->p.prefixlen, rn); return; } route_lock_node (rn); /* rib queue lock */ if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_info ("%s: work queue added", __func__); + zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen); assert (zebra); @@ -1106,7 +1119,7 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED); if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: rn %p queued", __func__, rn); + zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn); return; } @@ -1177,19 +1190,25 @@ static void rib_link (struct route_node *rn, struct rib *rib) { struct rib *head; + char buf[INET_ADDRSTRLEN]; assert (rib && rn); route_lock_node (rn); /* rn route table reference */ if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: rn %p, rib %p", __func__, rn, rib); + { + inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + zlog_debug ("%s: %s/%d: rn %p, rib %p", __func__, + buf, rn->p.prefixlen, rn, rib); + } head = rn->info; if (head) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: new head, rn_status copied over", __func__); + zlog_debug ("%s: %s/%d: new head, rn_status copied over", __func__, + buf, rn->p.prefixlen); head->prev = rib; /* Transfer the rn status flags to the new head RIB */ rib->rn_status = head->rn_status; @@ -1208,8 +1227,12 @@ rib_addnode (struct route_node *rn, struct rib *rib) if (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED)) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: rn %p, un-removed rib %p", - __func__, rn, rib); + { + char buf[INET_ADDRSTRLEN]; + inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + zlog_debug ("%s: %s/%d: rn %p, un-removed rib %p", + __func__, buf, rn->p.prefixlen, rn, rib); + } UNSET_FLAG (rib->status, RIB_ENTRY_REMOVED); return; } @@ -1220,12 +1243,16 @@ static void rib_unlink (struct route_node *rn, struct rib *rib) { struct nexthop *nexthop, *next; + char buf[INET_ADDRSTRLEN]; assert (rn && rib); if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: rn %p, rib %p", - __func__, rn, rib); + { + inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + zlog_debug ("%s: %s/%d: rn %p, rib %p", + __func__, buf, rn->p.prefixlen, rn, rib); + } if (rib->next) rib->next->prev = rib->prev; @@ -1239,8 +1266,8 @@ rib_unlink (struct route_node *rn, struct rib *rib) if (rn->info) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: rn %p, rib %p, new head copy", - __func__, rn, rib); + zlog_debug ("%s: %s/%d: rn %p, rib %p, new head copy", + __func__, buf, rn->p.prefixlen, rn, rib); rib->next->rn_status = rib->rn_status; } } @@ -1260,7 +1287,12 @@ static void rib_delnode (struct route_node *rn, struct rib *rib) { if (IS_ZEBRA_DEBUG_RIB) - zlog_debug ("%s: rn %p, rib %p, removing", __func__, rn, rib); + { + char buf[INET_ADDRSTRLEN]; + inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + zlog_debug ("%s: %s/%d: rn %p, rib %p, removing", __func__, + buf, rn->p.prefixlen, rn, rib); + } SET_FLAG (rib->status, RIB_ENTRY_REMOVED); rib_queue_add (&zebrad, rn); } -- cgit v1.2.3 From dc95824ae13d65156dd873a6e784d9a0eed2f39f Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 13 Aug 2007 16:03:06 +0000 Subject: Merged own patch for the bug #391 (debugging and comments mostly). --- zebra/zebra_rib.c | 240 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 235 insertions(+), 5 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 7a63c1c1..f61cbe31 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -631,6 +631,82 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) return NULL; } +/* + * This clone function, unlike its original rib_lookup_ipv4(), checks + * if specified IPv4 route record (prefix/mask -> gate) exists in + * the whole RIB and has ZEBRA_FLAG_SELECTED set. + * + * Return values: + * -1: error + * 0: exact match found + * 1: a match was found with a different gate + * 2: connected route found + * 3: no matches found + */ +int +rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) +{ + struct route_table *table; + struct route_node *rn; + struct rib *match; + struct nexthop *nexthop; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + return ZEBRA_RIB_LOOKUP_ERROR; + + /* Scan the RIB table for exactly matching RIB entry. */ + rn = route_node_lookup (table, (struct prefix *) p); + + /* No route for this prefix. */ + if (! rn) + return ZEBRA_RIB_NOTFOUND; + + /* Unlock node. */ + route_unlock_node (rn); + + /* Find out if a "selected" RR for the discovered RIB entry exists ever. */ + for (match = rn->info; match; match = match->next) + { + if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + } + + /* None such found :( */ + if (!match) + return ZEBRA_RIB_NOTFOUND; + + if (match->type == ZEBRA_ROUTE_CONNECT) + return ZEBRA_RIB_FOUND_CONNECTED; + + /* Ok, we have a cood candidate, let's check it's nexthop list... */ + for (nexthop = match->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) + { + /* We are happy with either direct or recursive hexthop */ + if (nexthop->gate.ipv4.s_addr == qgate->sin.sin_addr.s_addr || + nexthop->rgate.ipv4.s_addr == qgate->sin.sin_addr.s_addr) + return ZEBRA_RIB_FOUND_EXACT; + else + { + if (IS_ZEBRA_DEBUG_RIB) + { + char gate_buf[INET_ADDRSTRLEN], rgate_buf[INET_ADDRSTRLEN], qgate_buf[INET_ADDRSTRLEN]; + inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, gate_buf, INET_ADDRSTRLEN); + inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, rgate_buf, INET_ADDRSTRLEN); + inet_ntop (AF_INET, &qgate->sin.sin_addr.s_addr, qgate_buf, INET_ADDRSTRLEN); + zlog_debug ("%s: qgate == %s, gate == %s, rgate == %s", __func__, qgate_buf, gate_buf, rgate_buf); + } + return ZEBRA_RIB_FOUND_NOGATE; + } + } + + return ZEBRA_RIB_NOTFOUND; +} + #ifdef HAVE_IPV6 struct rib * rib_match_ipv6 (struct in6_addr *addr) @@ -694,6 +770,16 @@ rib_match_ipv6 (struct in6_addr *addr) #define RIB_SYSTEM_ROUTE(R) \ ((R)->type == ZEBRA_ROUTE_KERNEL || (R)->type == ZEBRA_ROUTE_CONNECT) +/* This function verifies reachability of one given nexthop, which can be + * numbered or unnumbered, IPv4 or IPv6. The result is unconditionally stored + * in nexthop->flags field. If the 4th parameter, 'set', is non-zero, + * nexthop->ifindex will be updated appropriately as well. + * An existing route map can turn (otherwise active) nexthop into inactive, but + * not vice versa. + * + * The return value is the final value of 'ACTIVE' flag. + */ + static int nexthop_active_check (struct route_node *rn, struct rib *rib, struct nexthop *nexthop, int set) @@ -839,6 +925,7 @@ rib_install_kernel (struct route_node *rn, struct rib *rib) #endif /* HAVE_IPV6 */ } + /* This condition is never met, if we are using rt_socket.c */ if (ret < 0) { for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) @@ -860,6 +947,8 @@ rib_uninstall_kernel (struct route_node *rn, struct rib *rib) break; #ifdef HAVE_IPV6 case AF_INET6: + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: calling kernel_delete_ipv4 (%p, %p)", __func__, rn, rib); ret = kernel_delete_ipv6 (&rn->p, rib); break; #endif /* HAVE_IPV6 */ @@ -907,6 +996,9 @@ rib_process (struct work_queue *wq, void *data) for (rib = rn->info; rib; rib = next) { + /* The next pointer is saved, because current pointer + * may be passed to rib_unlink() in the middle of iteration. + */ next = rib->next; /* Currently installed rib. */ @@ -983,9 +1075,16 @@ rib_process (struct work_queue *wq, void *data) /* metric tie-breaks equal distance */ if (rib->metric <= select->metric) select = rib; - } - - /* Same route is selected. */ + } /* for (rib = rn->info; rib; rib = next) */ + + /* After the cycle is finished, the following pointers will be set: + * select --- the winner RIB entry, if any was found, otherwise NULL + * fib --- the SELECTED RIB entry, if any, otherwise NULL + * del --- equal to fib, if fib is queued for deletion, NULL otherwise + * rib --- NULL + */ + + /* Same RIB entry is selected. Update FIB and finish. */ if (select && select == fib) { if (IS_ZEBRA_DEBUG_RIB) @@ -1024,7 +1123,10 @@ rib_process (struct work_queue *wq, void *data) goto end; } - /* Uninstall old rib from forwarding table. */ + /* At this point we either haven't found the best RIB entry or it is + * different from what we currently intend to flag with SELECTED. In both + * cases, if a RIB block is present in FIB, it should be withdrawn. + */ if (fib) { if (IS_ZEBRA_DEBUG_RIB) @@ -1039,7 +1141,10 @@ rib_process (struct work_queue *wq, void *data) nexthop_active_update (rn, fib, 1); } - /* Install new rib into forwarding table. */ + /* Regardless of some RIB entry being SELECTED or not before, now we can + * tell, that if a new winner exists, FIB is still not updated with this + * data, but ready to be. + */ if (select) { if (IS_ZEBRA_DEBUG_RIB) @@ -1382,16 +1487,127 @@ rib_add_ipv4 (int type, int flags, struct prefix_ipv4 *p, SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB); /* Link new rib to node.*/ + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: calling rib_addnode (%p, %p)", __func__, rn, rib); rib_addnode (rn, rib); /* Free implicit route.*/ if (same) + { + if (IS_ZEBRA_DEBUG_RIB) + zlog_debug ("%s: calling rib_delnode (%p, %p)", __func__, rn, rib); rib_delnode (rn, same); + } route_unlock_node (rn); return 0; } +/* This function dumps the contents of a given RIB entry into + * standard debug log. Calling function name and IP prefix in + * question are passed as 1st and 2nd arguments. + */ + +void rib_dump (const char * func, const struct prefix_ipv4 * p, const struct rib * rib) +{ + char straddr1[INET_ADDRSTRLEN], straddr2[INET_ADDRSTRLEN]; + struct nexthop *nexthop; + + inet_ntop (AF_INET, &p->prefix, straddr1, INET_ADDRSTRLEN); + zlog_debug ("%s: dumping RIB entry %p for %s/%d", func, rib, straddr1, p->prefixlen); + zlog_debug + ( + "%s: refcnt == %lu, uptime == %u, type == %u, table == %d", + func, + rib->refcnt, + rib->uptime, + rib->type, + rib->table + ); + zlog_debug + ( + "%s: metric == %u, distance == %u, flags == %u, status == %u", + func, + rib->metric, + rib->distance, + rib->flags, + rib->status + ); + zlog_debug + ( + "%s: nexthop_num == %u, nexthop_active_num == %u, nexthop_fib_num == %u", + func, + rib->nexthop_num, + rib->nexthop_active_num, + rib->nexthop_fib_num + ); + for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) + { + inet_ntop (AF_INET, &nexthop->gate.ipv4.s_addr, straddr1, INET_ADDRSTRLEN); + inet_ntop (AF_INET, &nexthop->rgate.ipv4.s_addr, straddr2, INET_ADDRSTRLEN); + zlog_debug + ( + "%s: NH %s (%s) with flags %s%s%s", + func, + straddr1, + straddr2, + (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE) ? "ACTIVE " : ""), + (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB) ? "FIB " : ""), + (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE) ? "RECURSIVE" : "") + ); + } + zlog_debug ("%s: dump complete", func); +} + +/* This is an exported helper to rtm_read() to dump the strange + * RIB entry found by rib_lookup_ipv4_route() + */ + +void rib_lookup_and_dump (struct prefix_ipv4 * p) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + char prefix_buf[INET_ADDRSTRLEN]; + + /* Lookup table. */ + table = vrf_table (AFI_IP, SAFI_UNICAST, 0); + if (! table) + { + zlog_err ("%s: vrf_table() returned NULL", __func__); + return; + } + + inet_ntop (AF_INET, &p->prefix.s_addr, prefix_buf, INET_ADDRSTRLEN); + /* Scan the RIB table for exactly matching RIB entry. */ + rn = route_node_lookup (table, (struct prefix *) p); + + /* No route for this prefix. */ + if (! rn) + { + zlog_debug ("%s: lookup failed for %s/%d", __func__, prefix_buf, p->prefixlen); + return; + } + + /* Unlock node. */ + route_unlock_node (rn); + + /* let's go */ + for (rib = rn->info; rib; rib = rib->next) + { + zlog_debug + ( + "%s: rn %p, rib %p: %s, %s", + __func__, + rn, + rib, + (CHECK_FLAG (rib->status, RIB_ENTRY_REMOVED) ? "removed" : "NOT removed"), + (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) ? "selected" : "NOT selected") + ); + rib_dump (__func__, p, rib); + } +} + int rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) { @@ -1440,10 +1656,24 @@ rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) /* Link new rib to node.*/ rib_addnode (rn, rib); + if (IS_ZEBRA_DEBUG_RIB) + { + zlog_debug ("%s: called rib_addnode (%p, %p) on new RIB entry", + __func__, rn, rib); + rib_dump (__func__, p, rib); + } /* Free implicit route.*/ if (same) + { + if (IS_ZEBRA_DEBUG_RIB) + { + zlog_debug ("%s: calling rib_delnode (%p, %p) on existing RIB entry", + __func__, rn, same); + rib_dump (__func__, p, same); + } rib_delnode (rn, same); + } route_unlock_node (rn); return 0; -- cgit v1.2.3 From 03e232a4588187992f3538985d541289dc272464 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 14 Aug 2007 09:46:48 +0000 Subject: Merged own patch for bug #390 (rewrite zebra/zebra_rib.c:nexthop_active_update()) --- zebra/zebra_rib.c | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index f61cbe31..e5cce1e8 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -881,27 +881,32 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, return CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); } +/* Iterate over all nexthops of the given RIB entry and refresh their + * ACTIVE flag. rib->nexthop_active_num is updated accordingly. If any + * nexthop is found to toggle the ACTIVE flag, the whole rib structure + * is flagged with ZEBRA_FLAG_CHANGED. The 4th 'set' argument is + * transparently passed to nexthop_active_check(). + * + * Return value is the new number of active nexthops. + */ + static int nexthop_active_update (struct route_node *rn, struct rib *rib, int set) { struct nexthop *nexthop; - int active; + int prev_active, new_active; rib->nexthop_active_num = 0; UNSET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next) - { - active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); - - nexthop_active_check (rn, rib, nexthop, set); - if ((MULTIPATH_NUM == 0 || rib->nexthop_active_num < MULTIPATH_NUM) - && active != CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); - - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE)) - rib->nexthop_active_num++; - } + { + prev_active = CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); + if ((new_active = nexthop_active_check (rn, rib, nexthop, set))) + rib->nexthop_active_num++; + if (prev_active != new_active) + SET_FLAG (rib->flags, ZEBRA_FLAG_CHANGED); + } return rib->nexthop_active_num; } -- cgit v1.2.3 From f304cb48f0d7d0ff8f36e7aca8293141a9fa9e60 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Wed, 3 Oct 2007 12:27:16 +0000 Subject: + Minor bugfix: IPv6 prefixes were logged incorrectly in RIB debugging calls. Fixed. --- zebra/zebra_rib.c | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index e5cce1e8..67dc810a 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -992,12 +992,12 @@ rib_process (struct work_queue *wq, void *data) struct route_node *rn = data; int installed = 0; struct nexthop *nexthop = NULL; - char buf[INET_ADDRSTRLEN]; + char buf[INET6_ADDRSTRLEN]; assert (rn); if (IS_ZEBRA_DEBUG_RIB || IS_ZEBRA_DEBUG_RIB_Q) - inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); for (rib = rn->info; rib; rib = next) { @@ -1300,7 +1300,7 @@ static void rib_link (struct route_node *rn, struct rib *rib) { struct rib *head; - char buf[INET_ADDRSTRLEN]; + char buf[INET6_ADDRSTRLEN]; assert (rib && rn); @@ -1308,7 +1308,7 @@ rib_link (struct route_node *rn, struct rib *rib) if (IS_ZEBRA_DEBUG_RIB) { - inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%s: %s/%d: rn %p, rib %p", __func__, buf, rn->p.prefixlen, rn, rib); } @@ -1338,8 +1338,8 @@ rib_addnode (struct route_node *rn, struct rib *rib) { if (IS_ZEBRA_DEBUG_RIB) { - char buf[INET_ADDRSTRLEN]; - inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + char buf[INET6_ADDRSTRLEN]; + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%s: %s/%d: rn %p, un-removed rib %p", __func__, buf, rn->p.prefixlen, rn, rib); } @@ -1353,13 +1353,13 @@ static void rib_unlink (struct route_node *rn, struct rib *rib) { struct nexthop *nexthop, *next; - char buf[INET_ADDRSTRLEN]; + char buf[INET6_ADDRSTRLEN]; assert (rn && rib); if (IS_ZEBRA_DEBUG_RIB) { - inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%s: %s/%d: rn %p, rib %p", __func__, buf, rn->p.prefixlen, rn, rib); } @@ -1398,8 +1398,8 @@ rib_delnode (struct route_node *rn, struct rib *rib) { if (IS_ZEBRA_DEBUG_RIB) { - char buf[INET_ADDRSTRLEN]; - inet_ntop (AF_INET, &rn->p.u.prefix, buf, INET_ADDRSTRLEN); + char buf[INET6_ADDRSTRLEN]; + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); zlog_debug ("%s: %s/%d: rn %p, rib %p, removing", __func__, buf, rn->p.prefixlen, rn, rib); } -- cgit v1.2.3 From a3aaf5b0ceb8c5b3821793333b4057df872fbedd Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Thu, 4 Oct 2007 10:49:21 +0000 Subject: + rib_process() speedup for multi-nexthop route nodes --- zebra/zebra_rib.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 67dc810a..37b84a66 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1118,9 +1118,10 @@ rib_process (struct work_queue *wq, void *data) */ for (nexthop = select->nexthop; nexthop; nexthop = nexthop->next) + if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) { - if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)) - installed = 1; + installed = 1; + break; } if (! installed) rib_install_kernel (rn, select); -- cgit v1.2.3 From 3f087670efa606021cde2f6a9615ac7e07aec2a5 Mon Sep 17 00:00:00 2001 From: "Andrew J. Schorr" Date: Tue, 8 Jan 2008 20:12:46 +0000 Subject: [link-detect] Static interface routes should behave properly with link-detect. 2008-01-08 Michael Larson * zebra_rib.c: (nexthop_active_check) Replace if_is_up with if_is_operative to solve problems with static interface routes not behaving properly with link-detect. --- zebra/zebra_rib.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 37b84a66..e27c63bf 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -795,7 +795,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, { case NEXTHOP_TYPE_IFINDEX: ifp = if_lookup_by_index (nexthop->ifindex); - if (ifp && if_is_up (ifp)) + if (ifp && if_is_operative(ifp)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); @@ -804,7 +804,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, family = AFI_IP6; case NEXTHOP_TYPE_IFNAME: ifp = if_lookup_by_name (nexthop->ifname); - if (ifp && if_is_up (ifp)) + if (ifp && if_is_operative(ifp)) { if (set) nexthop->ifindex = ifp->ifindex; @@ -838,7 +838,7 @@ nexthop_active_check (struct route_node *rn, struct rib *rib, if (IN6_IS_ADDR_LINKLOCAL (&nexthop->gate.ipv6)) { ifp = if_lookup_by_index (nexthop->ifindex); - if (ifp && if_is_up (ifp)) + if (ifp && if_is_operative(ifp)) SET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); else UNSET_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE); -- cgit v1.2.3 From 20e5ff0a8893ffad6d31739d68d224931c4a7992 Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Tue, 26 Feb 2008 14:02:24 +0000 Subject: + fix bug#326 by rib_lookup_and_pushup() --- zebra/zebra_rib.c | 56 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index e27c63bf..c6af3290 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1614,6 +1614,62 @@ void rib_lookup_and_dump (struct prefix_ipv4 * p) } } +/* Check if requested address assignment will fail due to another + * route being installed by zebra in FIB already. Take necessary + * actions, if needed: remove such a route from FIB and deSELECT + * corresponding RIB entry. Then put affected RN into RIBQ head. + */ +void rib_lookup_and_pushup (struct prefix_ipv4 * p) +{ + struct route_table *table; + struct route_node *rn; + struct rib *rib; + unsigned changed = 0; + + if (NULL == (table = vrf_table (AFI_IP, SAFI_UNICAST, 0))) + { + zlog_err ("%s: vrf_table() returned NULL", __func__); + return; + } + + /* No matches would be the simplest case. */ + if (NULL == (rn = route_node_lookup (table, (struct prefix *) p))) + return; + + /* Unlock node. */ + route_unlock_node (rn); + + /* Check all RIB entries. In case any changes have to be done, requeue + * the RN into RIBQ head. If the routing message about the new connected + * route (generated by the IP address we are going to assign very soon) + * comes before the RIBQ is processed, the new RIB entry will join + * RIBQ record already on head. This is necessary for proper revalidation + * of the rest of the RIB. + */ + for (rib = rn->info; rib; rib = rib->next) + { + if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_SELECTED) && + ! RIB_SYSTEM_ROUTE (rib)) + { + changed = 1; + if (IS_ZEBRA_DEBUG_RIB) + { + char buf[INET_ADDRSTRLEN]; + inet_ntop (rn->p.family, &p->prefix, buf, INET_ADDRSTRLEN); + zlog_debug ("%s: freeing way for connected prefix %s/%d", __func__, buf, p->prefixlen); + rib_dump (__func__, (struct prefix_ipv4 *)&rn->p, rib); + } + rib_uninstall (rn, rib); + } + } + if (changed) + { + work_queue_aim_head (zebrad.ribq, 1); + rib_queue_add (&zebrad, rn); + work_queue_aim_head (zebrad.ribq, 0); + } +} + int rib_add_ipv4_multipath (struct prefix_ipv4 *p, struct rib *rib) { -- cgit v1.2.3 From e96f92034dad1a70c92ad4ad863a5259c122cecb Mon Sep 17 00:00:00 2001 From: Denis Ovsienko Date: Mon, 2 Jun 2008 12:03:22 +0000 Subject: + initial edition of meta-queue for RIB updates processing (bug #431) --- zebra/zebra_rib.c | 160 +++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 133 insertions(+), 27 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c6af3290..4cb72ba8 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -981,15 +981,14 @@ rib_uninstall (struct route_node *rn, struct rib *rib) static void rib_unlink (struct route_node *, struct rib *); /* Core function for processing routing information base. */ -static wq_item_status -rib_process (struct work_queue *wq, void *data) +static void +rib_process (struct route_node *rn) { struct rib *rib; struct rib *next; struct rib *fib = NULL; struct rib *select = NULL; struct rib *del = NULL; - struct route_node *rn = data; int installed = 0; struct nexthop *nexthop = NULL; char buf[INET6_ADDRSTRLEN]; @@ -1177,10 +1176,95 @@ rib_process (struct work_queue *wq, void *data) end: if (IS_ZEBRA_DEBUG_RIB_Q) zlog_debug ("%s: %s/%d: rn %p dequeued", __func__, buf, rn->p.prefixlen, rn); - if (rn->info) - UNSET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED); - route_unlock_node (rn); /* rib queue lock */ - return WQ_SUCCESS; +} + +/* Take a list of route_node structs and return 1, if there was a record picked from + * it and processed by rib_process(). Don't process more, than one RN record; operate + * only in the specified sub-queue. + */ +unsigned int +process_subq (struct list * subq, u_char qindex) +{ + struct listnode *lnode; + struct route_node *rnode; + if (!(lnode = listhead (subq))) + return 0; + rnode = listgetdata (lnode); + rib_process (rnode); + if (rnode->info) /* The first RIB record is holding the flags bitmask. */ + UNSET_FLAG (((struct rib *)rnode->info)->rn_status, RIB_ROUTE_QUEUED(qindex)); + route_unlock_node (rnode); + list_delete_node (subq, lnode); + return 1; +} + +/* Dispatch the meta queue by picking, processing and unlocking the next RN from + * a non-empty sub-queue with lowest priority. wq is equal to zebra->ribq and data + * is pointed to the meta queue structure. + */ +static wq_item_status +meta_queue_process (struct work_queue *dummy, void *data) +{ + struct meta_queue * mq = data; + u_char i; + for (i = 0; i < MQ_SIZE; i++) + if (process_subq (mq->subq[i], i)) + { + mq->size--; + break; + } + return mq->size ? WQ_REQUEUE : WQ_SUCCESS; +} + +/* Look into the RN and queue it into one or more priority queues, increasing the size + * for each data push done. + */ +void rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) +{ + u_char qindex; + struct rib *rib; + char buf[INET6_ADDRSTRLEN]; + if (IS_ZEBRA_DEBUG_RIB_Q) + inet_ntop (rn->p.family, &rn->p.u.prefix, buf, INET6_ADDRSTRLEN); + for (rib = rn->info; rib; rib = rib->next) + { + switch (rib->type) + { + case ZEBRA_ROUTE_KERNEL: + case ZEBRA_ROUTE_CONNECT: + qindex = 0; + break; + case ZEBRA_ROUTE_STATIC: + qindex = 1; + break; + case ZEBRA_ROUTE_RIP: + case ZEBRA_ROUTE_RIPNG: + case ZEBRA_ROUTE_OSPF: + case ZEBRA_ROUTE_OSPF6: + case ZEBRA_ROUTE_ISIS: + qindex = 2; + break; + case ZEBRA_ROUTE_BGP: + qindex = 3; + break; + default: + qindex = 4; + break; + } + /* Invariant: at this point we always have rn->info set. */ + if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex))) + { + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_debug ("%s: %s/%d: rn %p is already queued in sub-queue %u", __func__, buf, rn->p.prefixlen, rn, qindex); + continue; + } + SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED(qindex)); + listnode_add (mq->subq[qindex], rn); + route_lock_node (rn); + mq->size++; + if (IS_ZEBRA_DEBUG_RIB_Q) + zlog_debug ("%s: %s/%d: queued rn %p into sub-queue %u", __func__, buf, rn->p.prefixlen, rn, qindex); + } } /* Add route_node to work queue and schedule processing */ @@ -1202,17 +1286,6 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) return; } - /* Route-table node already queued, so nothing to do */ - if (CHECK_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED)) - { - if (IS_ZEBRA_DEBUG_RIB_Q) - zlog_debug ("%s: %s/%d: rn %p already queued", __func__, buf, - rn->p.prefixlen, rn); - return; - } - - route_lock_node (rn); /* rib queue lock */ - if (IS_ZEBRA_DEBUG_RIB_Q) zlog_info ("%s: %s/%d: work queue added", __func__, buf, rn->p.prefixlen); @@ -1221,13 +1294,21 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) if (zebra->ribq == NULL) { zlog_err ("%s: work_queue does not exist!", __func__); - route_unlock_node (rn); return; } - - work_queue_add (zebra->ribq, rn); - SET_FLAG (((struct rib *)rn->info)->rn_status, RIB_ROUTE_QUEUED); + /* The RIB queue should normally be either empty or holding the only work_queue_item + * element. In the latter case this element would hold a pointer to the meta queue + * structure, which must be used to actually queue the route nodes to process. So + * create the MQ holder, if necessary, then push the work into it in any case. + * This semantics was introduced after 0.99.9 release. + */ + + /* Should I invent work_queue_empty() and use it, or it's Ok to do as follows? */ + if (!zebra->ribq->items->count) + work_queue_add (zebra->ribq, zebra->mq); + + rib_meta_queue_add (zebra->mq, rn); if (IS_ZEBRA_DEBUG_RIB_Q) zlog_debug ("%s: %s/%d: rn %p queued", __func__, buf, rn->p.prefixlen, rn); @@ -1235,6 +1316,30 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) return; } +/* Create new meta queue. A destructor function doesn't seem to be necessary here. */ +struct meta_queue * +meta_queue_new () +{ + struct meta_queue *new; + unsigned i, failed = 0; + + if ((new = XCALLOC (MTYPE_WORK_QUEUE, sizeof (struct meta_queue))) == NULL) + return NULL; + for (i = 0; i < MQ_SIZE; i++) + if ((new->subq[i] = list_new ()) == NULL) + failed = 1; + if (failed) + { + for (i = 0; i < MQ_SIZE; i++) + if (new->subq[i]) + list_delete (new->subq[i]); + XFREE (MTYPE_WORK_QUEUE, new); + return NULL; + } + new->size = 0; + return new; +} + /* initialise zebra rib work queue */ static void rib_queue_init (struct zebra_t *zebra) @@ -1249,12 +1354,17 @@ rib_queue_init (struct zebra_t *zebra) } /* fill in the work queue spec */ - zebra->ribq->spec.workfunc = &rib_process; + zebra->ribq->spec.workfunc = &meta_queue_process; zebra->ribq->spec.errorfunc = NULL; /* XXX: TODO: These should be runtime configurable via vty */ zebra->ribq->spec.max_retries = 3; zebra->ribq->spec.hold = rib_process_hold_time; + if (!(zebra->mq = meta_queue_new ())) + { + zlog_err ("%s: could not initialise meta queue!", __func__); + return; + } return; } @@ -1663,11 +1773,7 @@ void rib_lookup_and_pushup (struct prefix_ipv4 * p) } } if (changed) - { - work_queue_aim_head (zebrad.ribq, 1); rib_queue_add (&zebrad, rn); - work_queue_aim_head (zebrad.ribq, 0); - } } int -- cgit v1.2.3 From 16814f9698a3ee14b1412286c53711a562c348fc Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 17 Aug 2008 17:39:31 +0100 Subject: [zebra] ignore dead routes in RIB update 2008-08-17 Stephen Hemminger * zebra_rib.c: When doing a RIB update, routes in process of removal should be ignored. This fixes bugs where a route is removed but a recursive route is not changed. Signed-off-by: Paul Jakma --- zebra/zebra_rib.c | 53 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 17 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 4cb72ba8..09f35978 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -376,8 +376,12 @@ nexthop_active_ipv4 (struct rib *rib, struct nexthop *nexthop, int set, /* Pick up selected route. */ for (match = rn->info; match; match = match->next) - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; + { + if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + } /* If there is no selected route or matched route is EGP, go up tree. */ @@ -473,8 +477,12 @@ nexthop_active_ipv6 (struct rib *rib, struct nexthop *nexthop, int set, /* Pick up selected route. */ for (match = rn->info; match; match = match->next) - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; + { + if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + } /* If there is no selected route or matched route is EGP, go up tree. */ @@ -560,8 +568,12 @@ rib_match_ipv4 (struct in_addr addr) /* Pick up selected route. */ for (match = rn->info; match; match = match->next) - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; + { + if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + } /* If there is no selected route or matched route is EGP, go up tree. */ @@ -613,10 +625,13 @@ rib_lookup_ipv4 (struct prefix_ipv4 *p) /* Unlock node. */ route_unlock_node (rn); - /* Pick up selected route. */ for (match = rn->info; match; match = match->next) - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; + { + if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + } if (! match || match->type == ZEBRA_ROUTE_BGP) return NULL; @@ -668,12 +683,12 @@ rib_lookup_ipv4_route (struct prefix_ipv4 *p, union sockunion * qgate) /* Find out if a "selected" RR for the discovered RIB entry exists ever. */ for (match = rn->info; match; match = match->next) - { - if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) - continue; - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; - } + { + if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + } /* None such found :( */ if (!match) @@ -735,8 +750,12 @@ rib_match_ipv6 (struct in6_addr *addr) /* Pick up selected route. */ for (match = rn->info; match; match = match->next) - if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) - break; + { + if (CHECK_FLAG (match->status, RIB_ENTRY_REMOVED)) + continue; + if (CHECK_FLAG (match->flags, ZEBRA_FLAG_SELECTED)) + break; + } /* If there is no selected route or matched route is EGP, go up tree. */ -- cgit v1.2.3 From d145bc008a03889fff8949890cb8c532ee6aff74 Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 17 Aug 2008 17:41:37 +0100 Subject: [zebra] make some data local 2008-06-17 Stephen Hemminger * zebra_rib.c: static qualifier on local data Signed-off-by: Paul Jakma --- zebra/zebra_rib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 09f35978..c88264ba 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -51,7 +51,7 @@ extern struct zebra_t zebrad; int rib_process_hold_time = 10; /* Each route type's string and default distance value. */ -struct +static const struct { int key; int distance; @@ -70,7 +70,7 @@ struct }; /* Vector for routing table. */ -vector vrf_vector; +static vector vrf_vector; /* Allocate new VRF. */ static struct vrf * -- cgit v1.2.3 From ef9b113e2d4c0d49bd7d61458fa9acc113658d2c Mon Sep 17 00:00:00 2001 From: Stephen Hemminger Date: Sun, 17 Aug 2008 17:44:47 +0100 Subject: [zebra] trivia: static qualifiers for metaq 2008-08-17 Stephen Hemminger * zebra_rib.c: (process_subq) mark static (rib_meta_queue_add) ditto (meta_queue_new) ditt Signed-off-by: Paul Jakma --- zebra/zebra_rib.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'zebra/zebra_rib.c') diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index c88264ba..90db932b 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1201,7 +1201,7 @@ end: * it and processed by rib_process(). Don't process more, than one RN record; operate * only in the specified sub-queue. */ -unsigned int +static unsigned int process_subq (struct list * subq, u_char qindex) { struct listnode *lnode; @@ -1238,7 +1238,8 @@ meta_queue_process (struct work_queue *dummy, void *data) /* Look into the RN and queue it into one or more priority queues, increasing the size * for each data push done. */ -void rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) +static void +rib_meta_queue_add (struct meta_queue *mq, struct route_node *rn) { u_char qindex; struct rib *rib; @@ -1336,8 +1337,8 @@ rib_queue_add (struct zebra_t *zebra, struct route_node *rn) } /* Create new meta queue. A destructor function doesn't seem to be necessary here. */ -struct meta_queue * -meta_queue_new () +static struct meta_queue * +meta_queue_new (void) { struct meta_queue *new; unsigned i, failed = 0; -- cgit v1.2.3