diff options
| -rw-r--r-- | doc/user/ospf6d.rst | 2 | ||||
| -rw-r--r-- | doc/user/ospfd.rst | 2 | ||||
| -rw-r--r-- | doc/user/sharp.rst | 2 | ||||
| -rw-r--r-- | lib/atomlist.h | 10 | ||||
| -rw-r--r-- | lib/typerb.c | 5 | ||||
| -rw-r--r-- | lib/typerb.h | 23 | ||||
| -rw-r--r-- | lib/typesafe.c | 13 | ||||
| -rw-r--r-- | lib/typesafe.h | 45 | ||||
| -rw-r--r-- | sharpd/sharp_vty.c | 41 | ||||
| -rw-r--r-- | staticd/static_nht.c | 165 | ||||
| -rw-r--r-- | staticd/static_nht.h | 29 | ||||
| -rw-r--r-- | staticd/static_routes.c | 6 | ||||
| -rw-r--r-- | staticd/static_routes.h | 26 | ||||
| -rw-r--r-- | staticd/static_zebra.c | 22 | ||||
| -rw-r--r-- | staticd/static_zebra.h | 3 | ||||
| -rw-r--r-- | tests/lib/test_typelist.h | 16 | ||||
| -rw-r--r-- | tools/gen_northbound_callbacks.c | 73 | ||||
| -rw-r--r-- | zebra/zebra_rnh.c | 2 |
18 files changed, 372 insertions, 113 deletions
diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 6413c62995..2300cb0e19 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -195,7 +195,7 @@ Example of ospf6d configured on one interface and area: ipv6 ospf6 instance-id 0 ! router ospf6 - router-id 212.17.55.53 + ospf6 router-id 212.17.55.53 area 0.0.0.0 range 2001:770:105:2::/64 interface eth0 area 0.0.0.0 ! diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 83e14d474f..7dfadc472d 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -69,7 +69,7 @@ The instance number should be specified in the config when addressing a particul .. code-block:: frr router ospf 5 - router-id 1.2.3.4 + ospf router-id 1.2.3.4 area 0.0.0.0 authentication message-digest ... diff --git a/doc/user/sharp.rst b/doc/user/sharp.rst index 4568c2a901..111e9dc9e8 100644 --- a/doc/user/sharp.rst +++ b/doc/user/sharp.rst @@ -71,7 +71,7 @@ keyword. At present, no sharp commands will be preserved in the config. be used for pop and forward operations when the specified label is seen. .. index:: sharp watch -.. clicmd:: [no] sharp watch <nexthop|import> <A.B.C.D|X:X::X:X> [connected] +.. clicmd:: [no] sharp watch <nexthop <A.B.C.D|X:X::X:X>|import <A.B.C.D/M:X:X::X:X/M> [connected] Instruct zebra to monitor and notify sharp when the specified nexthop is changed. The notification from zebra is written into the debug log. diff --git a/lib/atomlist.h b/lib/atomlist.h index e4098ccb54..621db6824f 100644 --- a/lib/atomlist.h +++ b/lib/atomlist.h @@ -135,8 +135,10 @@ macro_inline void prefix ## _add_tail(struct prefix##_head *h, type *item) \ macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \ _Atomic atomptr_t *hint) \ { atomlist_del_hint(&h->ah, &item->field.ai, hint); } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ -{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); } \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ +{ atomlist_del_hint(&h->ah, &item->field.ai, NULL); \ + /* TODO: Return NULL if not found */ \ + return item; } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { char *p = (char *)atomlist_pop(&h->ah); \ return p ? (type *)(p - offsetof(type, field)) : NULL; } \ @@ -273,9 +275,11 @@ macro_inline void prefix ## _del_hint(struct prefix##_head *h, type *item, \ { \ atomsort_del_hint(&h->ah, &item->field.ai, hint); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ atomsort_del_hint(&h->ah, &item->field.ai, NULL); \ + /* TODO: Return NULL if not found */ \ + return item; \ } \ macro_inline size_t prefix ## _count(struct prefix##_head *h) \ { \ diff --git a/lib/typerb.c b/lib/typerb.c index 4c48d6434f..3886fc678e 100644 --- a/lib/typerb.c +++ b/lib/typerb.c @@ -333,9 +333,10 @@ color: return (old); } -void typed_rb_remove(struct rbt_tree *rbt, struct rb_entry *rbe) +struct typed_rb_entry *typed_rb_remove(struct rbt_tree *rbt, + struct rb_entry *rbe) { - rbe_remove(rbt, rbe); + return rbe_remove(rbt, rbe); } struct typed_rb_entry *typed_rb_insert(struct rbt_tree *rbt, diff --git a/lib/typerb.h b/lib/typerb.h index ce8446f853..2d7b0ba637 100644 --- a/lib/typerb.h +++ b/lib/typerb.h @@ -38,29 +38,30 @@ struct typed_rb_root { size_t count; }; -struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_insert(struct typed_rb_root *rbt, struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -void typed_rb_remove(struct typed_rb_root *, struct typed_rb_entry *rbe); -struct typed_rb_entry *typed_rb_find(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_remove(struct typed_rb_root *rbt, + struct typed_rb_entry *rbe); +struct typed_rb_entry *typed_rb_find(struct typed_rb_root *rbt, const struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_find_gteq(struct typed_rb_root *rbt, const struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *, +struct typed_rb_entry *typed_rb_find_lt(struct typed_rb_root *rbt, const struct typed_rb_entry *rbe, int (*cmpfn)( const struct typed_rb_entry *a, const struct typed_rb_entry *b)); -struct typed_rb_entry *typed_rb_min(struct typed_rb_root *); -struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *); +struct typed_rb_entry *typed_rb_min(struct typed_rb_root *rbt); +struct typed_rb_entry *typed_rb_next(struct typed_rb_entry *rbe); #define _PREDECL_RBTREE(prefix) \ struct prefix ## _head { struct typed_rb_root rr; }; \ @@ -99,9 +100,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ re = typed_rb_find_lt(&h->rr, &item->field.re, cmpfn_nuq); \ return container_of_null(re, type, field.re); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ - typed_rb_remove(&h->rr, &item->field.re); \ + struct typed_rb_entry *re; \ + re = typed_rb_remove(&h->rr, &item->field.re); \ + return container_of_null(re, type, field.re); \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -130,7 +133,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ re = item ? typed_rb_next(&item->field.re) : NULL; \ return container_of_null(re, type, field.re); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->rr.count; \ } \ diff --git a/lib/typesafe.c b/lib/typesafe.c index f2ca67b7c6..7e5939d5b3 100644 --- a/lib/typesafe.c +++ b/lib/typesafe.c @@ -341,13 +341,14 @@ struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head, return best; } -void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, - int (*cmpfn)(const struct sskip_item *a, - const struct sskip_item *b)) +struct sskip_item *typesafe_skiplist_del( + struct sskip_head *head, struct sskip_item *item, + int (*cmpfn)(const struct sskip_item *a, const struct sskip_item *b)) { size_t level = SKIPLIST_MAXDEPTH; struct sskip_item *prev = &head->hitem, *next; int cmpval; + bool found = false; while (level) { next = sl_level_get(prev, level - 1); @@ -359,6 +360,7 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, sl_level_set(prev, level - 1, sl_level_get(item, level - 1)); level--; + found = true; continue; } cmpval = cmpfn(next, item); @@ -369,6 +371,9 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, level--; } + if (!found) + return NULL; + /* TBD: assert when trying to remove non-existing item? */ head->count--; @@ -379,6 +384,8 @@ void typesafe_skiplist_del(struct sskip_head *head, struct sskip_item *item, XFREE(MTYPE_SKIPLIST_OFLOW, oflow); } memset(item, 0, sizeof(*item)); + + return item; } struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head) diff --git a/lib/typesafe.h b/lib/typesafe.h index ee244c78ae..c30d73d1b3 100644 --- a/lib/typesafe.h +++ b/lib/typesafe.h @@ -109,17 +109,18 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \ typesafe_list_add(&h->sh, nextp, &item->field.si); \ } \ /* TODO: del_hint */ \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct slist_item **iter = &h->sh.first; \ while (*iter && *iter != &item->field.si) \ iter = &(*iter)->next; \ if (!*iter) \ - return; \ + return NULL; \ h->sh.count--; \ *iter = item->field.si.next; \ if (!item->field.si.next) \ h->sh.last_next = iter; \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -149,7 +150,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ sitem = &item->field.si; \ return container_of_null(sitem->next, type, field.si); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ @@ -212,13 +213,14 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \ prev = after ? &after->field.di : &h->dh.hitem; \ typesafe_dlist_add(&h->dh, prev, &item->field.di); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct dlist_item *ditem = &item->field.di; \ ditem->prev->next = ditem->next; \ ditem->next->prev = ditem->prev; \ h->dh.count--; \ ditem->prev = ditem->next = NULL; \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -250,7 +252,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ return NULL; \ return prefix ## _next(h, item); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->dh.count; \ } \ @@ -308,7 +310,7 @@ macro_inline type *prefix ## _add(struct prefix##_head *h, type *item) \ h->hh.count++; \ return NULL; \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct heap_item *other; \ uint32_t index = item->field.hi.index; \ @@ -321,6 +323,7 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ typesafe_heap_pushdown(&h->hh, index, other, prefix ## __cmp); \ if (HEAP_RESIZE_TRESH_DN(h)) \ typesafe_heap_resize(&h->hh, false); \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -354,7 +357,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ return NULL; \ return prefix ## _next(h, item); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ @@ -449,15 +452,16 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ return container_of_null(prev, type, field.si); \ } \ /* TODO: del_hint */ \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct ssort_item **iter = &h->sh.first; \ while (*iter && *iter != &item->field.si) \ iter = &(*iter)->next; \ if (!*iter) \ - return; \ + return NULL; \ h->sh.count--; \ *iter = item->field.si.next; \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -485,7 +489,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ sitem = &item->field.si; \ return container_of_null(sitem->next, type, field.si); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ @@ -617,10 +621,10 @@ macro_inline type *prefix ## _find(struct prefix##_head *h, const type *item) \ } \ return NULL; \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ if (!h->hh.tabshift) \ - return; \ + return NULL; \ uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \ struct thash_item **np = &h->hh.entries[hbits]; \ while (*np && (*np)->hashval < hval) \ @@ -628,12 +632,13 @@ macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ while (*np && *np != &item->field.hi && (*np)->hashval == hval) \ np = &(*np)->next; \ if (*np != &item->field.hi) \ - return; \ + return NULL; \ *np = item->field.hi.next; \ item->field.hi.next = NULL; \ h->hh.count--; \ if (HASH_SHRINK_THRESHOLD(h->hh)) \ typesafe_hash_shrink(&h->hh); \ + return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -675,7 +680,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ return NULL; \ return prefix ## _next(h, item); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ @@ -751,9 +756,11 @@ macro_inline type *prefix ## _find_lt(struct prefix##_head *h, \ &item->field.si, cmpfn_nuq); \ return container_of_null(sitem, type, field.si); \ } \ -macro_inline void prefix ## _del(struct prefix##_head *h, type *item) \ +macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ - typesafe_skiplist_del(&h->sh, &item->field.si, cmpfn_uq); \ + struct sskip_item *sitem = typesafe_skiplist_del(&h->sh, \ + &item->field.si, cmpfn_uq); \ + return container_of_null(sitem, type, field.si); \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ @@ -776,7 +783,7 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ next = item ? item->field.si.next[0] : NULL; \ return container_of_null(next, type, field.si); \ } \ -macro_pure size_t prefix ## _count(struct prefix##_head *h) \ +macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ @@ -848,8 +855,8 @@ extern struct sskip_item *typesafe_skiplist_find_lt(struct sskip_head *head, const struct sskip_item *item, int (*cmpfn)( const struct sskip_item *a, const struct sskip_item *b)); -extern void typesafe_skiplist_del(struct sskip_head *head, - struct sskip_item *item, int (*cmpfn)( +extern struct sskip_item *typesafe_skiplist_del( + struct sskip_head *head, struct sskip_item *item, int (*cmpfn)( const struct sskip_item *a, const struct sskip_item *b)); extern struct sskip_item *typesafe_skiplist_pop(struct sskip_head *head); diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index a7552547e9..60cfb2e486 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -39,14 +39,15 @@ #endif DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, - "sharp watch [vrf NAME$name] <nexthop$n|import$import> X:X::X:X$nhop [connected$connected]", + "sharp watch [vrf NAME$name] <nexthop$n X:X::X:X$nhop|import$import X:X::X:X/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" "The NAME of the vrf\n" "Watch for nexthop changes\n" - "Watch for import check changes\n" "The v6 nexthop to signal for watching\n" + "Watch for import check changes\n" + "The v6 prefix to signal for watching\n" "Should the route be connected\n") { struct vrf *vrf; @@ -62,16 +63,17 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, return CMD_WARNING; } - if (n) - type_import = false; - else - type_import = true; - memset(&p, 0, sizeof(p)); - p.prefixlen = 128; - memcpy(&p.u.prefix6, &nhop, 16); - p.family = AF_INET6; + if (n) { + type_import = false; + p.prefixlen = 128; + memcpy(&p.u.prefix6, &nhop, 16); + p.family = AF_INET6; + } else { + type_import = true; + p = *(const struct prefix *)inhop; + } sharp_nh_tracker_get(&p); sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, @@ -81,14 +83,15 @@ DEFPY(watch_nexthop_v6, watch_nexthop_v6_cmd, } DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, - "sharp watch [vrf NAME$name] <nexthop$n|import$import> A.B.C.D$nhop [connected$connected]", + "sharp watch [vrf NAME$name] <nexthop$n A.B.C.D$nhop|import$import A.B.C.D/M$inhop> [connected$connected]", "Sharp routing Protocol\n" "Watch for changes\n" "The vrf we would like to watch if non-default\n" "The NAME of the vrf\n" "Watch for nexthop changes\n" + "The v4 address to signal for watching\n" "Watch for import check changes\n" - "The v4 nexthop to signal for watching\n" + "The v4 prefix for import check to watch\n" "Should the route be connected\n") { struct vrf *vrf; @@ -106,14 +109,16 @@ DEFPY(watch_nexthop_v4, watch_nexthop_v4_cmd, memset(&p, 0, sizeof(p)); - if (n) + if (n) { type_import = false; - else + p.prefixlen = 32; + p.u.prefix4 = nhop; + p.family = AF_INET; + } + else { type_import = true; - - p.prefixlen = 32; - p.u.prefix4 = nhop; - p.family = AF_INET; + p = *(const struct prefix *)inhop; + } sharp_nh_tracker_get(&p); sharp_zebra_nexthop_watch(&p, vrf->vrf_id, type_import, diff --git a/staticd/static_nht.c b/staticd/static_nht.c index 2aa0db59f1..1a2ddd7f05 100644 --- a/staticd/static_nht.c +++ b/staticd/static_nht.c @@ -23,18 +23,48 @@ #include "table.h" #include "vrf.h" #include "nexthop.h" +#include "srcdest_table.h" #include "static_vrf.h" #include "static_routes.h" #include "static_zebra.h" #include "static_nht.h" -static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, - afi_t afi, safi_t safi, struct vrf *vrf, - vrf_id_t nh_vrf_id) +static void static_nht_update_rn(struct route_node *rn, + struct prefix *nhp, uint32_t nh_num, + vrf_id_t nh_vrf_id, struct vrf *vrf, + safi_t safi) { - struct route_table *stable; struct static_route *si; + + for (si = rn->info; si; si = si->next) { + if (si->nh_vrf_id != nh_vrf_id) + continue; + + if (si->type != STATIC_IPV4_GATEWAY + && si->type != STATIC_IPV4_GATEWAY_IFNAME + && si->type != STATIC_IPV6_GATEWAY + && si->type != STATIC_IPV6_GATEWAY_IFNAME) + continue; + + if (nhp->family == AF_INET + && nhp->u.prefix4.s_addr == si->addr.ipv4.s_addr) + si->nh_valid = !!nh_num; + + if (nhp->family == AF_INET6 + && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) == 0) + si->nh_valid = !!nh_num; + + if (si->state == STATIC_START) + static_zebra_route_add(rn, si, vrf->vrf_id, safi, true); + } +} + +static void static_nht_update_safi(struct prefix *sp, struct prefix *nhp, + uint32_t nh_num, afi_t afi, safi_t safi, + struct vrf *vrf, vrf_id_t nh_vrf_id) +{ + struct route_table *stable; struct static_vrf *svrf; struct route_node *rn; @@ -46,40 +76,129 @@ static void static_nht_update_safi(struct prefix *p, uint32_t nh_num, if (!stable) return; + if (sp) { + rn = srcdest_rnode_lookup(stable, sp, NULL); + if (rn) { + static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id, + vrf, safi); + route_unlock_node(rn); + } + return; + } + + for (rn = route_top(stable); rn; rn = route_next(rn)) + static_nht_update_rn(rn, nhp, nh_num, nh_vrf_id, vrf, safi); + +} + +void static_nht_update(struct prefix *sp, struct prefix *nhp, + uint32_t nh_num, afi_t afi, vrf_id_t nh_vrf_id) +{ + + struct vrf *vrf; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + static_nht_update_safi(sp, nhp, nh_num, afi, SAFI_UNICAST, + vrf, nh_vrf_id); + static_nht_update_safi(sp, nhp, nh_num, afi, SAFI_MULTICAST, + vrf, nh_vrf_id); + } +} + +static void static_nht_reset_start_safi(struct prefix *nhp, afi_t afi, + safi_t safi, struct vrf *vrf, + vrf_id_t nh_vrf_id) +{ + struct static_vrf *svrf; + struct route_table *stable; + struct static_route *si; + struct route_node *rn; + + svrf = vrf->info; + if (!svrf) + return; + + stable = static_vrf_static_table(afi, safi, svrf); + if (!stable) + return; + for (rn = route_top(stable); rn; rn = route_next(rn)) { for (si = rn->info; si; si = si->next) { if (si->nh_vrf_id != nh_vrf_id) continue; - if (si->type != STATIC_IPV4_GATEWAY - && si->type != STATIC_IPV4_GATEWAY_IFNAME - && si->type != STATIC_IPV6_GATEWAY - && si->type != STATIC_IPV6_GATEWAY_IFNAME) + if (nhp->family == AF_INET + && nhp->u.prefix4.s_addr != si->addr.ipv4.s_addr) continue; - if (p->family == AF_INET - && p->u.prefix4.s_addr == si->addr.ipv4.s_addr) - si->nh_valid = !!nh_num; - - if (p->family == AF_INET6 - && memcmp(&p->u.prefix6, &si->addr.ipv6, 16) == 0) - si->nh_valid = !!nh_num; + if (nhp->family == AF_INET6 + && memcmp(&nhp->u.prefix6, &si->addr.ipv6, 16) != 0) + continue; - static_zebra_route_add(rn, si, vrf->vrf_id, safi, true); + /* + * We've been told that a nexthop we depend + * on has changed in some manner, so reset + * the state machine to allow us to start + * over. + */ + si->state = STATIC_START; } } } -void static_nht_update(struct prefix *p, uint32_t nh_num, afi_t afi, - vrf_id_t nh_vrf_id) +void static_nht_reset_start(struct prefix *nhp, afi_t afi, vrf_id_t nh_vrf_id) { - struct vrf *vrf; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - static_nht_update_safi(p, nh_num, afi, SAFI_UNICAST, - vrf, nh_vrf_id); - static_nht_update_safi(p, nh_num, afi, SAFI_MULTICAST, - vrf, nh_vrf_id); + static_nht_reset_start_safi(nhp, afi, SAFI_UNICAST, + vrf, nh_vrf_id); + static_nht_reset_start_safi(nhp, afi, SAFI_MULTICAST, + vrf, nh_vrf_id); } } + +static void static_nht_mark_state_safi(struct prefix *sp, afi_t afi, + safi_t safi, struct vrf *vrf, + enum static_install_states state) +{ + struct static_vrf *svrf; + struct route_table *stable; + struct static_route *si; + struct route_node *rn; + + svrf = vrf->info; + if (!svrf) + return; + + stable = static_vrf_static_table(afi, safi, svrf); + if (!stable) + return; + + rn = srcdest_rnode_lookup(stable, sp, NULL); + if (!rn) + return; + + for (si = rn->info; si; si = si->next) + si->state = state; + + route_unlock_node(rn); +} + +void static_nht_mark_state(struct prefix *sp, vrf_id_t vrf_id, + enum static_install_states state) +{ + struct vrf *vrf; + + afi_t afi = AFI_IP; + + if (sp->family == AF_INET6) + afi = AFI_IP6; + + vrf = vrf_lookup_by_id(vrf_id); + if (!vrf || !vrf->info) + return; + + static_nht_mark_state_safi(sp, afi, SAFI_UNICAST, vrf, state); + static_nht_mark_state_safi(sp, afi, SAFI_MULTICAST, vrf, state); +} diff --git a/staticd/static_nht.h b/staticd/static_nht.h index f273c71bba..18bb9e39ca 100644 --- a/staticd/static_nht.h +++ b/staticd/static_nht.h @@ -20,6 +20,31 @@ #ifndef __STATIC_NHT_H__ #define __STATIC_NHT_H__ -extern void static_nht_update(struct prefix *p, uint32_t nh_num, - afi_t afi, vrf_id_t vrf_id); +/* + * When we get notification that nexthop tracking has an answer for + * us call this function to find the nexthop we are tracking so it + * can be installed or removed. + * + * sp -> The route we are looking at. If NULL then look at all + * routes. + * nhp -> The nexthop that is being tracked. + * nh_num -> number of valid nexthops. + * afi -> The afi we are working in. + * vrf_id -> The vrf the nexthop is in. + */ +extern void static_nht_update(struct prefix *sp, struct prefix *nhp, + uint32_t nh_num, afi_t afi, vrf_id_t vrf_id); + +/* + * For the given tracked nexthop, nhp, mark all routes that use + * this route as in starting state again. + */ +extern void static_nht_reset_start(struct prefix *nhp, afi_t afi, + vrf_id_t nh_vrf_id); + +/* + * For the given prefix, sp, mark it as in a particular state + */ +extern void static_nht_mark_state(struct prefix *sp, vrf_id_t vrf_id, + enum static_install_states state); #endif diff --git a/staticd/static_routes.c b/staticd/static_routes.c index 5f9ecad694..b2c61bcbab 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -39,7 +39,7 @@ static void static_install_route(struct route_node *rn, struct static_route *si; for (si = rn->info; si; si = si->next) - static_zebra_nht_register(si, true); + static_zebra_nht_register(rn, si, true); si = rn->info; if (si) @@ -183,7 +183,7 @@ int static_add_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, /* check whether interface exists in system & install if it does */ if (!ifname) - static_install_route(rn, si, safi); + static_zebra_nht_register(rn, si, true); else { struct interface *ifp; @@ -242,7 +242,7 @@ int static_delete_route(afi_t afi, safi_t safi, uint8_t type, struct prefix *p, return 0; } - static_zebra_nht_register(si, false); + static_zebra_nht_register(rn, si, false); /* Unlink static route from linked list. */ if (si->prev) diff --git a/staticd/static_routes.h b/staticd/static_routes.h index 6036bfe396..6414947b16 100644 --- a/staticd/static_routes.h +++ b/staticd/static_routes.h @@ -44,6 +44,26 @@ typedef enum { STATIC_IPV6_GATEWAY_IFNAME, } static_types; +/* + * Route Creation gives us: + * START -> Initial State, only exit is when we send the route to + * zebra for installation + * When we send the route to Zebra move to SENT_TO_ZEBRA + * SENT_TO_ZEBRA -> A way to notice that we've sent the route to zebra + * But have not received a response on it's status yet + * After The response from zebra we move to INSTALLED or FAILED + * INSTALLED -> Route was accepted + * FAILED -> Route was rejected + * When we receive notification about a nexthop that a route uses + * We move the route back to START and initiate the process again. + */ +enum static_install_states { + STATIC_START, + STATIC_SENT_TO_ZEBRA, + STATIC_INSTALLED, + STATIC_NOT_INSTALLED, +}; + /* Static route information. */ struct static_route { /* For linked list. */ @@ -55,6 +75,12 @@ struct static_route { vrf_id_t nh_vrf_id; char nh_vrfname[VRF_NAMSIZ + 1]; + /* + * States that we walk the route through + * To know where we are. + */ + enum static_install_states state; + /* Administrative distance. */ uint8_t distance; diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index c6da00418b..13c04259d7 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -43,6 +43,8 @@ #include "static_nht.h" #include "static_vty.h" +bool debug; + /* Zebra structure to hold current status. */ struct zclient *zclient; static struct hash *static_nht_hash; @@ -154,18 +156,23 @@ static int route_notify_owner(ZAPI_CALLBACK_ARGS) switch (note) { case ZAPI_ROUTE_FAIL_INSTALL: + static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED); zlog_warn("%s: Route %s failed to install for table: %u", __PRETTY_FUNCTION__, buf, table_id); break; case ZAPI_ROUTE_BETTER_ADMIN_WON: + static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED); zlog_warn("%s: Route %s over-ridden by better route for table: %u", __PRETTY_FUNCTION__, buf, table_id); break; case ZAPI_ROUTE_INSTALLED: + static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED); break; case ZAPI_ROUTE_REMOVED: + static_nht_mark_state(&p, vrf_id, STATIC_NOT_INSTALLED); break; case ZAPI_ROUTE_REMOVE_FAIL: + static_nht_mark_state(&p, vrf_id, STATIC_INSTALLED); zlog_warn("%s: Route %s failure to remove for table: %u", __PRETTY_FUNCTION__, buf, table_id); break; @@ -210,7 +217,8 @@ static int static_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) if (nhtd) { nhtd->nh_num = nhr.nexthop_num; - static_nht_update(&nhr.prefix, nhr.nexthop_num, afi, + static_nht_reset_start(&nhr.prefix, afi, nhtd->nh_vrf_id); + static_nht_update(NULL, &nhr.prefix, nhr.nexthop_num, afi, nhtd->nh_vrf_id); } else zlog_err("No nhtd?"); @@ -267,7 +275,8 @@ static void static_nht_hash_free(void *data) XFREE(MTYPE_TMP, nhtd); } -void static_zebra_nht_register(struct static_route *si, bool reg) +void static_zebra_nht_register(struct route_node *rn, + struct static_route *si, bool reg) { struct static_nht_data *nhtd, lookup; uint32_t cmd; @@ -315,8 +324,11 @@ void static_zebra_nht_register(struct static_route *si, bool reg) static_nht_hash_alloc); nhtd->refcount++; - if (nhtd->refcount > 1) { - static_nht_update(nhtd->nh, nhtd->nh_num, + if (debug) + zlog_debug("Registered nexthop(%pFX) for %pRN %d", &p, + rn, nhtd->nh_num); + if (nhtd->refcount > 1 && nhtd->nh_num) { + static_nht_update(&rn->p, nhtd->nh, nhtd->nh_num, afi, si->nh_vrf_id); return; } @@ -389,6 +401,8 @@ extern void static_zebra_route_add(struct route_node *rn, api_nh->vrf_id = si->nh_vrf_id; api_nh->onlink = si->onlink; + si->state = STATIC_SENT_TO_ZEBRA; + switch (si->type) { case STATIC_IFNAME: if (si->ifindex == IFINDEX_INTERNAL) diff --git a/staticd/static_zebra.h b/staticd/static_zebra.h index a82eb162e1..15f5410b81 100644 --- a/staticd/static_zebra.h +++ b/staticd/static_zebra.h @@ -21,7 +21,8 @@ extern struct thread_master *master; -extern void static_zebra_nht_register(struct static_route *si, bool reg); +extern void static_zebra_nht_register(struct route_node *rn, + struct static_route *si, bool reg); extern void static_zebra_route_add(struct route_node *rn, struct static_route *si_changed, diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h index b288f0bd8e..7ff210cae3 100644 --- a/tests/lib/test_typelist.h +++ b/tests/lib/test_typelist.h @@ -209,7 +209,7 @@ static void concat(test_, TYPE)(void) assert(list_add(&head, &dummy) == &itm[j]); else { assert(list_add(&head, &dummy) == NULL); - list_del(&head, &dummy); + assert(list_del(&head, &dummy) != NULL); } } ts_hashx("add-dup", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); @@ -255,7 +255,7 @@ static void concat(test_, TYPE)(void) list_first(&head) == &dummy); } else if (list_next(&head, &dummy)) assert(list_next(&head, &dummy)->val > j); - list_del(&head, &dummy); + assert(list_del(&head, &dummy) != NULL); } ts_hash("add-dup+find_{lt,gteq}", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); #endif @@ -295,7 +295,7 @@ static void concat(test_, TYPE)(void) (void)prng_rand(prng); j = prng_rand(prng) % NITEM; if (itm[j].scratchpad == 1) { - list_del(&head, &itm[j]); + assert(list_del(&head, &itm[j]) != NULL); itm[j].scratchpad = 0; l++; } @@ -307,7 +307,7 @@ static void concat(test_, TYPE)(void) assert(item->scratchpad != 0); if (item->val & 1) { - list_del(&head, item); + assert(list_del(&head, item) != NULL); item->scratchpad = 0; l++; } @@ -333,7 +333,7 @@ static void concat(test_, TYPE)(void) for (i = 0; i < NITEM / 2; i++) { j = prng_rand(prng) % NITEM; if (itm[j].scratchpad == 1) { - list_del(&head, &itm[j]); + assert(list_del(&head, &itm[j]) != NULL); itm[j].scratchpad = 0; k--; } @@ -371,7 +371,7 @@ static void concat(test_, TYPE)(void) for (i = 0; i < NITEM / 2; i++) { j = prng_rand(prng) % NITEM; if (itm[j].scratchpad == 1) { - list_del(&head, &itm[j]); + assert(list_del(&head, &itm[j]) != NULL); itm[j].scratchpad = 0; k--; } @@ -424,7 +424,7 @@ static void concat(test_, TYPE)(void) item = &itm[j]; if (item->scratchpad == 0) continue; - list_del(&head, item); + assert(list_del(&head, item) != NULL); } item->scratchpad = 0; k--; @@ -469,7 +469,7 @@ static void concat(test_, TYPE)(void) item = &itm[j]; if (item->scratchpad == 0) continue; - list_del(&head, item); + assert(list_del(&head, item) != NULL); } item->scratchpad = 0; k--; diff --git a/tools/gen_northbound_callbacks.c b/tools/gen_northbound_callbacks.c index f6c757f5d7..14f648e8da 100644 --- a/tools/gen_northbound_callbacks.c +++ b/tools/gen_northbound_callbacks.c @@ -28,7 +28,8 @@ static void __attribute__((noreturn)) usage(int status) { - fprintf(stderr, "usage: gen_northbound_callbacks [-h] MODULE\n"); + extern const char *__progname; + fprintf(stderr, "usage: %s [-h] [-p path] MODULE\n", __progname); exit(status); } @@ -152,6 +153,36 @@ static void generate_callback_name(struct lys_node *snode, replace_hyphens_by_underscores(buffer); } +static void generate_callback(const struct nb_callback_info *ncinfo, + const char *cb_name) +{ + printf("static %s%s(%s)\n{\n", + ncinfo->return_type, cb_name, ncinfo->arguments); + + switch (ncinfo->operation) { + case NB_OP_CREATE: + case NB_OP_MODIFY: + case NB_OP_DESTROY: + case NB_OP_MOVE: + printf("\tswitch (event) {\n" + "\tcase NB_EV_VALIDATE:\n" + "\tcase NB_EV_PREPARE:\n" + "\tcase NB_EV_ABORT:\n" + "\tcase NB_EV_APPLY:\n" + "\t\t/* TODO: implement me. */\n" + "\t\tbreak;\n" + "\t}\n\n" + ); + break; + + default: + printf("\t/* TODO: implement me. */\n"); + break; + } + + printf("\treturn %s;\n}\n\n", ncinfo->return_value); +} + static int generate_callbacks(const struct lys_node *snode, void *arg) { bool first = true; @@ -191,14 +222,7 @@ static int generate_callbacks(const struct lys_node *snode, void *arg) generate_callback_name((struct lys_node *)snode, cb->operation, cb_name, sizeof(cb_name)); - printf("static %s%s(%s)\n" - "{\n" - "\t/* TODO: implement me. */\n" - "\treturn %s;\n" - "}\n\n", - nb_callbacks[cb->operation].return_type, cb_name, - nb_callbacks[cb->operation].arguments, - nb_callbacks[cb->operation].return_value); + generate_callback(cb, cb_name); } return YANG_ITER_CONTINUE; @@ -237,32 +261,52 @@ static int generate_nb_nodes(const struct lys_node *snode, void *arg) printf("\t\t{\n" "\t\t\t.xpath = \"%s\",\n", xpath); + printf("\t\t\t.cbs = {\n"); first = false; } generate_callback_name((struct lys_node *)snode, cb->operation, cb_name, sizeof(cb_name)); - printf("\t\t\t.cbs.%s = %s,\n", - nb_operation_name(cb->operation), cb_name); + printf("\t\t\t\t.%s = %s,\n", nb_operation_name(cb->operation), + cb_name); } - if (!first) + if (!first) { + printf("\t\t\t}\n"); printf("\t\t},\n"); + } return YANG_ITER_CONTINUE; } int main(int argc, char *argv[]) { + const char *search_path = NULL; struct yang_module *module; char module_name_underscores[64]; + struct stat st; int opt; - while ((opt = getopt(argc, argv, "h")) != -1) { + while ((opt = getopt(argc, argv, "hp:")) != -1) { switch (opt) { case 'h': usage(EXIT_SUCCESS); /* NOTREACHED */ + case 'p': + if (stat(optarg, &st) == -1) { + fprintf(stderr, + "error: invalid search path '%s': %s\n", + optarg, strerror(errno)); + exit(EXIT_FAILURE); + } + if (S_ISDIR(st.st_mode) == 0) { + fprintf(stderr, + "error: search path is not directory"); + exit(EXIT_FAILURE); + } + + search_path = optarg; + break; default: usage(EXIT_FAILURE); /* NOTREACHED */ @@ -275,6 +319,9 @@ int main(int argc, char *argv[]) yang_init(); + if (search_path) + ly_ctx_set_searchdir(ly_native_ctx, search_path); + /* Load all FRR native models to ensure all augmentations are loaded. */ yang_module_load_all(); module = yang_module_find(argv[0]); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 0397b96983..da2fe4a30c 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -924,7 +924,7 @@ void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, } for (rn = route_top(table); rn; rn = route_next(rn)) { - if (p && prefix_cmp(&rn->p, p) != 0) + if (p && !prefix_match(&rn->p, p)) continue; if (rn->info) |
