summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_evpn.c11
-rw-r--r--bgpd/bgp_evpn_mh.c8
-rw-r--r--bgpd/bgp_evpn_mh.h10
-rw-r--r--bgpd/bgp_mplsvpn.c40
-rw-r--r--bgpd/bgp_nht.c4
-rw-r--r--isisd/isis_adjacency.c10
-rw-r--r--isisd/isis_circuit.c7
-rw-r--r--isisd/isis_nb_config.c48
-rw-r--r--ospf6d/ospf6_flood.c43
-rw-r--r--pimd/pim6_cmd.c4
-rw-r--r--pimd/pim_cmd.c8
-rw-r--r--tests/topotests/zebra_multiple_connected/r1/ip_route2.json102
-rw-r--r--tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py24
-rw-r--r--watchfrr/watchfrr.c6
-rw-r--r--zebra/zebra_evpn_mh.c16
-rw-r--r--zebra/zebra_nhg.c3
16 files changed, 231 insertions, 113 deletions
diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c
index 3224c1a2b0..fbb0d2272a 100644
--- a/bgpd/bgp_evpn.c
+++ b/bgpd/bgp_evpn.c
@@ -3366,7 +3366,9 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
assert(attr);
- /* Only type-2, type-3, type-4 and type-5 are supported currently */
+ /* Only type-1, type-2, type-3, type-4 and type-5
+ * are supported currently
+ */
if (!(evp->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
|| evp->prefix.route_type == BGP_EVPN_IMET_ROUTE
|| evp->prefix.route_type == BGP_EVPN_ES_ROUTE
@@ -3471,7 +3473,7 @@ static int bgp_evpn_install_uninstall_table(struct bgp *bgp, afi_t afi,
if (evp->prefix.route_type == BGP_EVPN_ES_ROUTE) {
/* we will match based on the entire esi to avoid
- * imoort of an es route for esi2 into esi1
+ * import of an es route for esi2 into esi1
*/
es = bgp_evpn_es_find(&evp->prefix.es_addr.esi);
if (es && bgp_evpn_is_es_local(es))
@@ -6097,8 +6099,9 @@ bool bgp_evpn_is_prefix_nht_supported(const struct prefix *pfx)
* EVPN routes should be marked as valid only if the nexthop is
* reachable. Only if this happens, the route should be imported
* (into VNI or VRF routing tables) and/or advertised.
- * Note: This is currently applied for EVPN type-2, type-3 and
- * type-5 routes. It may be tweaked later on for other routes, or
+ * Note: This is currently applied for EVPN type-1, type-2,
+ * type-3, type-4 and type-5 routes.
+ * It may be tweaked later on for other routes, or
* even removed completely when all routes are handled.
*/
if (pfx && pfx->family == AF_EVPN
diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c
index b9e3577f5c..6db4cba44d 100644
--- a/bgpd/bgp_evpn_mh.c
+++ b/bgpd/bgp_evpn_mh.c
@@ -287,7 +287,7 @@ static int bgp_evpn_es_route_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
return ret;
}
-/* Install or unistall a Tyoe-4 route in the per-ES routing table */
+/* Install or unistall a Type-4 route in the per-ES routing table */
int bgp_evpn_es_route_install_uninstall(struct bgp *bgp, struct bgp_evpn_es *es,
afi_t afi, safi_t safi, struct prefix_evpn *evp,
struct bgp_path_info *pi, int install)
@@ -378,16 +378,16 @@ int bgp_evpn_mh_route_update(struct bgp *bgp, struct bgp_evpn_es *es,
remote_pi = tmp_pi;
}
- /* we don't expect to see a remote_ri at this point as
+ /* we don't expect to see a remote_pi at this point as
* an ES route has {esi, vtep_ip} as the key in the ES-rt-table
* in the VNI-rt-table.
*/
if (remote_pi) {
flog_err(
EC_BGP_ES_INVALID,
- "%u ERROR: local es route for ESI: %s Vtep %pI4 also learnt from remote",
+ "%u ERROR: local es route for ESI: %s vtep %pI4 also learnt from remote",
bgp->vrf_id, es ? es->esi_str : "Null",
- &es->originator_ip);
+ es ? &es->originator_ip : NULL);
return -1;
}
diff --git a/bgpd/bgp_evpn_mh.h b/bgpd/bgp_evpn_mh.h
index 2e2e4231e6..dc3fe44776 100644
--- a/bgpd/bgp_evpn_mh.h
+++ b/bgpd/bgp_evpn_mh.h
@@ -50,7 +50,9 @@ struct bgp_evpn_es_frag {
/* RD for this ES fragment */
struct prefix_rd prd;
- /* Memory used for linking bgp_evpn_es_rd to bgp_evpn_es->rd_list */
+ /* Memory used for linking bgp_evpn_es_frag to
+ * bgp_evpn_es->es_frag_list
+ */
struct listnode es_listnode;
/* List of ES-EVIs associated with this fragment */
@@ -59,11 +61,11 @@ struct bgp_evpn_es_frag {
/* Ethernet Segment entry -
* - Local and remote ESs are maintained in a global RB tree,
- * bgp_mh_info->es_rb_tree using ESI as key
+ * bgp_mh_info->es_rb_tree using ESI as key
* - Local ESs are received from zebra (BGP_EVPNES_LOCAL)
* - Remotes ESs are implicitly created (by reference) by a remote ES-EVI
* (BGP_EVPNES_REMOTE)
- * - An ES can be simulatenously LOCAL and REMOTE; infact all LOCAL ESs are
+ * - An ES can be simultaneously LOCAL and REMOTE; infact all LOCAL ESs are
* expected to have REMOTE ES peers.
*/
struct bgp_evpn_es {
@@ -101,7 +103,7 @@ struct bgp_evpn_es {
*/
struct listnode pend_es_listnode;
- /* [EVPNES_LOCAL] List of RDs for this ES (bgp_evpn_es_rd) */
+ /* [EVPNES_LOCAL] List of RDs for this ES (bgp_evpn_es_frag) */
struct list *es_frag_list;
struct bgp_evpn_es_frag *es_base_frag;
diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c
index 0074d5daac..b3d8d1b82d 100644
--- a/bgpd/bgp_mplsvpn.c
+++ b/bgpd/bgp_mplsvpn.c
@@ -516,28 +516,35 @@ static bool sid_exist(struct bgp *bgp, const struct in6_addr *sid)
}
/*
+ * This function generates a new SID based on bgp->srv6_locator_chunks and
+ * index. The locator and generated SID are stored in arguments sid_locator
+ * and sid, respectively.
+ *
* if index != 0: try to allocate as index-mode
* else: try to allocate as auto-mode
*/
static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
- struct in6_addr *sid_locator)
+ struct in6_addr *sid_locator,
+ struct in6_addr *sid)
{
struct listnode *node;
struct srv6_locator_chunk *chunk;
- struct in6_addr sid_buf;
bool alloced = false;
int label = 0;
+ uint8_t offset = 0;
- if (!bgp || !sid_locator)
+ if (!bgp || !sid_locator || !sid)
return false;
for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, chunk)) {
*sid_locator = chunk->prefix.prefix;
- sid_buf = chunk->prefix.prefix;
+ *sid = chunk->prefix.prefix;
+ offset = chunk->block_bits_length + chunk->node_bits_length;
+
if (index != 0) {
label = index << 12;
- transpose_sid(&sid_buf, label, 64, 16);
- if (sid_exist(bgp, &sid_buf))
+ transpose_sid(sid, label, offset, 16);
+ if (sid_exist(bgp, sid))
return false;
alloced = true;
break;
@@ -545,8 +552,8 @@ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
for (size_t i = 1; i < 255; i++) {
label = i << 12;
- transpose_sid(&sid_buf, label, 64, 16);
- if (sid_exist(bgp, &sid_buf))
+ transpose_sid(sid, label, offset, 16);
+ if (sid_exist(bgp, sid))
continue;
alloced = true;
break;
@@ -556,7 +563,7 @@ static uint32_t alloc_new_sid(struct bgp *bgp, uint32_t index,
if (!alloced)
return 0;
- sid_register(bgp, &sid_buf, bgp->srv6_locator_name);
+ sid_register(bgp, sid, bgp->srv6_locator_name);
return label;
}
@@ -600,20 +607,19 @@ void ensure_vrf_tovpn_sid(struct bgp *bgp_vpn, struct bgp *bgp_vrf, afi_t afi)
tovpn_sid_locator =
XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
- tovpn_sid_transpose_label =
- alloc_new_sid(bgp_vpn, tovpn_sid_index, tovpn_sid_locator);
+ tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
+
+ tovpn_sid_transpose_label = alloc_new_sid(bgp_vpn, tovpn_sid_index,
+ tovpn_sid_locator, tovpn_sid);
+
if (tovpn_sid_transpose_label == 0) {
zlog_debug("%s: not allocated new sid for vrf %s: afi %s",
__func__, bgp_vrf->name_pretty, afi2str(afi));
+ XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid_locator);
+ XFREE(MTYPE_BGP_SRV6_SID, tovpn_sid);
return;
}
- tovpn_sid = XCALLOC(MTYPE_BGP_SRV6_SID, sizeof(struct in6_addr));
- *tovpn_sid = *tovpn_sid_locator;
- transpose_sid(tovpn_sid, tovpn_sid_transpose_label,
- BGP_PREFIX_SID_SRV6_TRANSPOSITION_OFFSET,
- BGP_PREFIX_SID_SRV6_TRANSPOSITION_LENGTH);
-
if (debug) {
inet_ntop(AF_INET6, tovpn_sid, buf, sizeof(buf));
zlog_debug("%s: new sid %s allocated for vrf %s: afi %s",
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index d3ebc0e6a2..f5b3556731 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -589,6 +589,10 @@ static void bgp_nht_ifp_handle(struct interface *ifp, bool up)
if (!bgp)
return;
+ bgp_nht_ifp_table_handle(bgp, &bgp->nexthop_cache_table[AFI_IP], ifp,
+ up);
+ bgp_nht_ifp_table_handle(bgp, &bgp->import_check_table[AFI_IP], ifp,
+ up);
bgp_nht_ifp_table_handle(bgp, &bgp->nexthop_cache_table[AFI_IP6], ifp,
up);
bgp_nht_ifp_table_handle(bgp, &bgp->import_check_table[AFI_IP6], ifp,
diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c
index 2729dce382..11f17ec7bf 100644
--- a/isisd/isis_adjacency.c
+++ b/isisd/isis_adjacency.c
@@ -31,6 +31,7 @@
#include "thread.h"
#include "if.h"
#include "stream.h"
+#include "bfd.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
@@ -814,6 +815,15 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty,
vty_out(vty, " %s\n", buf);
}
}
+ if (adj->circuit && adj->circuit->bfd_config.enabled) {
+ vty_out(vty, " BFD is %s%s\n",
+ adj->bfd_session ? "active, status "
+ : "configured",
+ !adj->bfd_session
+ ? ""
+ : bfd_get_status_str(bfd_sess_status(
+ adj->bfd_session)));
+ }
for (ALL_LIST_ELEMENTS_RO(adj->adj_sids, anode, sra)) {
const char *adj_type;
const char *backup;
diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c
index c7bf1e2012..fedceed3bb 100644
--- a/isisd/isis_circuit.c
+++ b/isisd/isis_circuit.c
@@ -661,8 +661,11 @@ int isis_circuit_up(struct isis_circuit *circuit)
"Interface MTU %zu on %s is too low to support area lsp mtu %u!",
isis_circuit_pdu_size(circuit),
circuit->interface->name, circuit->area->lsp_mtu);
- isis_circuit_update_all_srmflags(circuit, 0);
- return ISIS_ERROR;
+
+ /* Allow ISIS to continue configuration. With this
+ * configuration failure ISIS will attempt to send lsp
+ * packets but will fail until the mtu is configured properly
+ */
}
if (circuit->circ_type == CIRCUIT_T_BROADCAST) {
diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c
index de7797813a..cf4c2aea0a 100644
--- a/isisd/isis_nb_config.c
+++ b/isisd/isis_nb_config.c
@@ -393,30 +393,11 @@ int isis_instance_purge_originator_modify(struct nb_cb_modify_args *args)
*/
int isis_instance_lsp_mtu_modify(struct nb_cb_modify_args *args)
{
- struct listnode *node;
- struct isis_circuit *circuit;
uint16_t lsp_mtu = yang_dnode_get_uint16(args->dnode, NULL);
struct isis_area *area;
switch (args->event) {
case NB_EV_VALIDATE:
- area = nb_running_get_entry(args->dnode, NULL, false);
- if (!area)
- break;
- for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) {
- if (circuit->state != C_STATE_INIT
- && circuit->state != C_STATE_UP)
- continue;
- if (lsp_mtu > isis_circuit_pdu_size(circuit)) {
- snprintf(
- args->errmsg, args->errmsg_len,
- "ISIS area contains circuit %s, which has a maximum PDU size of %zu",
- circuit->interface->name,
- isis_circuit_pdu_size(circuit));
- return NB_ERR_VALIDATION;
- }
- }
- break;
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
@@ -2552,43 +2533,14 @@ int isis_instance_mpls_ldp_sync_holddown_modify(struct nb_cb_modify_args *args)
*/
int lib_interface_isis_create(struct nb_cb_create_args *args)
{
- struct isis_area *area = NULL;
struct interface *ifp;
struct isis_circuit *circuit = NULL;
const char *area_tag = yang_dnode_get_string(args->dnode, "./area-tag");
- uint32_t min_mtu, actual_mtu;
switch (args->event) {
case NB_EV_PREPARE:
case NB_EV_ABORT:
- break;
case NB_EV_VALIDATE:
- /* check if interface mtu is sufficient. If the area has not
- * been created yet, assume default MTU for the area
- */
- ifp = nb_running_get_entry(args->dnode, NULL, false);
- /* zebra might not know yet about the MTU - nothing we can do */
- if (!ifp || ifp->mtu == 0)
- break;
- actual_mtu =
- if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu;
-
- area = isis_area_lookup(area_tag, ifp->vrf->vrf_id);
- if (area)
- min_mtu = area->lsp_mtu;
- else
-#ifndef FABRICD
- min_mtu = yang_get_default_uint16(
- "/frr-isisd:isis/instance/lsp/mtu");
-#else
- min_mtu = DEFAULT_LSP_MTU;
-#endif /* ifndef FABRICD */
- if (actual_mtu < min_mtu) {
- snprintf(args->errmsg, args->errmsg_len,
- "Interface %s has MTU %u, minimum MTU for the area is %u",
- ifp->name, actual_mtu, min_mtu);
- return NB_ERR_VALIDATION;
- }
break;
case NB_EV_APPLY:
ifp = nb_running_get_entry(args->dnode, NULL, true);
diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c
index cc82084e5e..bc9e2c3405 100644
--- a/ospf6d/ospf6_flood.c
+++ b/ospf6d/ospf6_flood.c
@@ -878,6 +878,28 @@ static int ospf6_is_maxage_lsa_drop(struct ospf6_lsa *lsa,
return 0;
}
+static bool ospf6_lsa_check_min_arrival(struct ospf6_lsa *lsa,
+ struct ospf6_neighbor *from)
+{
+ struct timeval now, res;
+ unsigned int time_delta_ms;
+
+ monotime(&now);
+ timersub(&now, &lsa->installed, &res);
+ time_delta_ms = (res.tv_sec * 1000) + (int)(res.tv_usec / 1000);
+
+ if (time_delta_ms < from->ospf6_if->area->ospf6->lsa_minarrival) {
+ if (IS_OSPF6_DEBUG_FLOODING ||
+ IS_OSPF6_DEBUG_FLOOD_TYPE(lsa->header->type))
+ zlog_debug(
+ "LSA can't be updated within MinLSArrival, %dms < %dms, discard",
+ time_delta_ms,
+ from->ospf6_if->area->ospf6->lsa_minarrival);
+ return true;
+ }
+ return false;
+}
+
/* RFC2328 section 13 The Flooding Procedure */
void ospf6_receive_lsa(struct ospf6_neighbor *from,
struct ospf6_lsa_header *lsa_header)
@@ -885,7 +907,6 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
struct ospf6_lsa *new = NULL, *old = NULL, *rem = NULL;
int ismore_recent;
int is_debug = 0;
- unsigned int time_delta_ms;
ismore_recent = 1;
assert(from);
@@ -993,19 +1014,7 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
/* (a) MinLSArrival check */
if (old) {
- struct timeval now, res;
- monotime(&now);
- timersub(&now, &old->installed, &res);
- time_delta_ms =
- (res.tv_sec * 1000) + (int)(res.tv_usec / 1000);
- if (time_delta_ms
- < from->ospf6_if->area->ospf6->lsa_minarrival) {
- if (is_debug)
- zlog_debug(
- "LSA can't be updated within MinLSArrival, %dms < %dms, discard",
- time_delta_ms,
- from->ospf6_if->area->ospf6
- ->lsa_minarrival);
+ if (ospf6_lsa_check_min_arrival(old, from)) {
ospf6_lsa_delete(new);
return; /* examin next lsa */
}
@@ -1222,7 +1231,11 @@ void ospf6_receive_lsa(struct ospf6_neighbor *from,
__PRETTY_FUNCTION__, old->name);
}
- /* XXX, MinLSArrival check !? RFC 2328 13 (8) */
+ /* MinLSArrival check as per RFC 2328 13 (8) */
+ if (ospf6_lsa_check_min_arrival(old, from)) {
+ ospf6_lsa_delete(new);
+ return; /* examin next lsa */
+ }
ospf6_lsdb_add(ospf6_lsa_copy(old),
from->lsupdate_list);
diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c
index 90840a95e0..ce26f912f4 100644
--- a/pimd/pim6_cmd.c
+++ b/pimd/pim6_cmd.c
@@ -170,7 +170,7 @@ DEFPY (ipv6_pim_rp_keep_alive,
"ipv6 pim rp keep-alive-timer (1-65535)$kat",
IPV6_STR
PIM_STR
- "Rendevous Point\n"
+ "Rendezvous Point\n"
"Keep alive Timer\n"
"Seconds\n")
{
@@ -183,7 +183,7 @@ DEFPY (no_ipv6_pim_rp_keep_alive,
NO_STR
IPV6_STR
PIM_STR
- "Rendevous Point\n"
+ "Rendezvous Point\n"
"Keep alive Timer\n"
IGNORED_IN_NO_STR)
{
diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c
index 8630f79b36..706a21322b 100644
--- a/pimd/pim_cmd.c
+++ b/pimd/pim_cmd.c
@@ -4909,7 +4909,7 @@ DEFPY (ip_pim_rp_keep_alive,
"ip pim rp keep-alive-timer (1-65535)$kat",
IP_STR
"pim multicast routing\n"
- "Rendevous Point\n"
+ "Rendezvous Point\n"
"Keep alive Timer\n"
"Seconds\n")
{
@@ -4922,7 +4922,7 @@ DEFUN (no_ip_pim_rp_keep_alive,
NO_STR
IP_STR
"pim multicast routing\n"
- "Rendevous Point\n"
+ "Rendezvous Point\n"
"Keep alive Timer\n"
IGNORED_IN_NO_STR)
{
@@ -5062,7 +5062,7 @@ DEFPY (ip_pim_rp,
"ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp",
IP_STR
"pim multicast routing\n"
- "Rendevous Point\n"
+ "Rendezvous Point\n"
"ip address of RP\n"
"Group Address range to cover\n")
{
@@ -5090,7 +5090,7 @@ DEFPY (no_ip_pim_rp,
NO_STR
IP_STR
"pim multicast routing\n"
- "Rendevous Point\n"
+ "Rendezvous Point\n"
"ip address of RP\n"
"Group Address range to cover\n")
{
diff --git a/tests/topotests/zebra_multiple_connected/r1/ip_route2.json b/tests/topotests/zebra_multiple_connected/r1/ip_route2.json
new file mode 100644
index 0000000000..26995654f7
--- /dev/null
+++ b/tests/topotests/zebra_multiple_connected/r1/ip_route2.json
@@ -0,0 +1,102 @@
+{
+ "10.0.1.0/24":[
+ {
+ "prefix":"10.0.1.0/24",
+ "prefixLen":24,
+ "protocol":"connected",
+ "vrfName":"default",
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ },
+ {
+ "prefix":"10.0.1.0/24",
+ "prefixLen":24,
+ "protocol":"connected",
+ "vrfName":"default",
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r1-eth0",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.0.1.30/32":[
+ {
+ "prefix":"10.0.1.30/32",
+ "prefixLen":32,
+ "protocol":"kernel",
+ "vrfName":"default",
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "directlyConnected":true,
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "10.9.9.0/24":[
+ {
+ "prefix":"10.9.9.0/24",
+ "prefixLen":24,
+ "protocol":"kernel",
+ "vrfName":"default",
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.30",
+ "afi":"ipv4",
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ],
+ "192.168.1.1/32":[
+ {
+ "prefix":"192.168.1.1/32",
+ "prefixLen":32,
+ "protocol":"kernel",
+ "vrfName":"default",
+ "distance":0,
+ "metric":0,
+ "installed":true,
+ "table":254,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.1.99",
+ "afi":"ipv4",
+ "interfaceName":"r1-eth1",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
index 31ac831b35..8882cf5bda 100644
--- a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
+++ b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py
@@ -133,6 +133,30 @@ def test_zebra_connected_multiple():
assert result is None, "Kernel route is missing from zebra"
+def test_zebra_system_recursion():
+ "Test a system route recursing through another system route"
+
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r1"]
+ router.run("ip route add 10.0.1.30/32 dev r1-eth1")
+ router.run("ip route add 10.9.9.0/24 via 10.0.1.30 dev r1-eth1")
+ router.run("ip link add dummy2 type dummy")
+ router.run("ip link set dummy2 up")
+ router.run("ip link set dummy2 down")
+
+ routes = "{}/{}/ip_route2.json".format(CWD, router.name)
+ expected = json.loads(open(routes).read())
+ test_func = partial(
+ topotest.router_json_cmp, router, "show ip route json", expected
+ )
+
+ _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assert result is None, "Kernel route is missing from zebra"
+
+
if __name__ == "__main__":
args = ["-s"] + sys.argv[1:]
sys.exit(pytest.main(args))
diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c
index e5afa68986..51e4f802c9 100644
--- a/watchfrr/watchfrr.c
+++ b/watchfrr/watchfrr.c
@@ -1053,6 +1053,12 @@ void watchfrr_status(struct vty *vty)
struct timeval delay;
vty_out(vty, "watchfrr global phase: %s\n", phase_str[gs.phase]);
+ vty_out(vty, " Restart Command: %pSQq\n", gs.restart_command);
+ vty_out(vty, " Start Command: %pSQq\n", gs.start_command);
+ vty_out(vty, " Stop Command: %pSQq\n", gs.stop_command);
+ vty_out(vty, " Min Restart Interval: %ld\n", gs.min_restart_interval);
+ vty_out(vty, " Max Restart Interval: %ld\n", gs.max_restart_interval);
+ vty_out(vty, " Restart Timeout: %ld\n", gs.restart_timeout);
if (gs.restart.pid)
vty_out(vty, " global restart running, pid %ld\n",
(long)gs.restart.pid);
diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c
index 6c4e8b99f7..b1e48374c4 100644
--- a/zebra/zebra_evpn_mh.c
+++ b/zebra/zebra_evpn_mh.c
@@ -3761,18 +3761,10 @@ static inline bool zebra_evpn_mh_is_all_uplinks_down(void)
static void zebra_evpn_mh_uplink_oper_flags_update(struct zebra_if *zif,
bool set)
{
- if (set) {
- if (if_is_operative(zif->ifp)) {
- if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)) {
- zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
- ++zmh_info->uplink_oper_up_cnt;
- }
- } else {
- if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP) {
- zif->flags &= ~ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
- if (zmh_info->uplink_oper_up_cnt)
- --zmh_info->uplink_oper_up_cnt;
- }
+ if (set && if_is_operative(zif->ifp)) {
+ if (!(zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP)) {
+ zif->flags |= ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP;
+ ++zmh_info->uplink_oper_up_cnt;
}
} else {
if (zif->flags & ZIF_FLAG_EVPN_MH_UPLINK_OPER_UP) {
diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c
index f4524a8018..069d35c6a3 100644
--- a/zebra/zebra_nhg.c
+++ b/zebra/zebra_nhg.c
@@ -2265,7 +2265,8 @@ static int nexthop_active(struct nexthop *nexthop, struct nhg_hash_entry *nhe,
continue;
}
- if (match->type == ZEBRA_ROUTE_CONNECT) {
+ if ((match->type == ZEBRA_ROUTE_CONNECT) ||
+ (RIB_SYSTEM_ROUTE(match) && RSYSTEM_ROUTE(type))) {
match = zebra_nhg_connected_ifindex(rn, match,
nexthop->ifindex);