summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--COMMUNITY.md30
-rw-r--r--bgpd/bgp_zebra.c14
-rw-r--r--lib/zclient.c2
-rw-r--r--lib/zebra.h2
-rw-r--r--nhrpd/nhrp_route.c2
-rw-r--r--ospf6d/ospf6_asbr.c267
-rw-r--r--ospf6d/ospf6_asbr.h3
-rw-r--r--ospf6d/ospf6_route.c26
-rw-r--r--ospf6d/ospf6_top.c27
-rw-r--r--ospfd/ospf_sr.c14
-rw-r--r--pimd/TODO372
-rw-r--r--sharpd/sharp_zebra.c1
-rw-r--r--tests/.gitignore4
-rw-r--r--tests/lib/test_ringbuf.py4
-rw-r--r--zebra/zebra_rib.c2
-rw-r--r--zebra/zserv.c10
16 files changed, 338 insertions, 442 deletions
diff --git a/COMMUNITY.md b/COMMUNITY.md
index 0eee524d58..081f7ab3b8 100644
--- a/COMMUNITY.md
+++ b/COMMUNITY.md
@@ -492,6 +492,36 @@ In all cases, compatibility pieces should be marked with compiler/preprocessor
annotations to print warnings at compile time, pointing to the appropriate
update path. A `-Werror` build should fail if compatibility bits are used.
+### Release Process/Schedule
+
+FRR employs a <MAJOR>.<MINOR>.<BUGFIX> versioning scheme.
+
+* MAJOR - Significant new features or multiple minor features
+ A example of a MAJOR feature is a New Routing Protocol
+* MINOR - Smaller Features
+ A example of a MINOR feature is the addition of the BGP Shutdown feature.
+* BUGFIX - Fixes for actual bugs and/or security issues.
+
+We will pull a new development branch for the next release every 4 months.
+The current schedule is Feb/June/October 1. The decision for a MAJOR/MINOR
+release is made at the time of branch pull based on what has been received
+the previous 4 months. The branch name will be dev/MAJOR.MINOR. At
+this point in time the master branch configure.ac and packaging systems
+will be updated to reflect the next possible release name to allow
+for easy distinguishing. Additionally the new dev branch will have
+these files updated too.
+
+After one month the development branch will be renamed to
+stable/MAJOR.MINOR. This process is not held up unless a crash or
+security issue has been found and needs to be addressed. Issues
+being fixed will not cause a delay.
+
+Bug fix releases are at 1 month intervals until next MAJOR.MINOR is
+pulled. Then at that time as needed for issues filed.
+
+Security issues are fixed for 1 year minimum on old releases and
+normal bug fixes for the current and previous release
+
### Miscellaneous
When in doubt, follow the guidelines in the Linux kernel style guide, or ask on
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 1da6136428..029b3d4d36 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -1026,14 +1026,14 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (peer->sort == BGP_PEER_IBGP || peer->sort == BGP_PEER_CONFED
|| info->sub_type == BGP_ROUTE_AGGREGATE) {
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
- SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+ SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
}
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|| CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
|| bgp_flag_check(bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
- SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+ SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
/* Metric is currently based on the best-path only */
metric = info->attr->med;
@@ -1054,6 +1054,9 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
else
continue;
+ api_nh = &api.nexthops[valid_nh_count];
+ api_nh->vrf_id = bgp->vrf_id;
+
if (nh_family == AF_INET) {
struct in_addr *nexthop;
@@ -1078,9 +1081,7 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
nexthop = &mpinfo_cp->attr->nexthop;
- api_nh = &api.nexthops[valid_nh_count];
api_nh->gate.ipv4 = *nexthop;
- api_nh->vrf_id = bgp->vrf_id;
/* EVPN type-2 routes are
programmed as onlink on l3-vni SVI
*/
@@ -1135,7 +1136,6 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p,
if (ifindex == 0)
continue;
- api_nh = &api.nexthops[valid_nh_count];
api_nh->gate.ipv6 = *nexthop;
api_nh->ifindex = ifindex;
api_nh->type = NEXTHOP_TYPE_IPV6_IFINDEX;
@@ -1265,14 +1265,14 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_info *info, safi_t safi)
SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE);
if (peer->sort == BGP_PEER_IBGP) {
- SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+ SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
SET_FLAG(api.flags, ZEBRA_FLAG_IBGP);
}
if ((peer->sort == BGP_PEER_EBGP && peer->ttl != 1)
|| CHECK_FLAG(peer->flags, PEER_FLAG_DISABLE_CONNECTED_CHECK)
|| bgp_flag_check(peer->bgp, BGP_FLAG_DISABLE_NH_CONNECTED_CHK))
- SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+ SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
if (bgp_debug_zebra(p)) {
char buf[PREFIX_STRLEN];
diff --git a/lib/zclient.c b/lib/zclient.c
index ad91eb504b..01d8838e1f 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -1085,7 +1085,7 @@ int zapi_route_decode(struct stream *s, struct zapi_route *api)
STREAM_GETC(s, api->message);
STREAM_GETC(s, api->safi);
if (CHECK_FLAG(api->flags, ZEBRA_FLAG_EVPN_ROUTE))
- stream_get(&(api->rmac), s, sizeof(struct ethaddr));
+ STREAM_GET(&(api->rmac), s, sizeof(struct ethaddr));
/* Prefix. */
STREAM_GETC(s, api->prefix.family);
diff --git a/lib/zebra.h b/lib/zebra.h
index b9a795d160..11bf764b63 100644
--- a/lib/zebra.h
+++ b/lib/zebra.h
@@ -402,7 +402,7 @@ extern const char *zserv_command_string(unsigned int command);
#define strmatch(a,b) (!strcmp((a), (b)))
/* Zebra message flags */
-#define ZEBRA_FLAG_INTERNAL 0x01
+#define ZEBRA_FLAG_ALLOW_RECURSION 0x01
#define ZEBRA_FLAG_SELFROUTE 0x02
#define ZEBRA_FLAG_IBGP 0x08
#define ZEBRA_FLAG_SELECTED 0x10
diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c
index d43aa4929e..8178a8b4b5 100644
--- a/nhrpd/nhrp_route.c
+++ b/nhrpd/nhrp_route.c
@@ -114,7 +114,7 @@ void nhrp_route_announce(int add, enum nhrp_cache_type type, const struct prefix
SET_FLAG(api.flags, ZEBRA_FLAG_FIB_OVERRIDE);
break;
}
- SET_FLAG(api.flags, ZEBRA_FLAG_INTERNAL);
+ SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api.nexthop_num = 1;
diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c
index 11f9e7c7b6..b52f1cef6c 100644
--- a/ospf6d/ospf6_asbr.c
+++ b/ospf6d/ospf6_asbr.c
@@ -204,26 +204,142 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
{
struct ospf6_route *old_route;
struct ospf6_path *ecmp_path, *o_path = NULL;
- struct listnode *anode;
+ struct listnode *anode, *anext;
struct listnode *nnode, *rnode, *rnext;
struct ospf6_nexthop *nh, *rnh;
char buf[PREFIX2STR_BUFFER];
bool route_found = false;
+ /* check for old entry match with new route origin,
+ * delete old entry.
+ */
for (old_route = old; old_route; old_route = old_route->next) {
- if (ospf6_route_is_same(old_route, route) &&
- (old_route->path.type == route->path.type) &&
- (old_route->path.cost == route->path.cost) &&
- (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
+ bool route_updated = false;
+
+ if (!ospf6_route_is_same(old_route, route) ||
+ (old_route->path.type != route->path.type))
+ continue;
+
+ /* Current and New route has same origin,
+ * delete old entry.
+ */
+ for (ALL_LIST_ELEMENTS(old_route->paths, anode, anext,
+ o_path)) {
+ /* Check old route path and route has same
+ * origin.
+ */
+ if (o_path->area_id != route->path.area_id ||
+ (memcmp(&(o_path)->origin, &(route)->path.origin,
+ sizeof(struct ospf6_ls_origin)) != 0))
+ continue;
+
+ /* Cost is not same then delete current path */
+ if ((o_path->cost == route->path.cost) &&
+ (o_path->u.cost_e2 == route->path.u.cost_e2))
+ continue;
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&old_route->prefix, buf,
sizeof(buf));
- zlog_debug("%s: old route %s path cost %u [%u]",
+ zlog_debug("%s: route %s cost old %u new %u is not same, replace route",
+ __PRETTY_FUNCTION__, buf,
+ o_path->cost, route->path.cost);
+ }
+
+ /* Remove selected current rout path's nh from
+ * effective nh list.
+ */
+ for (ALL_LIST_ELEMENTS_RO(o_path->nh_list, nnode, nh)) {
+ for (ALL_LIST_ELEMENTS(old_route->nh_list,
+ rnode, rnext, rnh)) {
+ if (!ospf6_nexthop_is_same(rnh, nh))
+ continue;
+ listnode_delete(old_route->nh_list,
+ rnh);
+ ospf6_nexthop_delete(rnh);
+ route_updated = true;
+ }
+ }
+
+ listnode_delete(old_route->paths, o_path);
+ ospf6_path_free(o_path);
+
+ /* Current route's path (adv_router info) is similar
+ * to route being added.
+ * Replace current route's path with paths list head.
+ * Update FIB with effective NHs.
+ */
+ if (listcount(old_route->paths)) {
+ if (old_route->path.origin.id ==
+ route->path.origin.id &&
+ old_route->path.origin.adv_router ==
+ route->path.origin.adv_router) {
+ struct ospf6_path *h_path;
+
+ h_path = (struct ospf6_path *)
+ listgetdata(listhead(old_route->paths));
+ old_route->path.origin.type =
+ h_path->origin.type;
+ old_route->path.origin.id =
+ h_path->origin.id;
+ old_route->path.origin.adv_router =
+ h_path->origin.adv_router;
+ }
+
+ if (route_updated) {
+ for (ALL_LIST_ELEMENTS(old_route->paths,
+ anode, anext, o_path)) {
+ ospf6_merge_nexthops(
+ old_route->nh_list,
+ o_path->nh_list);
+ }
+ /* Update RIB/FIB with effective
+ * nh_list
+ */
+ if (ospf6->route_table->hook_add)
+ (*ospf6->route_table->hook_add)
+ (old_route);
+ break;
+ }
+ } else {
+ if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+ prefix2str(&old_route->prefix, buf,
+ sizeof(buf));
+ zlog_debug("%s: route %s old cost %u new cost %u, delete old entry.",
+ __PRETTY_FUNCTION__, buf,
+ old_route->path.cost,
+ route->path.cost);
+ }
+ ospf6_route_remove(old_route,
+ ospf6->route_table);
+ break;
+ }
+ }
+ if (route_updated)
+ break;
+ }
+
+ /* Add new route */
+ for (old_route = old; old_route; old_route = old_route->next) {
+
+ /* Current and New Route prefix or route type
+ * is not same skip this current node.
+ */
+ if (!ospf6_route_is_same(old_route, route) ||
+ (old_route->path.type != route->path.type))
+ continue;
+
+ /* Old Route and New Route have Equal Cost, Merge NHs */
+ if ((old_route->path.cost == route->path.cost) &&
+ (old_route->path.u.cost_e2 == route->path.u.cost_e2)) {
+
+ if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+ prefix2str(&old_route->prefix, buf,
+ sizeof(buf));
+ zlog_debug("%s: old route %s path cost %u e2 %u",
__PRETTY_FUNCTION__, buf,
old_route->path.cost,
- ospf6_route_is_same(old_route,
- route));
+ old_route->path.u.cost_e2);
}
route_found = true;
/* check if this path exists already in
@@ -232,9 +348,10 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
*/
for (ALL_LIST_ELEMENTS_RO(old_route->paths, anode,
o_path)) {
- if ((o_path->origin.id == route->path.origin.id)
- && (o_path->origin.adv_router ==
- route->path.origin.adv_router))
+ if (o_path->area_id == route->path.area_id &&
+ (memcmp(&(o_path)->origin,
+ &(route)->path.origin,
+ sizeof(struct ospf6_ls_origin)) == 0))
break;
}
/* If path is not found in old_route paths's list,
@@ -262,12 +379,13 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&route->prefix, buf,
sizeof(buf));
- zlog_debug("%s: route %s another path added with nh %u, Paths %u",
+ zlog_debug("%s: route %s another path added with nh %u, effective paths %u nh %u",
__PRETTY_FUNCTION__, buf,
listcount(ecmp_path->nh_list),
old_route->paths ?
listcount(old_route->paths)
- : 0);
+ : 0,
+ listcount(old_route->nh_list));
}
} else {
for (ALL_LIST_ELEMENTS_RO(o_path->nh_list,
@@ -313,6 +431,7 @@ void ospf6_asbr_update_route_ecmp_path(struct ospf6_route *old,
* route.
*/
ospf6_route_delete(route);
+
break;
}
}
@@ -426,11 +545,12 @@ void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa)
}
-void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
+void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
+ struct ospf6_route *asbr_entry)
{
struct ospf6_as_external_lsa *external;
struct prefix prefix;
- struct ospf6_route *route, *nroute;
+ struct ospf6_route *route, *nroute, *route_to_del;
char buf[PREFIX2STR_BUFFER];
external = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END(
@@ -445,6 +565,35 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
return;
}
+ route_to_del = ospf6_route_create();
+ route_to_del->type = OSPF6_DEST_TYPE_NETWORK;
+ route_to_del->prefix.family = AF_INET6;
+ route_to_del->prefix.prefixlen = external->prefix.prefix_length;
+ ospf6_prefix_in6_addr(&route_to_del->prefix.u.prefix6,
+ &external->prefix);
+
+ route_to_del->path.origin.type = lsa->header->type;
+ route_to_del->path.origin.id = lsa->header->id;
+ route_to_del->path.origin.adv_router = lsa->header->adv_router;
+
+ if (asbr_entry) {
+ route_to_del->path.area_id = asbr_entry->path.area_id;
+ if (CHECK_FLAG(external->bits_metric, OSPF6_ASBR_BIT_E)) {
+ route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL2;
+ route_to_del->path.metric_type = 2;
+ route_to_del->path.cost = asbr_entry->path.cost;
+ route_to_del->path.u.cost_e2 =
+ OSPF6_ASBR_METRIC(external);
+ } else {
+ route_to_del->path.type = OSPF6_PATH_TYPE_EXTERNAL1;
+ route_to_del->path.metric_type = 1;
+ route_to_del->path.cost =
+ asbr_entry->path.cost +
+ OSPF6_ASBR_METRIC(external);
+ route_to_del->path.u.cost_e2 = 0;
+ }
+ }
+
memset(&prefix, 0, sizeof(struct prefix));
prefix.family = AF_INET6;
prefix.prefixlen = external->prefix.prefix_length;
@@ -459,14 +608,25 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
return;
}
- for (ospf6_route_lock(route);
- route && ospf6_route_is_prefix(&prefix, route); route = nroute) {
+ if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+ prefix2str(&prefix, buf, sizeof(buf));
+ zlog_debug("%s: Current route %s cost %u e2 %u, route to del cost %u e2 %u",
+ __PRETTY_FUNCTION__, buf, route->path.cost,
+ route->path.u.cost_e2,
+ route_to_del->path.cost,
+ route_to_del->path.u.cost_e2);
+ }
+
+ for (ospf6_route_lock(route); route &&
+ ospf6_route_is_prefix(&prefix, route); route = nroute) {
nroute = ospf6_route_next(route);
+
if (route->type != OSPF6_DEST_TYPE_NETWORK)
continue;
- /* Route has multiple ECMP paths remove,
- * matching path and update effective route's nh list.
+ /* Route has multiple ECMP paths, remove matching
+ * path. Update current route's effective nh list
+ * after removal of one of the path.
*/
if (listcount(route->paths) > 1) {
struct listnode *anode, *anext;
@@ -481,18 +641,36 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
*/
for (ALL_LIST_ELEMENTS(route->paths, anode, anext,
o_path)) {
- if (o_path->origin.type != lsa->header->type)
- continue;
- if (o_path->origin.id != lsa->header->id)
+ if ((o_path->origin.type != lsa->header->type)
+ || (o_path->origin.adv_router !=
+ lsa->header->adv_router) ||
+ (o_path->origin.id != lsa->header->id))
continue;
- if (o_path->origin.adv_router !=
- lsa->header->adv_router)
+
+ /* Compare LSA cost with current
+ * route info.
+ */
+ if (!asbr_entry && (o_path->cost !=
+ route_to_del->path.cost ||
+ o_path->u.cost_e2 !=
+ route_to_del->path.u.cost_e2)) {
+ if (IS_OSPF6_DEBUG_EXAMIN(
+ AS_EXTERNAL)) {
+ prefix2str(&prefix, buf,
+ sizeof(buf));
+ zlog_debug(
+ "%s: route %s to delete is not same, cost %u del cost %u. skip",
+ __PRETTY_FUNCTION__, buf,
+ route->path.cost,
+ route_to_del->path.cost);
+ }
continue;
+ }
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
prefix2str(&prefix, buf, sizeof(buf));
zlog_debug(
- "%s: route %s path found with nh %u",
+ "%s: route %s path found with nh %u to remove.",
__PRETTY_FUNCTION__, buf,
listcount(o_path->nh_list));
}
@@ -542,13 +720,13 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
listcount(route->nh_list));
}
- /* Update RIB/FIB w/ effective nh_list */
+ /* Update RIB/FIB with effective nh_list */
if (ospf6->route_table->hook_add)
(*ospf6->route_table->hook_add)(route);
- /* route's path is similar to lsa header,
- * replace route's path with route's
- * paths list head.
+ /* route's primary path is similar to LSA,
+ * replace route's primary path with
+ * route's paths list head.
*/
if (route->path.origin.id == lsa->header->id &&
route->path.origin.adv_router ==
@@ -568,12 +746,29 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
continue;
} else {
- if (route->path.origin.type != lsa->header->type)
- continue;
- if (route->path.origin.id != lsa->header->id)
+ /* Compare LSA origin and cost with current route info.
+ * if any check fails skip del this route node.
+ */
+ if (asbr_entry && (!ospf6_route_is_same_origin(route,
+ route_to_del) ||
+ (route->path.type != route_to_del->path.type) ||
+ (route->path.cost != route_to_del->path.cost) ||
+ (route->path.u.cost_e2 !=
+ route_to_del->path.u.cost_e2))) {
+ if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
+ prefix2str(&prefix, buf, sizeof(buf));
+ zlog_debug("%s: route %s to delete is not same, cost %u del cost %u. skip",
+ __PRETTY_FUNCTION__, buf,
+ route->path.cost,
+ route_to_del->path.cost);
+ }
continue;
- if (route->path.origin.adv_router !=
- lsa->header->adv_router)
+ }
+
+ if ((route->path.origin.type != lsa->header->type) ||
+ (route->path.origin.adv_router !=
+ lsa->header->adv_router) ||
+ (route->path.origin.id != lsa->header->id))
continue;
}
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
@@ -589,6 +784,8 @@ void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa)
}
if (route != NULL)
ospf6_route_unlock(route);
+
+ ospf6_route_delete(route_to_del);
}
void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry)
@@ -622,7 +819,7 @@ void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry)
type = htons(OSPF6_LSTYPE_AS_EXTERNAL);
router = ospf6_linkstate_prefix_adv_router(&asbr_entry->prefix);
for (ALL_LSDB_TYPED_ADVRTR(ospf6->lsdb, type, router, lsa))
- ospf6_asbr_lsa_remove(lsa);
+ ospf6_asbr_lsa_remove(lsa, asbr_entry);
}
diff --git a/ospf6d/ospf6_asbr.h b/ospf6d/ospf6_asbr.h
index cc4f0272aa..bd160a6456 100644
--- a/ospf6d/ospf6_asbr.h
+++ b/ospf6d/ospf6_asbr.h
@@ -71,7 +71,8 @@ struct ospf6_as_external_lsa {
}
extern void ospf6_asbr_lsa_add(struct ospf6_lsa *lsa);
-extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa);
+extern void ospf6_asbr_lsa_remove(struct ospf6_lsa *lsa,
+ struct ospf6_route *asbr_entry);
extern void ospf6_asbr_lsentry_add(struct ospf6_route *asbr_entry);
extern void ospf6_asbr_lsentry_remove(struct ospf6_route *asbr_entry);
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index 19eb9a3fe6..ef0a093d13 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -469,6 +469,8 @@ int ospf6_route_cmp(struct ospf6_route *ra, struct ospf6_route *rb)
if (ra->path.type == OSPF6_PATH_TYPE_EXTERNAL2) {
if (ra->path.u.cost_e2 != rb->path.u.cost_e2)
return (ra->path.u.cost_e2 - rb->path.u.cost_e2);
+ else
+ return (ra->path.cost - rb->path.cost);
} else {
if (ra->path.cost != rb->path.cost)
return (ra->path.cost - rb->path.cost);
@@ -627,10 +629,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
if (ospf6_route_is_identical(old, route)) {
if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
zlog_debug(
- "%s %p: route add %p: needless update of %p",
+ "%s %p: route add %p: needless update of %p old cost %u",
ospf6_route_table_name(table),
(void *)table, (void *)route,
- (void *)old);
+ (void *)old, old->path.cost);
else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
zlog_debug("%s: route add: needless update",
ospf6_route_table_name(table));
@@ -645,9 +647,10 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
}
if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
- zlog_debug("%s %p: route add %p: update of %p",
+ zlog_debug("%s %p: route add %p cost %u: update of %p old cost %u",
ospf6_route_table_name(table), (void *)table,
- (void *)route, (void *)old);
+ (void *)route, route->path.cost, (void *)old,
+ old->path.cost);
else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
zlog_debug("%s: route add: update",
ospf6_route_table_name(table));
@@ -686,13 +689,14 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route,
if (prev || next) {
if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
zlog_debug(
- "%s %p: route add %p: another path: prev %p, next %p node refcount %u",
+ "%s %p: route add %p cost %u: another path: prev %p, next %p node ref %u",
ospf6_route_table_name(table), (void *)table,
- (void *)route, (void *)prev, (void *)next,
- node->lock);
+ (void *)route, route->path.cost, (void *)prev,
+ (void *)next, node->lock);
else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
- zlog_debug("%s: route add: another path found",
- ospf6_route_table_name(table));
+ zlog_debug("%s: route add cost %u: another path found",
+ ospf6_route_table_name(table),
+ route->path.cost);
if (prev == NULL)
prev = next->prev;
@@ -814,9 +818,9 @@ void ospf6_route_remove(struct ospf6_route *route,
prefix2str(&route->prefix, buf, sizeof(buf));
if (IS_OSPF6_DEBUG_ROUTE(MEMORY))
- zlog_debug("%s %p: route remove %p: %s refcount %u",
+ zlog_debug("%s %p: route remove %p: %s cost %u refcount %u",
ospf6_route_table_name(table), (void *)table,
- (void *)route, buf, route->lock);
+ (void *)route, buf, route->path.cost, route->lock);
else if (IS_OSPF6_DEBUG_ROUTE(TABLE))
zlog_debug("%s: route remove: %s",
ospf6_route_table_name(table), buf);
diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c
index 25d968fb68..afe2d7397b 100644
--- a/ospf6d/ospf6_top.c
+++ b/ospf6d/ospf6_top.c
@@ -72,7 +72,7 @@ static void ospf6_top_lsdb_hook_remove(struct ospf6_lsa *lsa)
{
switch (ntohs(lsa->header->type)) {
case OSPF6_LSTYPE_AS_EXTERNAL:
- ospf6_asbr_lsa_remove(lsa);
+ ospf6_asbr_lsa_remove(lsa, NULL);
break;
default:
@@ -96,11 +96,16 @@ static void ospf6_top_route_hook_remove(struct ospf6_route *route)
static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
{
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
- char buf[PREFIX2STR_BUFFER];
-
- prefix2str(&route->prefix, buf, sizeof(buf));
- zlog_debug("%s: brouter %s add with nh count %u",
- __PRETTY_FUNCTION__, buf, listcount(route->nh_list));
+ uint32_t brouter_id;
+ char brouter_name[16];
+
+ brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix);
+ inet_ntop(AF_INET, &brouter_id, brouter_name,
+ sizeof(brouter_name));
+ zlog_debug("%s: brouter %s add with adv router %x nh count %u",
+ __PRETTY_FUNCTION__, brouter_name,
+ route->path.origin.adv_router,
+ listcount(route->nh_list));
}
ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
ospf6_asbr_lsentry_add(route);
@@ -110,11 +115,15 @@ static void ospf6_top_brouter_hook_add(struct ospf6_route *route)
static void ospf6_top_brouter_hook_remove(struct ospf6_route *route)
{
if (IS_OSPF6_DEBUG_EXAMIN(AS_EXTERNAL)) {
- char buf[PREFIX2STR_BUFFER];
+ uint32_t brouter_id;
+ char brouter_name[16];
- prefix2str(&route->prefix, buf, sizeof(buf));
+ brouter_id = ADV_ROUTER_IN_PREFIX(&route->prefix);
+ inet_ntop(AF_INET, &brouter_id, brouter_name,
+ sizeof(brouter_name));
zlog_debug("%s: brouter %s del with nh count %u",
- __PRETTY_FUNCTION__, buf, listcount(route->nh_list));
+ __PRETTY_FUNCTION__, brouter_name,
+ listcount(route->nh_list));
}
route->flag |= OSPF6_ROUTE_REMOVE;
ospf6_abr_examin_brouter(ADV_ROUTER_IN_PREFIX(&route->prefix));
diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c
index 2944c8b09a..fef77f574e 100644
--- a/ospfd/ospf_sr.c
+++ b/ospfd/ospf_sr.c
@@ -307,7 +307,8 @@ int ospf_sr_init(void)
{
int rc = -1;
- zlog_info("SR (%s): Initialize SR Data Base", __func__);
+ if (IS_DEBUG_OSPF_SR)
+ zlog_info("SR (%s): Initialize SR Data Base", __func__);
memset(&OspfSR, 0, sizeof(struct ospf_sr_db));
OspfSR.enabled = false;
@@ -676,6 +677,7 @@ static int ospf_zebra_send_mpls_ftn(int cmd, struct sr_nhlfe nhlfe)
SET_FLAG(api.message, ZAPI_MESSAGE_LABEL);
api_nh->labels[0] = nhlfe.label_out;
api_nh->label_num = 1;
+ api_nh->vrf_id = VRF_DEFAULT;
api.nexthop_num = 1;
}
@@ -1617,11 +1619,11 @@ static int ospf_sr_update_schedule(struct thread *t)
monotime(&stop_time);
- zlog_info(
- "SR (%s): SPF Processing Time(usecs): %lld\n",
- __func__,
- (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
- + (stop_time.tv_usec - start_time.tv_usec));
+ if (IS_DEBUG_OSPF_SR)
+ zlog_debug("SR (%s): SPF Processing Time(usecs): %lld\n",
+ __func__,
+ (stop_time.tv_sec - start_time.tv_sec) * 1000000LL
+ + (stop_time.tv_usec - start_time.tv_usec));
OspfSR.update = false;
return 1;
diff --git a/pimd/TODO b/pimd/TODO
index 57d2a17b5f..4a147751dd 100644
--- a/pimd/TODO
+++ b/pimd/TODO
@@ -1,375 +1,21 @@
-T1 DONE Implement debug command
- test pim receive join
-
-T2 DONE Implement debug command
- test pim receive prune
-
-T3 DONE Per-interface Downstream (S,G) state machine
- (RFC 4601 4.5.3. Receiving (S,G) Join/Prune Messages)
-
-T4 DONE Upstream (S,G) state machine
- (RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages)
-
-T5 DONE Verify Data Packet Forwarding Rules
- RFC 4601 4.2. Data Packet Forwarding Rules
- RFC 4601 4.8.2. PIM-SSM-Only Routers
-
- Additionally, the Packet forwarding rules of Section 4.2 can be
- simplified in a PIM-SSM-only router:
-
- iif is the incoming interface of the packet.
- oiflist = NULL
- if (iif == RPF_interface(S) AND UpstreamJPState(S,G) == Joined) {
- oiflist = inherited_olist(S,G)
- } else if (iif is in inherited_olist(S,G)) {
- send Assert(S,G) on iif
- }
- oiflist = oiflist (-) iif
- forward packet on all interfaces in oiflist
-
- Macro:
- inherited_olist(S,G) =
- joins(S,G) (+) pim_include(S,G) (-) lost_assert(S,G)
-
-T6 DONE Implement (S,G) Assert state machine (RFC 4601, section 4.6.1).
- Changes in pim_ifchannel.ifassert_winner should trigger
- pim_upstream_update_join_desired().
- Depends on TODO T27.
- Depends on TODO T33.
- See also CAVEAT C7.
- See also: RFC 4601 4.5.7. Sending (S,G) Join/Prune Messages
- Transitions from Joined State
- RPF'(S,G) changes due to an Assert
-
- http://www.hep.ucl.ac.uk/~ytl/multi-cast/pim-dm_01.html:
-
- The PIM Assert mechanism is used to shutoff duplicate flows onto
- the same multiaccess network. Routers detect this condiction when
- they receive an (S,G) packet via a multi-access interface that is
- in the (S,G) OIL. This causes the routers to send Assert
- Messages.
-
- Note that neighbors will not accept Join/Prune or Assert messages
- from a router unless they have first heard a Hello message from that
- router. Thus, if a router needs to send a Join/Prune or Assert
- message on an interface on which it has not yet sent a Hello message
- with the currently configured IP address, then it MUST immediately
- send the relevant Hello message without waiting for the Hello Timer
- to expire, followed by the Join/Prune or Assert message.
-
-T7 DONE Implement hello option: LAN Prune Delay
-
-T8 DONE Implement J/P_Override_Interval(I)
- Depends on TODO T7.
- See pim_ifchannel.c, pim_ifchannel_prune(), jp_override_interval.
-
-T9 DONE Detect change in IGMPv3 RPF interface/next-hop for S and update.
- channel_oil vif index accordingly ?
- Beware accidentaly adding looped MFC entries (IIF=OIF).
-
-T10 DONE React to (S,G) join directed to another upstream address. See
- also:
-
- RFC 4601: 4.5.7. Sending (S,G) Join/Prune Messages
-
- If a router wishes to propagate a Join(S,G) upstream, it must also
- watch for messages on its upstream interface from other routers on
- that subnet, and these may modify its behavior. If it sees a
- Join(S,G) to the correct upstream neighbor, it should suppress its
- own Join(S,G). If it sees a Prune(S,G), Prune(S,G,rpt), or
- Prune(*,G) to the correct upstream neighbor towards S, it should
- be prepared to override that prune by scheduling a Join(S,G) to be
- sent almost immediately.
-
-T11 DONE Review protocol modifications for SSM
- (RFC 4601 4.8.1. Protocol Modifications for SSM Destination
- Addresses)
-
-T12 DONE Review updates of RPF entries.
- FIXME pim_upstream.c send_join():
- Currently only one upstream state is affected by detection of RPF change.
- RPF change should affect all upstream states sharing the RPF cache.
-
-T13 DONE Check that RFC macros using S,G,RPF_interface(S) are actually
- implemented with this strategy:
- rpf_ifch=find_ifch(up->rpf->interface).
- See pim_rpf.c pim_rpf_find_rpf_addr() for a correct example.
-
- $ grep -i macro pimd/*.c
- pimd/pim_iface.c: RFC 4601: 4.1.6. State Summarization Macros
- pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros
- pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros
- pimd/pim_ifchannel.c: RFC 4601: 4.1.6. State Summarization Macros
- pimd/pim_ifchannel.c: RFC 4601: 4.6.5. Assert State Macros
- pimd/pim_ifchannel.c: Macro:
- pimd/pim_rpf.c: RFC 4601: 4.1.6. State Summarization Macros
-
-T14 DONE Send Assert(S,G) on iif as response to WRONGVIF kernel upcall.
- See pim_mroute.c mroute_msg().
-
-T15 DONE Interface command to statically join (S,G).
- interface eth0
- ip igmp join-group 239.1.1.1 source 1.1.1.1
-
-T16 DONE RPF'(S,G) lookup is not working for S reachable with default route.
- See "RPF'(S,G) not found" in pim_rpf_update() from pim_rpf.c.
- Zebra daemon RIB is not reflecting changes in kernel routes
- accurately?
-
-T17 DONE Prevent CLI from creating bogus interfaces.
- Example:
- conf t
- interface xxx
-
-T18 Consider reliable pim solution (refresh reduction)
+T1 Consider reliable pim solution (refresh reduction)
A Reliable Transport Mechanism for PIM
http://tools.ietf.org/wg/pim/draft-ietf-pim-port/
PORT=PIM-Over-Reliable-Transport
-T19 DONE Fix self as neighbor
- See mailing list post:
- http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html
-
-T20 DONE Fix debug message: "pim_neighbor_update: internal error:
- trying to replace same prefix list"
- See mailing list post:
- http://lists.gnu.org/archive/html/qpimd-users/2009-04/msg00000.html
-
-T21 DONE Clean-up PIM/IGMP interface mismatch debugging
- See option PIM_CHECK_RECV_IFINDEX_SANITY in pimd/Makefile.am
- See mailing list post:
- http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00003.html
-
-T22 DONE IGMP must be protected against adding looped MFC entries
- created by both source and receiver attached to the same
- interface.
-
-T23 DONE libfrr crash after zclient_lookup_nexthop.
- See mailing list post:
- http://lists.nongnu.org/archive/html/qpimd-users/2009-04/msg00008.html
-
-T24 DONE zserv may return recursive routes:
- - nexthop type is set to ZEBRA_NEXTHOP_IPV4
- - ifindex is not reported
- - calls expecting ifindex (fib_lookup_if_vif_index) are disrupted
- See also this mailing list post:
- [PATCH 21/21] Link detect and recursive routes
- http://www.gossamer-threads.com/lists/quagga/dev/17564
-
-T25 DONE Zclient nexthop lookup missing OSPF route to 1.1.1.1/32
- See also:
- pim_zlookup.c zclient_lookup_nexthop misses OSPF 1.1.1.1/32
- zebra/zebra_vty.c show_ip_route_addr_cmd hits OSPF 1.1.1.1/32
-
-T26 DONE Zebra daemon is marking recursive static route as inactive.
-
- FIXED: zebra daemon was incorrectly marking recursive routes
- pointing to kernel routes as inactive:
- zebra/zebra_rib.c nexthop_active_ipv4:
- -- Original:
- else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL))
- -- Fixed:
- else if (CHECK_FLAG (rib->flags, ZEBRA_FLAG_INTERNAL) ||
- match->type == ZEBRA_ROUTE_KERNEL)
-
- Old problem description:
-
- This prevents rib_match_ipv4 from returning its nexthop:
- client: pim_zlookup.c zclient_read_nexthop
- server: zebra/zserv.c zsend_ipv4_nexthop_lookup_v2 -> rib_match_ipv4
-
- Kernel route is injected into zebra in zebra_rib.c rib_add_ipv4
- Examples:
- rt_netlink.c:726: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, flags, &p, gate, src, index, table, metric, 0);
- rt_netlink.c:864: rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, 0, &p, gate, src, index, table, 0, 0);
-
- This patch didn't fix the issue:
- [PATCH 21/21] Link detect and recursive routes
- http://www.gossamer-threads.com/lists/quagga/dev/17564
-
- See the example below for the route 2.2.2.2.
-
-bash# route add -host 1.1.1.1 gw 127.0.0.1
-bash# route add -host 2.2.2.2 gw 1.1.1.1
-bash# netstat -nvr
-Kernel IP routing table
-Destination Gateway Genmask Flags MSS Window irtt Iface
-2.2.2.2 1.1.1.1 255.255.255.255 UGH 0 0 0 lo
-1.1.1.1 127.0.0.1 255.255.255.255 UGH 0 0 0 lo
-192.168.0.0 0.0.0.0 255.255.255.0 U 0 0 0 eth0
-0.0.0.0 192.168.0.2 0.0.0.0 UG 0 0 0 eth0
-bash#
-
-zebra# sh ip route
-Codes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,
- I - ISIS, B - BGP, > - selected route, * - FIB route
-
-K>* 0.0.0.0/0 via 192.168.0.2, eth0
-K>* 1.1.1.1/32 via 127.0.0.1, lo
-K * 2.2.2.2/32 via 1.1.1.1, lo inactive
-C>* 127.0.0.0/8 is directly connected, lo
-C>* 192.168.0.0/24 is directly connected, eth0
-
-quagga-pimd-router# sh ip route 1.1.1.1
-Address NextHop Interface Metric Preference
-1.1.1.1 127.0.0.1 lo 0 0
-quagga-pimd-router#
-quagga-pimd-router# sh ip route 2.2.2.2
-Address NextHop Interface Metric Preference
-2.2.2.2 192.168.0.2 eth0 0 0
-quagga-pimd-router#
-
-T27 DONE Implement debug command
- test pim receive assert
- See also TODO T6: (S,G) Assert state machine.
-
-T28 DONE Bad IPv4 address family=02 in Join/Prune dump
- Reported by Andrew Lunn <andrew.lunn@ascom.ch>
-
- # 58-byte pim v2 Join/Prune dump
- # ------------------------------
- # IPv4 address family=02 is wrong, correct IPv4 address family is 01
- # See http://www.iana.org/assignments/address-family-numbers
- #
- c8XX YY03 : ip src 200.xx.yy.3
- e000 000d : ip dst 224.0.0.13
- 9404 0000 : ip router alert option 148.4.0.0
- 2300 ab13 : pimv2,type=3 res=00 checksum=ab13
- 0200 : upstream family=02, encoding=00
- c8XX YY08 : upstream 200.xx.yy.8
- 0001 00d2 : res=00 groups=01 holdtime=00d2
- 0200 0020 : group family=02, encoding=00, res=00, mask_len=20
- ef01 0101 : group address 239.1.1.1
- 0001 0000 : joined=0001 pruned=0000
- 0200 0020 : source family=02, encoding=00, res=00, mask_len=20
- 0101 0101 : source address 1.1.1.1
-
-T29 DONE Reset interface PIM-hello-sent counter when primary address changes
- See pim_ifp->pim_ifstat_hello_sent
-
- RFC 4601: 4.3.1. Sending Hello Messages
-
- Thus, if a router needs to send a Join/Prune or Assert message on
- an interface on which it has not yet sent a Hello message with the
- currently configured IP address, then it MUST immediately send the
- relevant Hello message without waiting for the Hello Timer to
- expire, followed by the Join/Prune or Assert message.
-
-T30 DONE Run interface DR election when primary address changes
- Reported by Andrew Lunn <andrew.lunn@ascom.ch>
- See pim_if_dr_election().
-
-T31 If an interface changes one of its secondary IP addresses, a Hello
+T2 If an interface changes one of its secondary IP addresses, a Hello
message with an updated Address_List option and a non-zero
HoldTime should be sent immediately.
See also detect_secondary_address_change
See also CAVEAT C15.
See also RFC 4601: 4.3.1. Sending Hello Messages
-T32 FIXED Detection of interface primary address changes may fail when
- there are multiple addresses.
- See also CAVEAT C14.
-
- pim_find_primary_addr() should return interface primary address
- from connected list. Currently it returns the first address.
-
- Zebra daemon "show int" is able to keep the primary address as
- first address.
-
-T33 DONE Implement debug command: test pim receive upcall
- See also TODO T6: (S,G) Assert state machine.
-
-T34 DONE assert_action_a1
-
-T35 DONE Review macros depending on interface I.
-
- See also: grep ,I\) pimd/*.c
-
- For the case (S,G,I) check if I is either
- 1) interface attached to this per-interface S,G state (don't think so)
- or
- 2) an arbitrary interface (most probably)
-
- For the arbitrary interface case (2), consider representing
- interface ifp as its primary address (struct in_addr ifaddr). The
- benefit is in_addr does not need to be dereferenced, so it does
- not demand protection against crashes.
-
-T36 DONE React to zebra daemon link-detect up/down notification.
- pim_ifp->primary_address is managed by detect_primary_address_change()
- depending on to ifp->connected (managed by zebra_interface_address_read()).
-
-T37 DONE Review list of variables which may affect pim_upstream.c
- pim_upstream_evaluate_join_desired().
- Call pim_upstream_update_join_desired() accordingly.
-
- See the order of invokation:
- pim_if_dr_election(ifp);
- pim_if_update_join_desired(pim_ifp); /* depends on DR */
- pim_if_update_could_assert(ifp); /* depends on DR */
- pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
-
- join_desired depends on:
- pim_ifp->primary_address
- pim_ifp->pim_dr_addr
- ch->ifassert_winner_metric
- ch->ifassert_winner
- ch->local_ifmembership
- ch->ifjoin_state
- ch->upstream->rpf.source_nexthop.mrib_metric_preference
- ch->upstream->rpf.source_nexthop.mrib_route_metric
- ch->upstream->rpf.source_nexthop.interface
-
-T38 DONE Detect change in AssertTrackingDesired(S,G,I)
-
- See the order of invokation:
- dr_election: none
- update_join_desired: depends on DR
- update_tracking_desired: depends on DR, join_desired
-
- AssertTrackingDesired(S,G,I) depends on:
- pim_ifp->primary_address
- pim_ifp->pim_dr_addr
- ch->local_ifmembership
- ch->ifassert_winner
- ch->ifjoin_state
- ch->upstream->rpf.source_nexthop.interface
- PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED(ch->upstream->flags)
-
-T39 DONE AssertTrackingDesired: flags is not matching evaluation
-
- # show ip pim assert-internal
- CA: CouldAssert
- ECA: Evaluate CouldAssert
- ATD: AssertTrackingDesired
- eATD: Evaluate AssertTrackingDesired
-
- Interface Address Source Group CA eCA ATD eATD
- eth0 192.168.1.100 1.1.1.1 239.1.1.1 no no no yes
- #
-
-T40 Lightweight MLDv2
+T3 Lightweight MLDv2
http://tools.ietf.org/html/draft-ietf-mboned-lightweight-igmpv3-mldv2-05
http://www.ietf.org/internet-drafts/draft-ietf-mboned-lightweight-igmpv3-mldv2-05.txt
http://www.ietf.org/html.charters/mboned-charter.html
-T41 DONE ssmping support
-
- See also:
- http://www.venaas.no/multicast/ssmping/
- draft-ietf-mboned-ssmping-07
- http://tools.ietf.org/html/draft-ietf-mboned-ssmping-07
-
- Example:
-
- debug ssmpingd
-
- conf t
- ip ssmpingd 1.1.1.1
-
- show ip ssmpingd
-
-T42 Static igmp join fails when loading config at boot time
+T4 Static igmp join fails when loading config at boot time
! Wrong behavior seen at boot time:
!
@@ -396,7 +42,7 @@ T42 Static igmp join fails when loading config at boot time
eth0 200.202.112.3 2 2 0 0 0 0
lo 127.0.0.1 1 1 0 0 0 0
-T43 PIM Neighbor Reduction
+T5 PIM Neighbor Reduction
https://datatracker.ietf.org/doc/draft-wijnands-pim-neighbor-reduction/
"In a transit LAN (no directly connected source or receiver), many
@@ -404,19 +50,19 @@ T43 PIM Neighbor Reduction
a procedure to reduce the amount of neighbors established over a
transit LAN."
-T44 Single Stream Multicast Fast Reroute (SMFR) Method
+T6 Single Stream Multicast Fast Reroute (SMFR) Method
https://datatracker.ietf.org/doc/draft-liu-pim-single-stream-multicast-frr/
"This document proposes an IP multicast fast convergence method
based on differentiating primary and backup PIM join."
-T45 RFC5384 - The Join Attribute Format
+T7 RFC5384 - The Join Attribute Format
"This document describes a modification of the Join message that
allows a node to associate attributes with a particular tree."
-T46 PIM Multi-Topology ID (MT-ID) Join-Attribute
+T8 PIM Multi-Topology ID (MT-ID) Join-Attribute
http://tools.ietf.org/html/draft-cai-pim-mtid-00
- Depends on T45.
+ Depends on T7.
"This draft introduces a new type of PIM Join Attribute used to
encode the identity of the topology PIM uses for RPF."
diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c
index 3b22db20aa..f02ce4979c 100644
--- a/sharpd/sharp_zebra.c
+++ b/sharpd/sharp_zebra.c
@@ -169,6 +169,7 @@ void route_add(struct prefix *p, struct nexthop *nh)
api.safi = SAFI_UNICAST;
memcpy(&api.prefix, p, sizeof(*p));
+ SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION);
SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP);
api_nh = &api.nexthops[0];
diff --git a/tests/.gitignore b/tests/.gitignore
index ab1d55b548..c2fe9c8890 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -24,10 +24,12 @@ __pycache__
/bgpd/test_ecommunity
/bgpd/test_mp_attr
/bgpd/test_mpath
+/bgpd/test_packet
/isisd/test_fuzz_isis_tlv
/isisd/test_fuzz_isis_tlv_tests.h
/isisd/test_isis_vertex_queue
/lib/cli/test_cli
+/lib/cli/test_cli_clippy.c
/lib/cli/test_commands
/lib/cli/test_commands_defun.c
/lib/test_buffer
@@ -38,6 +40,7 @@ __pycache__
/lib/test_memory
/lib/test_nexthop_iter
/lib/test_privs
+/lib/test_ringbuf
/lib/test_srcdest_table
/lib/test_segv
/lib/test_sig
@@ -48,3 +51,4 @@ __pycache__
/lib/test_ttable
/lib/test_zmq
/ospf6d/test_lsdb
+/ospf6d/test_lsdb_clippy.c
diff --git a/tests/lib/test_ringbuf.py b/tests/lib/test_ringbuf.py
index 860d872f86..5d994ddd7b 100644
--- a/tests/lib/test_ringbuf.py
+++ b/tests/lib/test_ringbuf.py
@@ -1,4 +1,6 @@
import frrtest
-class TestRingbuf(frrtest.TestExitNonzero):
+class TestRingbuf(frrtest.TestMultiOut):
program = './test_ringbuf'
+
+TestRingbuf.exit_cleanly()
diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c
index 5c316e077f..7f6c8aefa8 100644
--- a/zebra/zebra_rib.c
+++ b/zebra/zebra_rib.c
@@ -514,7 +514,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re,
nexthop->ifindex = newhop->ifindex;
}
return 1;
- } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_INTERNAL)) {
+ } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) {
resolved = 0;
for (ALL_NEXTHOPS(match->nexthop, newhop)) {
if (!CHECK_FLAG(newhop->flags,
diff --git a/zebra/zserv.c b/zebra/zserv.c
index 98cb54f7b8..bca8a509d8 100644
--- a/zebra/zserv.c
+++ b/zebra/zserv.c
@@ -1166,12 +1166,12 @@ static int zread_route_add(struct zserv *client, u_short length,
switch (api_nh->type) {
case NEXTHOP_TYPE_IFINDEX:
nexthop = route_entry_nexthop_ifindex_add(
- re, api_nh->ifindex, re->vrf_id);
+ re, api_nh->ifindex, api_nh->vrf_id);
break;
case NEXTHOP_TYPE_IPV4:
nexthop = route_entry_nexthop_ipv4_add(
re, &api_nh->gate.ipv4, NULL,
- re->vrf_id);
+ api_nh->vrf_id);
break;
case NEXTHOP_TYPE_IPV4_IFINDEX: {
@@ -1188,7 +1188,7 @@ static int zread_route_add(struct zserv *client, u_short length,
nexthop = route_entry_nexthop_ipv4_ifindex_add(
re, &api_nh->gate.ipv4, NULL, ifindex,
- re->vrf_id);
+ api_nh->vrf_id);
/* if this an EVPN route entry,
program the nh as neigh
@@ -1211,12 +1211,12 @@ static int zread_route_add(struct zserv *client, u_short length,
}
case NEXTHOP_TYPE_IPV6:
nexthop = route_entry_nexthop_ipv6_add(
- re, &api_nh->gate.ipv6, re->vrf_id);
+ re, &api_nh->gate.ipv6, api_nh->vrf_id);
break;
case NEXTHOP_TYPE_IPV6_IFINDEX:
nexthop = route_entry_nexthop_ipv6_ifindex_add(
re, &api_nh->gate.ipv6, api_nh->ifindex,
- re->vrf_id);
+ api_nh->vrf_id);
break;
case NEXTHOP_TYPE_BLACKHOLE:
nexthop = route_entry_nexthop_blackhole_add(