summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/user/ospf6d.rst2
-rw-r--r--doc/user/ospfd.rst2
-rw-r--r--doc/user/sharp.rst2
-rw-r--r--lib/atomlist.h10
-rw-r--r--lib/typerb.c5
-rw-r--r--lib/typerb.h23
-rw-r--r--lib/typesafe.c13
-rw-r--r--lib/typesafe.h45
-rw-r--r--sharpd/sharp_vty.c41
-rw-r--r--staticd/static_nht.c165
-rw-r--r--staticd/static_nht.h29
-rw-r--r--staticd/static_routes.c6
-rw-r--r--staticd/static_routes.h26
-rw-r--r--staticd/static_zebra.c22
-rw-r--r--staticd/static_zebra.h3
-rw-r--r--tests/lib/test_typelist.h16
-rw-r--r--tools/gen_northbound_callbacks.c73
-rw-r--r--zebra/zebra_rnh.c2
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)