summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/route_types.txt2
-rw-r--r--zebra/zapi_msg.c38
-rw-r--r--zebra/zebra_nhg.c176
-rw-r--r--zebra/zebra_nhg.h60
-rw-r--r--zebra/zebra_vty.c2
5 files changed, 217 insertions, 61 deletions
diff --git a/lib/route_types.txt b/lib/route_types.txt
index b549c11cfc..37cc2fb590 100644
--- a/lib/route_types.txt
+++ b/lib/route_types.txt
@@ -84,7 +84,7 @@ ZEBRA_ROUTE_PBR, pbr, pbrd, 'F', 1, 1, 0, "PBR"
ZEBRA_ROUTE_BFD, bfd, bfdd, '-', 0, 0, 0, "BFD"
ZEBRA_ROUTE_OPENFABRIC, openfabric, fabricd, 'f', 1, 1, 1, "OpenFabric"
ZEBRA_ROUTE_VRRP, vrrp, vrrpd, '-', 0, 0, 0, "VRRP"
-ZEBRA_ROUTE_NHG, nhg, none, '-', 0, 0, 0, "Nexthop Group"
+ZEBRA_ROUTE_NHG, zebra, none, '-', 0, 0, 0, "Nexthop Group"
ZEBRA_ROUTE_SRTE, srte, none, '-', 0, 0, 0, "SR-TE"
ZEBRA_ROUTE_ALL, wildcard, none, '-', 0, 0, 0, "-"
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index 7c00ae1032..dfcab080f1 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -1734,16 +1734,22 @@ static void zread_nhg_del(ZAPI_HANDLER_ARGS)
struct stream *s = msg;
uint32_t id;
uint16_t proto;
+ struct nhg_hash_entry *nhe;
STREAM_GETW(s, proto);
STREAM_GETL(s, id);
/*
* Delete the received nhg id
- * id is incremented to make compiler happy right now
- * it should be removed in future code work.
*/
- nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVED);
+
+ nhe = zebra_nhg_proto_del(id);
+
+ if (nhe) {
+ zebra_nhg_uninstall_kernel(nhe);
+ nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVED);
+ } else
+ nhg_notify(proto, client->instance, id, ZAPI_NHG_REMOVE_FAIL);
return;
@@ -1762,6 +1768,7 @@ static void zread_nhg_reader(ZAPI_HANDLER_ARGS)
struct nexthop_group *nhg = NULL;
struct prefix p;
uint16_t proto;
+ struct nhg_hash_entry *nhe;
memset(&p, 0, sizeof(p));
@@ -1771,8 +1778,9 @@ static void zread_nhg_reader(ZAPI_HANDLER_ARGS)
STREAM_GETL(s, id);
STREAM_GETW(s, nhops);
- if (zserv_nexthop_num_warn(__func__, &p, nhops))
- return;
+ // TODO: Can't use this without a prefix.
+ // if (zserv_nexthop_num_warn(__func__, &p, nhops))
+ // return;
for (i = 0; i < nhops; i++) {
struct zapi_nexthop *znh = &zapi_nexthops[i];
@@ -1792,10 +1800,28 @@ static void zread_nhg_reader(ZAPI_HANDLER_ARGS)
__func__);
return;
}
+
/*
* Install the nhg
*/
- nhg_notify(proto, client->instance, id, ZAPI_NHG_INSTALLED);
+
+ // TODO: Forcing AF_UNSPEC/AF_IP for now
+ nhe = zebra_nhg_proto_add(id, ZEBRA_ROUTE_BGP, nhg,
+ ((nhops > 1) ? AFI_UNSPEC : AFI_IP));
+
+ nexthop_group_delete(&nhg);
+
+ /*
+ * TODO:
+ * Assume fully resolved for now and install.
+ *
+ * Resolution is going to need some more work.
+ */
+ if (nhe) {
+ zebra_nhg_install_kernel(nhe);
+ nhg_notify(proto, client->instance, id, ZAPI_NHG_INSTALLED);
+ } else
+ nhg_notify(proto, client->instance, id, ZAPI_NHG_FAIL_INSTALL);
return;
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index ac972012b2..59df45420b 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -54,13 +54,13 @@ uint32_t id_counter;
/* */
static bool g_nexthops_enabled = true;
-static struct nhg_hash_entry *depends_find(const struct nexthop *nh,
- afi_t afi);
+static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
+ int type);
static void depends_add(struct nhg_connected_tree_head *head,
struct nhg_hash_entry *depend);
static struct nhg_hash_entry *
depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
- afi_t afi);
+ afi_t afi, int type);
static struct nhg_hash_entry *
depends_find_id_add(struct nhg_connected_tree_head *head, uint32_t id);
static void depends_decrement_free(struct nhg_connected_tree_head *head);
@@ -431,7 +431,6 @@ static void *zebra_nhg_hash_alloc(void *arg)
nhe->nhg.nexthop->vrf_id, nhe->id);
}
- zebra_nhg_insert_id(nhe);
return nhe;
}
@@ -439,17 +438,17 @@ static void *zebra_nhg_hash_alloc(void *arg)
uint32_t zebra_nhg_hash_key(const void *arg)
{
const struct nhg_hash_entry *nhe = arg;
- uint32_t val, key = 0x5a351234;
-
- val = nexthop_group_hash(&(nhe->nhg));
- if (nhe->backup_info) {
- val = jhash_2words(val,
- nexthop_group_hash(
- &(nhe->backup_info->nhe->nhg)),
- key);
- }
+ uint32_t key = 0x5a351234;
+ uint32_t primary = 0;
+ uint32_t backup = 0;
+
+ primary = nexthop_group_hash(&(nhe->nhg));
+ if (nhe->backup_info)
+ backup = nexthop_group_hash(&(nhe->backup_info->nhe->nhg));
- key = jhash_3words(nhe->vrf_id, nhe->afi, val, key);
+ key = jhash_3words(primary, backup, nhe->type, key);
+
+ key = jhash_2words(nhe->vrf_id, nhe->afi, key);
return key;
}
@@ -512,6 +511,9 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2)
if (nhe1->id && nhe2->id && (nhe1->id == nhe2->id))
return true;
+ if (nhe1->type != nhe2->type)
+ return false;
+
if (nhe1->vrf_id != nhe2->vrf_id)
return false;
@@ -611,7 +613,7 @@ static int zebra_nhg_process_grp(struct nexthop_group *nhg,
}
static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
- struct nexthop *nh, afi_t afi)
+ struct nexthop *nh, afi_t afi, int type)
{
struct nhg_hash_entry *depend = NULL;
struct nexthop_group resolved_ng = {};
@@ -622,7 +624,7 @@ static void handle_recursive_depend(struct nhg_connected_tree_head *nhg_depends,
zlog_debug("%s: head %p, nh %pNHv",
__func__, nhg_depends, nh);
- depend = zebra_nhg_rib_find(0, &resolved_ng, afi);
+ depend = zebra_nhg_rib_find(0, &resolved_ng, afi, type);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: nh %pNHv => %p (%u)",
@@ -672,7 +674,25 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
*/
if (lookup->id == 0)
lookup->id = ++id_counter;
- newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
+
+ if (ZEBRA_OWNED(lookup)) {
+ /*
+ * This is a zebra hashed/owned NHG.
+ *
+ * It goes in HASH and ID table.
+ */
+ newnhe = hash_get(zrouter.nhgs, lookup, zebra_nhg_hash_alloc);
+ zebra_nhg_insert_id(newnhe);
+ } else {
+ /*
+ * This is upperproto owned NHG and should not be hashed to.
+ *
+ * It goes in ID table.
+ */
+ newnhe =
+ hash_get(zrouter.nhgs_id, lookup, zebra_nhg_hash_alloc);
+ }
+
created = true;
/* Mail back the new object */
@@ -713,7 +733,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE)) {
/* Single recursive nexthop */
handle_recursive_depend(&newnhe->nhg_depends,
- nh->resolved, afi);
+ nh->resolved, afi,
+ newnhe->type);
recursive = true;
}
} else {
@@ -726,7 +747,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
NEXTHOP_FLAG_RECURSIVE) ?
"(R)" : "");
- depends_find_add(&newnhe->nhg_depends, nh, afi);
+ depends_find_add(&newnhe->nhg_depends, nh, afi,
+ newnhe->type);
}
}
@@ -753,8 +775,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
__func__, nh);
/* Single recursive nexthop */
- handle_recursive_depend(&backup_nhe->nhg_depends,
- nh->resolved, afi);
+ handle_recursive_depend(&backup_nhe->nhg_depends, nh->resolved,
+ afi, backup_nhe->type);
recursive = true;
} else {
/* One or more backup NHs */
@@ -766,8 +788,8 @@ static bool zebra_nhe_find(struct nhg_hash_entry **nhe, /* return value */
NEXTHOP_FLAG_RECURSIVE) ?
"(R)" : "");
- depends_find_add(&backup_nhe->nhg_depends,
- nh, afi);
+ depends_find_add(&backup_nhe->nhg_depends, nh, afi,
+ backup_nhe->type);
}
}
@@ -1014,10 +1036,10 @@ static void zebra_nhg_release(struct nhg_hash_entry *nhe)
if_nhg_dependents_del(nhe->ifp, nhe);
/*
- * If its not zebra created, we didn't store it here and have to be
+ * If its not zebra owned, we didn't store it here and have to be
* sure we don't clear one thats actually being used.
*/
- if (nhe->type == ZEBRA_ROUTE_NHG)
+ if (ZEBRA_OWNED(nhe))
hash_release(zrouter.nhgs, nhe);
hash_release(zrouter.nhgs_id, nhe);
@@ -1093,8 +1115,8 @@ static int nhg_ctx_process_new(struct nhg_ctx *ctx)
return -ENOENT;
}
- if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, type,
- afi))
+ if (!zebra_nhg_find(&nhe, id, nhg, &nhg_depends, vrf_id, afi,
+ type))
depends_decrement_free(&nhg_depends);
/* These got copied over in zebra_nhg_alloc() */
@@ -1261,14 +1283,14 @@ int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id)
/* Some dependency helper functions */
static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
- afi_t afi)
+ afi_t afi, int type)
{
struct nhg_hash_entry *nhe;
struct nexthop *lookup = NULL;
lookup = nexthop_dup(nh, NULL);
- nhe = zebra_nhg_find_nexthop(0, lookup, afi, 0);
+ nhe = zebra_nhg_find_nexthop(0, lookup, afi, type);
nexthops_free(lookup);
@@ -1276,7 +1298,7 @@ static struct nhg_hash_entry *depends_find_recursive(const struct nexthop *nh,
}
static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
- afi_t afi)
+ afi_t afi, int type)
{
struct nhg_hash_entry *nhe;
struct nexthop lookup = {};
@@ -1286,7 +1308,7 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
*/
nexthop_copy_no_recurse(&lookup, nh, NULL);
- nhe = zebra_nhg_find_nexthop(0, &lookup, afi, 0);
+ nhe = zebra_nhg_find_nexthop(0, &lookup, afi, type);
/* The copy may have allocated labels; free them if necessary. */
nexthop_del_labels(&lookup);
@@ -1298,7 +1320,8 @@ static struct nhg_hash_entry *depends_find_singleton(const struct nexthop *nh,
return nhe;
}
-static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
+static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi,
+ int type)
{
struct nhg_hash_entry *nhe = NULL;
@@ -1309,9 +1332,9 @@ static struct nhg_hash_entry *depends_find(const struct nexthop *nh, afi_t afi)
* in the non-recursive case (by not alloc/freeing)
*/
if (CHECK_FLAG(nh->flags, NEXTHOP_FLAG_RECURSIVE))
- nhe = depends_find_recursive(nh, afi);
+ nhe = depends_find_recursive(nh, afi, type);
else
- nhe = depends_find_singleton(nh, afi);
+ nhe = depends_find_singleton(nh, afi, type);
if (IS_ZEBRA_DEBUG_NHG_DETAIL) {
@@ -1344,11 +1367,11 @@ static void depends_add(struct nhg_connected_tree_head *head,
static struct nhg_hash_entry *
depends_find_add(struct nhg_connected_tree_head *head, struct nexthop *nh,
- afi_t afi)
+ afi_t afi, int type)
{
struct nhg_hash_entry *depend = NULL;
- depend = depends_find(nh, afi);
+ depend = depends_find(nh, afi, type);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: nh %pNHv => %p",
@@ -1380,8 +1403,9 @@ static void depends_decrement_free(struct nhg_connected_tree_head *head)
}
/* Find an nhe based on a list of nexthops */
-struct nhg_hash_entry *
-zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
+struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id,
+ struct nexthop_group *nhg,
+ afi_t rt_afi, int type)
{
struct nhg_hash_entry *nhe = NULL;
vrf_id_t vrf_id;
@@ -1393,7 +1417,7 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi)
assert(nhg->nexthop);
vrf_id = !vrf_is_backend_netns() ? VRF_DEFAULT : nhg->nexthop->vrf_id;
- zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, 0);
+ zebra_nhg_find(&nhe, id, nhg, NULL, vrf_id, rt_afi, type);
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
zlog_debug("%s: => nhe %p (%u)",
@@ -2478,7 +2502,8 @@ void zebra_nhg_install_kernel(struct nhg_hash_entry *nhe)
&& !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED)
&& !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_QUEUED)) {
/* Change its type to us since we are installing it */
- nhe->type = ZEBRA_ROUTE_NHG;
+ if (!ZEBRA_NHG_CREATED(nhe))
+ nhe->type = ZEBRA_ROUTE_NHG;
int ret = dplane_nexthop_add(nhe);
@@ -2635,3 +2660,74 @@ bool zebra_nhg_kernel_nexthops_enabled(void)
{
return g_nexthops_enabled;
}
+
+/* Add NHE from upper level proto */
+struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
+ struct nexthop_group *nhg, afi_t afi)
+{
+ struct nhg_hash_entry lookup;
+ struct nhg_hash_entry *new;
+ struct nhg_connected *rb_node_dep = NULL;
+
+ zebra_nhe_init(&lookup, afi, nhg->nexthop);
+ lookup.nhg.nexthop = nhg->nexthop;
+ lookup.id = id;
+ lookup.type = type;
+
+ new = zebra_nhg_rib_find_nhe(&lookup, afi);
+
+ if (!new)
+ return NULL;
+
+ /* TODO: Assuming valid/onlink for now */
+ SET_FLAG(new->flags, NEXTHOP_GROUP_VALID);
+
+ if (!zebra_nhg_depends_is_empty(new)) {
+ frr_each (nhg_connected_tree, &new->nhg_depends, rb_node_dep)
+ SET_FLAG(rb_node_dep->nhe->flags, NEXTHOP_GROUP_VALID);
+ }
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: added nhe %p (%u), vrf %d, type %s", __func__,
+ new, new->id, new->vrf_id,
+ zebra_route_string(new->type));
+
+ return new;
+}
+
+/* Delete NHE from upper level proto */
+struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id)
+{
+ struct nhg_hash_entry *nhe;
+
+ nhe = zebra_nhg_lookup_id(id);
+
+ if (!nhe) {
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: id %u, lookup failed", __func__, id);
+
+ return NULL;
+ }
+
+ if (nhe->refcnt) {
+ /* TODO: should be warn? */
+ if (IS_ZEBRA_DEBUG_NHG)
+ zlog_debug("%s: id %u, still being used refcnt %u",
+ __func__, nhe->id, nhe->refcnt);
+ return NULL;
+ }
+
+ if (IS_ZEBRA_DEBUG_NHG_DETAIL)
+ zlog_debug("%s: deleted nhe %p (%u), vrf %d, type %s", __func__,
+ nhe, nhe->id, nhe->vrf_id,
+ zebra_route_string(nhe->type));
+
+ return nhe;
+}
+
+/* Replace NHE from upper level proto */
+struct nhg_hash_entry *
+zebra_nhg_proto_replace(uint32_t id, struct nexthop_group *nhg, afi_t afi)
+{
+ return NULL;
+}
diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h
index de5f097472..44d768648f 100644
--- a/zebra/zebra_nhg.h
+++ b/zebra/zebra_nhg.h
@@ -102,29 +102,25 @@ struct nhg_hash_entry {
* Is this a nexthop that is recursively resolved?
*/
#define NEXTHOP_GROUP_RECURSIVE (1 << 3)
-/*
- * This is a nexthop group we got from the kernel, it is identical to
- * one we already have. (The kernel allows duplicate nexthops, we don't
- * since we hash on them). We are only tracking it in our ID table,
- * it is unusable by our created routes but may be used by routes we get
- * from the kernel. Therefore, it is unhashable.
- */
-#define NEXTHOP_GROUP_UNHASHABLE (1 << 4)
/*
* Backup nexthop support - identify groups that are backups for
* another group.
*/
-#define NEXTHOP_GROUP_BACKUP (1 << 5)
+#define NEXTHOP_GROUP_BACKUP (1 << 4)
/*
* Track FPM installation status..
*/
-#define NEXTHOP_GROUP_FPM (1 << 6)
+#define NEXTHOP_GROUP_FPM (1 << 5)
};
/* Was this one we created, either this session or previously? */
-#define ZEBRA_NHG_CREATED(NHE) ((NHE->type) == ZEBRA_ROUTE_NHG)
+#define ZEBRA_NHG_CREATED(NHE) \
+ (((NHE->type) <= ZEBRA_ROUTE_MAX) && (NHE->type != ZEBRA_ROUTE_KERNEL))
+
+/* Is this an NHE owned by zebra and not an upper level protocol? */
+#define ZEBRA_OWNED(NHE) (NHE->type == ZEBRA_ROUTE_NHG)
/*
* Backup nexthops: this is a group object itself, so
@@ -249,13 +245,51 @@ extern int zebra_nhg_kernel_find(uint32_t id, struct nexthop *nh,
extern int zebra_nhg_kernel_del(uint32_t id, vrf_id_t vrf_id);
/* Find an nhe based on a nexthop_group */
-extern struct nhg_hash_entry *
-zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi);
+extern struct nhg_hash_entry *zebra_nhg_rib_find(uint32_t id,
+ struct nexthop_group *nhg,
+ afi_t rt_afi, int type);
/* Find an nhe based on a route's nhe, used during route creation */
struct nhg_hash_entry *
zebra_nhg_rib_find_nhe(struct nhg_hash_entry *rt_nhe, afi_t rt_afi);
+
+/**
+ * Functions for Add/Del/Replace via protocol NHG creation.
+ *
+ * The NHEs will not be hashed. They will only be present in the
+ * ID table and therefore not sharable.
+ *
+ * It is the owning protocols job to manage these.
+ */
+
+/*
+ * Add NHE.
+ *
+ * Returns allocated NHE on success, otherwise NULL.
+ */
+struct nhg_hash_entry *zebra_nhg_proto_add(uint32_t id, int type,
+ struct nexthop_group *nhg,
+ afi_t afi);
+
+
+/*
+ * Del NHE.
+ *
+ * Returns deleted NHE on success, otherwise NULL.
+ *
+ * Caller must free the NHE.
+ */
+struct nhg_hash_entry *zebra_nhg_proto_del(uint32_t id);
+
+/*
+ * Replace NHE.
+ *
+ * Returns new NHE on success, otherwise NULL.
+ */
+struct nhg_hash_entry *
+zebra_nhg_proto_replace(uint32_t id, struct nexthop_group *nhg, afi_t afi);
+
/* Reference counter functions */
extern void zebra_nhg_decrement_ref(struct nhg_hash_entry *nhe);
extern void zebra_nhg_increment_ref(struct nhg_hash_entry *nhe);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index ab96a5cf1f..baf7d2c14d 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1300,7 +1300,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe)
struct nhg_connected *rb_node_dep = NULL;
struct nexthop_group *backup_nhg;
- vty_out(vty, "ID: %u\n", nhe->id);
+ vty_out(vty, "ID: %u (%s)\n", nhe->id, zebra_route_string(nhe->type));
vty_out(vty, " RefCnt: %d\n", nhe->refcnt);
vty_out(vty, " VRF: %s\n", vrf_id_to_name(nhe->vrf_id));