mirror of
https://github.com/FRRouting/frr.git
synced 2025-04-30 13:37:17 +02:00
Merge 4e0ba30515
into 3dd4d417be
This commit is contained in:
commit
948e55bfa5
|
@ -1639,7 +1639,7 @@ zebra Terminal Mode Commands
|
|||
total number of route nodes in the table. Which will be higher than
|
||||
the actual number of routes that are held.
|
||||
|
||||
.. clicmd:: show nexthop-group rib [ID] [vrf NAME] [singleton [ip|ip6]] [type] [json]
|
||||
.. clicmd:: show nexthop-group rib [ID [routes]] [vrf NAME] [singleton [ip|ip6]] [type] [json]
|
||||
|
||||
Display nexthop groups created by zebra. The [vrf NAME] option
|
||||
is only meaningful if you have started zebra with the --vrfwnetns
|
||||
|
@ -1650,7 +1650,9 @@ zebra Terminal Mode Commands
|
|||
that has `Initial Delay`, means that this nexthop group entry
|
||||
was not installed because no-one was using it at that point and
|
||||
Zebra can delay installing this route until it is used by something
|
||||
else.
|
||||
else. [routes] option after the NHG ID will show all the routes using
|
||||
a particular NHG.
|
||||
|
||||
|
||||
.. clicmd:: show <ip|ipv6> zebra route dump [<vrf> VRFNAME]
|
||||
|
||||
|
|
40
zebra/rib.h
40
zebra/rib.h
|
@ -80,6 +80,9 @@ struct route_entry {
|
|||
/* Link list. */
|
||||
struct re_list_item next;
|
||||
|
||||
/* Back pointer to route node */
|
||||
struct route_node *rn;
|
||||
|
||||
/* Nexthop group, shared/refcounted, based on the nexthop(s)
|
||||
* provided by the owner of the route
|
||||
*/
|
||||
|
@ -161,8 +164,42 @@ struct route_entry {
|
|||
*/
|
||||
struct nexthop_group fib_ng;
|
||||
struct nexthop_group fib_backup_ng;
|
||||
|
||||
/* Selected re using an nhe are in its re RB tree */
|
||||
struct nhe_re_tree_item re_item;
|
||||
};
|
||||
|
||||
static int route_entry_cmp(const struct route_entry *re1, const struct route_entry *re2)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/* Compare VRF first - most likely to be different */
|
||||
if (re1->vrf_id != re2->vrf_id)
|
||||
return (re1->vrf_id - re2->vrf_id);
|
||||
|
||||
/* Compare protocol type - next most likely differentiator */
|
||||
if (re1->type != re2->type)
|
||||
return (re1->type - re2->type);
|
||||
|
||||
/* Compare instance */
|
||||
if (re1->instance != re2->instance)
|
||||
return (re1->instance - re2->instance);
|
||||
|
||||
/* Compare the actual prefix */
|
||||
if (re1->rn && re2->rn) {
|
||||
ret = prefix_cmp(&re1->rn->p, &re2->rn->p);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
} else if (re1->rn)
|
||||
return 1;
|
||||
else if (re2->rn)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DECLARE_RBTREE_UNIQ(nhe_re_tree, struct route_entry, re_item, route_entry_cmp);
|
||||
|
||||
#define RIB_SYSTEM_ROUTE(R) RSYSTEM_ROUTE((R)->type)
|
||||
|
||||
#define RIB_KERNEL_ROUTE(R) RKERNEL_ROUTE((R)->type)
|
||||
|
@ -639,6 +676,9 @@ extern pid_t zebra_pid;
|
|||
|
||||
extern uint32_t rt_table_main_id;
|
||||
|
||||
extern void nhe_re_tree_replace(struct nhe_re_tree_head *head, struct route_entry *re_to_oper,
|
||||
bool is_del);
|
||||
|
||||
void route_entry_dump_nh(const struct route_entry *re, const char *straddr,
|
||||
const struct vrf *re_vrf,
|
||||
const struct nexthop *nexthop);
|
||||
|
|
|
@ -398,6 +398,10 @@ struct nhg_hash_entry *zebra_nhg_alloc(void)
|
|||
struct nhg_hash_entry *nhe;
|
||||
|
||||
nhe = XCALLOC(MTYPE_NHG, sizeof(struct nhg_hash_entry));
|
||||
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
|
||||
zlog_debug("%s Creating the nhe %u (%p) re-tree", __func__, nhe->id, nhe);
|
||||
|
||||
nhe_re_tree_init(&nhe->re_head);
|
||||
|
||||
return nhe;
|
||||
}
|
||||
|
@ -1713,6 +1717,15 @@ void zebra_nhg_free(struct nhg_hash_entry *nhe)
|
|||
|
||||
EVENT_OFF(nhe->timer);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
|
||||
zlog_debug("%s Deleting the nhe %u (%p) re-tree", __func__, nhe->id, nhe);
|
||||
|
||||
struct route_entry *re = NULL;
|
||||
/* Just pop entries until tree is empty */
|
||||
while ((re = nhe_re_tree_pop(&nhe->re_head)) != NULL)
|
||||
;
|
||||
|
||||
nhe_re_tree_fini(&nhe->re_head);
|
||||
zebra_nhg_free_members(nhe);
|
||||
|
||||
XFREE(MTYPE_NHG, nhe);
|
||||
|
@ -3553,6 +3566,36 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx)
|
|||
SET_FLAG(nhe->flags, NEXTHOP_GROUP_INSTALLED);
|
||||
zebra_nhg_handle_install(nhe, true);
|
||||
|
||||
/*
|
||||
* In cases such as quick Interface flaps/kernel nexthop related
|
||||
* triggers (ip nexthop flush/ip nexthop del id <>), reinstall all
|
||||
* the routes which the nhe has at this moment.
|
||||
* The remainder new routes will anyway be successful since the NHG
|
||||
* is now installed.
|
||||
*/
|
||||
while (nhe_re_tree_count(&nhe->re_head)) {
|
||||
struct route_entry *re = nhe_re_tree_pop(&nhe->re_head);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_NHG_DETAIL)
|
||||
zlog_debug("%s Route re-install for re %p (%pRN, %s) on nhe %u (%p)",
|
||||
__func__, re, re->rn,
|
||||
zebra_route_string(re->type), id, nhe);
|
||||
/*
|
||||
* There is always a case where (say, initially BGP was best),
|
||||
* which we try to install in the kernel, and it fails because
|
||||
* NHG installation failed.
|
||||
*
|
||||
* Now when NHG installation is successful, if OSPF/Static
|
||||
* is preferred to be installed or already installed, we don't
|
||||
* want to install this BGP route entry anymore.
|
||||
* In that case, just remove the entry (just in case).
|
||||
*/
|
||||
if (CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED))
|
||||
rib_install_kernel(re->rn, re, NULL);
|
||||
else
|
||||
nhe_re_tree_replace(&re->nhe->re_head, re, true);
|
||||
}
|
||||
|
||||
/* If daemon nhg, send it an update */
|
||||
if (PROTO_OWNED(nhe))
|
||||
zsend_nhg_notify(nhe->type, nhe->zapi_instance,
|
||||
|
|
|
@ -26,6 +26,7 @@ struct nh_grp {
|
|||
};
|
||||
|
||||
PREDECL_RBTREE_UNIQ(nhg_connected_tree);
|
||||
PREDECL_RBTREE_UNIQ(nhe_re_tree);
|
||||
|
||||
/*
|
||||
* Hashtables containing nhg entries is in `zebra_router`.
|
||||
|
@ -171,6 +172,9 @@ struct nhg_hash_entry {
|
|||
* chooses this NHG then we can install it then.
|
||||
*/
|
||||
#define NEXTHOP_GROUP_INITIAL_DELAY_INSTALL (1 << 9)
|
||||
|
||||
/* Head of rb_tree of route_entries(re's)*/
|
||||
struct nhe_re_tree_head re_head;
|
||||
};
|
||||
|
||||
/* Upper 4 bits of the NHG are reserved for indicating the NHG type */
|
||||
|
|
|
@ -1980,6 +1980,30 @@ done:
|
|||
}
|
||||
|
||||
|
||||
/* Finds existing entry and deletes it. Add new entry if ADD/UPDATE */
|
||||
void nhe_re_tree_replace(struct nhe_re_tree_head *head, struct route_entry *re_to_oper, bool is_del)
|
||||
{
|
||||
struct route_entry *old_re = NULL;
|
||||
|
||||
if (head->rr.rbt_root != NULL) {
|
||||
old_re = nhe_re_tree_find(head, re_to_oper);
|
||||
if (old_re) {
|
||||
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
||||
zlog_debug("%s Found and deleting old_re %p (%pRN %s)", __func__,
|
||||
old_re, old_re->rn, zebra_route_string(old_re->type));
|
||||
|
||||
nhe_re_tree_del(head, old_re);
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_del) {
|
||||
nhe_re_tree_add(head, re_to_oper);
|
||||
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
||||
zlog_debug("%s Added new_re %p (%pRN %s)", __func__, re_to_oper,
|
||||
re_to_oper->rn, zebra_route_string(re_to_oper->type));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Route-update results processing after async dataplane update.
|
||||
|
@ -2091,6 +2115,12 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
|
|||
}
|
||||
|
||||
if (op == DPLANE_OP_ROUTE_INSTALL || op == DPLANE_OP_ROUTE_UPDATE) {
|
||||
if (old_re && old_re != re)
|
||||
nhe_re_tree_replace(&old_re->nhe->re_head, old_re, true);
|
||||
|
||||
if (re)
|
||||
nhe_re_tree_replace(&re->nhe->re_head, re, false);
|
||||
|
||||
if (status == ZEBRA_DPLANE_REQUEST_SUCCESS) {
|
||||
if (re) {
|
||||
UNSET_FLAG(re->status, ROUTE_ENTRY_FAILED);
|
||||
|
@ -2183,8 +2213,10 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx)
|
|||
}
|
||||
} else if (op == DPLANE_OP_ROUTE_DELETE) {
|
||||
rt_delete = true;
|
||||
if (re)
|
||||
if (re) {
|
||||
nhe_re_tree_replace(&re->nhe->re_head, re, true);
|
||||
SET_FLAG(re->status, ROUTE_ENTRY_FAILED);
|
||||
}
|
||||
/*
|
||||
* In the delete case, the zebra core datastructs were
|
||||
* updated (or removed) at the time the delete was issued,
|
||||
|
@ -4117,6 +4149,7 @@ static void rib_link(struct route_node *rn, struct route_entry *re, int process)
|
|||
rnode_debug(rn, re->vrf_id, "rn %p adding dest", rn);
|
||||
}
|
||||
|
||||
re->rn = rn;
|
||||
re_list_add_head(&dest->routes, re);
|
||||
|
||||
afi = (rn->p.family == AF_INET)
|
||||
|
@ -4173,6 +4206,13 @@ void rib_unlink(struct route_node *rn, struct route_entry *re)
|
|||
|
||||
dest = rib_dest_from_rnode(rn);
|
||||
|
||||
if (IS_ZEBRA_DEBUG_RIB_DETAILED)
|
||||
zlog_debug("%s Deleting re %p (%pRN, %s) from NHE %u (%p) re-tree", __func__, re,
|
||||
re->rn, zebra_route_string(re->type), re->nhe->id, re->nhe);
|
||||
|
||||
nhe_re_tree_replace(&re->nhe->re_head, re, true);
|
||||
|
||||
re->rn = NULL;
|
||||
re_list_del(&dest->routes, re);
|
||||
|
||||
if (dest->selected_fib == re)
|
||||
|
@ -4445,6 +4485,7 @@ struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type,
|
|||
re->uptime = monotime(NULL);
|
||||
re->tag = tag;
|
||||
re->nhe_id = nhe_id;
|
||||
re->rn = NULL;
|
||||
|
||||
return re;
|
||||
}
|
||||
|
|
|
@ -1435,11 +1435,12 @@ DEFPY (show_interface_nexthop_group,
|
|||
|
||||
DEFPY(show_nexthop_group,
|
||||
show_nexthop_group_cmd,
|
||||
"show nexthop-group rib <(0-4294967295)$id|[singleton <ip$v4|ipv6$v6>] [<kernel|zebra|bgp|sharp>$type_str] [vrf <NAME$vrf_name|all$vrf_all>]> [json]",
|
||||
"show nexthop-group rib <(0-4294967295)$id [routes$routes]|[singleton <ip$v4|ipv6$v6>] [<kernel|zebra|bgp|sharp>$type_str] [vrf <NAME$vrf_name|all$vrf_all>]> [json]",
|
||||
SHOW_STR
|
||||
"Show Nexthop Groups\n"
|
||||
"RIB information\n"
|
||||
"Nexthop Group ID\n"
|
||||
"Show routes using this nexthop group\n"
|
||||
"Show Singleton Nexthop-Groups\n"
|
||||
IP_STR
|
||||
IP6_STR
|
||||
|
@ -1450,19 +1451,74 @@ DEFPY(show_nexthop_group,
|
|||
VRF_FULL_CMD_HELP_STR
|
||||
JSON_STR)
|
||||
{
|
||||
|
||||
struct zebra_vrf *zvrf = NULL;
|
||||
afi_t afi = AFI_UNSPEC;
|
||||
int type = 0;
|
||||
bool uj = use_json(argc, argv);
|
||||
json_object *json = NULL;
|
||||
json_object *json_vrf = NULL;
|
||||
struct route_entry *re = NULL;
|
||||
|
||||
if (uj)
|
||||
json = json_object_new_object();
|
||||
|
||||
if (id)
|
||||
return show_nexthop_group_id_cmd_helper(vty, id, json);
|
||||
if (id) {
|
||||
struct nhg_hash_entry *nhe = zebra_nhg_lookup_id(id);
|
||||
|
||||
if (!nhe) {
|
||||
vty_out(vty, "%% Can't find nexthop group %lu\n", id);
|
||||
return CMD_WARNING;
|
||||
}
|
||||
|
||||
if (routes) {
|
||||
if (uj) {
|
||||
json_object *json_routes = json_object_new_array();
|
||||
|
||||
frr_each (nhe_re_tree, &nhe->re_head, re) {
|
||||
json_object *json_route = json_object_new_object();
|
||||
char buf[PREFIX_STRLEN];
|
||||
const char *proto_name;
|
||||
|
||||
prefix2str(&re->rn->p, buf, sizeof(buf));
|
||||
proto_name = zebra_route_string(re->type);
|
||||
|
||||
json_object_string_add(json_route, "prefix", buf);
|
||||
json_object_boolean_add(json_route, "installed",
|
||||
CHECK_FLAG(re->flags,
|
||||
ZEBRA_FLAG_SELECTED));
|
||||
json_object_string_add(json_route, "protocol", proto_name);
|
||||
json_object_array_add(json_routes, json_route);
|
||||
}
|
||||
json_object_object_add(json, "routes", json_routes);
|
||||
vty_json(vty, json);
|
||||
} else {
|
||||
vty_out(vty, "Routes using nexthop group %lu:\n", id);
|
||||
|
||||
vty_out(vty,
|
||||
"Route Entry Status Protocol\n");
|
||||
vty_out(vty,
|
||||
"------------------------------ ----------- --------\n");
|
||||
|
||||
frr_each (nhe_re_tree, &nhe->re_head, re) {
|
||||
char buf[PREFIX_STRLEN];
|
||||
const char *proto_name;
|
||||
|
||||
prefix2str(&re->rn->p, buf, sizeof(buf));
|
||||
proto_name = zebra_route_string(re->type);
|
||||
|
||||
vty_out(vty, "%-30s %-11s %s\n", buf,
|
||||
CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED)
|
||||
? "installed"
|
||||
: "not installed",
|
||||
proto_name);
|
||||
}
|
||||
}
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
show_nexthop_group_id_cmd_helper(vty, id, uj ? json : NULL);
|
||||
return CMD_SUCCESS;
|
||||
}
|
||||
|
||||
if (v4)
|
||||
afi = AFI_IP;
|
||||
|
|
Loading…
Reference in a new issue