summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bfdd/bfd.c21
-rw-r--r--bfdd/bfd.h3
-rw-r--r--bfdd/bfd_packet.c16
-rw-r--r--bgpd/bgp_bfd.c34
-rw-r--r--bgpd/bgp_nht.c5
-rw-r--r--bgpd/bgp_open.c91
-rw-r--r--bgpd/bgp_open.h5
-rw-r--r--bgpd/bgp_vty.c132
-rw-r--r--bgpd/bgpd.c41
-rw-r--r--bgpd/bgpd.h18
-rw-r--r--doc/user/bgp.rst15
-rw-r--r--doc/user/zebra.rst55
-rw-r--r--lib/bfd.c9
-rw-r--r--lib/bfd.h6
-rw-r--r--lib/if.c3
-rw-r--r--lib/if.h1
-rw-r--r--lib/vrf.c9
-rw-r--r--ospf6d/ospf6_interface.c3
-rw-r--r--ospf6d/ospf6_message.c6
-rw-r--r--ospf6d/ospf6_neighbor.c5
-rw-r--r--ospf6d/ospf6_neighbor.h2
-rw-r--r--ospf6d/ospf6_route.c24
-rw-r--r--ospfd/ospf_dump.c29
-rw-r--r--ospfd/ospf_dump.h5
-rw-r--r--ospfd/ospf_snmp.c2
-rw-r--r--ospfd/ospf_vty.c42
-rw-r--r--pceplib/test/pcep_msg_tools_test.c65
-rw-r--r--pceplib/test/pcep_session_logic_loop_test.c1
-rw-r--r--pimd/pim_join.c10
-rw-r--r--pimd/pim_register.c10
-rw-r--r--pimd/pim_zebra.c15
-rw-r--r--tests/topotests/all_protocol_startup/test_all_protocol_startup.py8
-rw-r--r--tests/topotests/ldp_vpls_topo1/r1/show_ip_route_after_link_down.ref20
-rw-r--r--tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py12
-rw-r--r--tests/topotests/ospf_topo1/test_ospf_topo1.py28
-rw-r--r--tests/topotests/pim_basic/test_pim.py6
-rw-r--r--zebra/zebra_evpn_mac.c32
-rw-r--r--zebra/zebra_l2.c2
-rw-r--r--zebra/zebra_netns_notify.c1
-rw-r--r--zebra/zebra_vxlan.c12
40 files changed, 655 insertions, 149 deletions
diff --git a/bfdd/bfd.c b/bfdd/bfd.c
index a4091534f5..f497480457 100644
--- a/bfdd/bfd.c
+++ b/bfdd/bfd.c
@@ -590,10 +590,10 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa,
struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
struct sockaddr_any *peer,
struct sockaddr_any *local,
- ifindex_t ifindex, vrf_id_t vrfid,
+ struct interface *ifp,
+ vrf_id_t vrfid,
bool is_mhop)
{
- struct interface *ifp;
struct vrf *vrf;
struct bfd_key key;
@@ -601,21 +601,8 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
if (cp->discrs.remote_discr)
return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr));
- /*
- * Search for session without using discriminator.
- *
- * XXX: we can't trust `vrfid` because the VRF handling is not
- * properly implemented. Meanwhile we should use the interface
- * VRF to find out which one it belongs.
- */
- ifp = if_lookup_by_index_all_vrf(ifindex);
- if (ifp == NULL) {
- if (vrfid != VRF_DEFAULT)
- vrf = vrf_lookup_by_id(vrfid);
- else
- vrf = NULL;
- } else
- vrf = vrf_lookup_by_id(ifp->vrf_id);
+ /* Search for session without using discriminator. */
+ vrf = vrf_lookup_by_id(vrfid);
gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL,
vrf ? vrf->name : VRF_DEFAULT_NAME);
diff --git a/bfdd/bfd.h b/bfdd/bfd.h
index 7d5b7887c7..dfe1a20303 100644
--- a/bfdd/bfd.h
+++ b/bfdd/bfd.h
@@ -600,7 +600,8 @@ void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo);
struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp,
struct sockaddr_any *peer,
struct sockaddr_any *local,
- ifindex_t ifindex, vrf_id_t vrfid,
+ struct interface *ifp,
+ vrf_id_t vrfid,
bool is_mhop);
struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc);
diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c
index 3d6ca6ddd3..b7c1af7e71 100644
--- a/bfdd/bfd_packet.c
+++ b/bfdd/bfd_packet.c
@@ -546,8 +546,6 @@ int bfd_recv_cb(struct thread *t)
struct interface *ifp = NULL;
struct bfd_vrf_global *bvrf = THREAD_ARG(t);
- vrfid = bvrf->vrf->vrf_id;
-
/* Schedule next read. */
bfd_sd_reschedule(bvrf, sd);
@@ -573,9 +571,15 @@ int bfd_recv_cb(struct thread *t)
&local, &peer);
}
- /* update vrf-id because when in vrf-lite mode,
- * the socket is on default namespace
+ /*
+ * With netns backend, we have a separate socket in each VRF. It means
+ * that bvrf here is correct and we believe the bvrf->vrf->vrf_id.
+ * With VRF-lite backend, we have a single socket in the default VRF.
+ * It means that we can't believe the bvrf->vrf->vrf_id. But in
+ * VRF-lite, the ifindex is globally unique, so we can retrieve the
+ * correct vrf_id from the interface.
*/
+ vrfid = bvrf->vrf->vrf_id;
if (ifindex) {
ifp = if_lookup_by_index(ifindex, vrfid);
if (ifp)
@@ -628,7 +632,7 @@ int bfd_recv_cb(struct thread *t)
}
/* Find the session that this packet belongs. */
- bfd = ptm_bfd_sess_find(cp, &peer, &local, ifindex, vrfid, is_mhop);
+ bfd = ptm_bfd_sess_find(cp, &peer, &local, ifp, vrfid, is_mhop);
if (bfd == NULL) {
cp_debug(is_mhop, &peer, &local, ifindex, vrfid,
"no session found");
@@ -657,7 +661,7 @@ int bfd_recv_cb(struct thread *t)
* packet came in.
*/
if (!is_mhop && bfd->ifp == NULL)
- bfd->ifp = if_lookup_by_index(ifindex, vrfid);
+ bfd->ifp = ifp;
/* Log remote discriminator changes. */
if ((bfd->discrs.remote_discr != 0)
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index 4995f9a1fd..f23e6b2e9b 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -150,6 +150,7 @@ void bgp_peer_config_apply(struct peer *p, struct peer_group *pg)
void bgp_peer_bfd_update_source(struct peer *p)
{
struct bfd_session_params *session = p->bfd_config->session;
+ const union sockunion *source;
bool changed = false;
int family;
union {
@@ -161,44 +162,45 @@ void bgp_peer_bfd_update_source(struct peer *p)
if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP))
return;
+ /* Figure out the correct source to use. */
+ if (CHECK_FLAG(p->flags, PEER_FLAG_UPDATE_SOURCE))
+ source = p->update_source;
+ else
+ source = p->su_local;
+
/* Update peer's source/destination addresses. */
bfd_sess_addresses(session, &family, &src.v6, &dst.v6);
if (family == AF_INET) {
- if ((p->su_local
- && p->su_local->sin.sin_addr.s_addr != src.v4.s_addr)
+ if ((source && source->sin.sin_addr.s_addr != src.v4.s_addr)
|| p->su.sin.sin_addr.s_addr != dst.v4.s_addr) {
if (BGP_DEBUG(bfd, BFD_LIB))
zlog_debug(
"%s: address [%pI4->%pI4] to [%pI4->%pI4]",
__func__, &src.v4, &dst.v4,
- p->su_local ? &p->su_local->sin.sin_addr
- : &src.v4,
+ source ? &source->sin.sin_addr
+ : &src.v4,
&p->su.sin.sin_addr);
bfd_sess_set_ipv4_addrs(
- session,
- p->su_local ? &p->su_local->sin.sin_addr : NULL,
+ session, source ? &source->sin.sin_addr : NULL,
&p->su.sin.sin_addr);
changed = true;
}
} else {
- if ((p->su_local
- && memcmp(&p->su_local->sin6, &src.v6, sizeof(src.v6)))
+ if ((source && memcmp(&source->sin6, &src.v6, sizeof(src.v6)))
|| memcmp(&p->su.sin6, &dst.v6, sizeof(dst.v6))) {
if (BGP_DEBUG(bfd, BFD_LIB))
zlog_debug(
"%s: address [%pI6->%pI6] to [%pI6->%pI6]",
__func__, &src.v6, &dst.v6,
- p->su_local
- ? &p->su_local->sin6.sin6_addr
- : &src.v6,
+ source ? &source->sin6.sin6_addr
+ : &src.v6,
&p->su.sin6.sin6_addr);
- bfd_sess_set_ipv6_addrs(
- session,
- p->su_local ? &p->su_local->sin6.sin6_addr
- : NULL,
- &p->su.sin6.sin6_addr);
+ bfd_sess_set_ipv6_addrs(session,
+ source ? &source->sin6.sin6_addr
+ : NULL,
+ &p->su.sin6.sin6_addr);
changed = true;
}
}
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 061fa6f087..28dd19d842 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -611,7 +611,8 @@ void bgp_nht_ifp_down(struct interface *ifp)
static int bgp_nht_ifp_initial(struct thread *thread)
{
ifindex_t ifindex = THREAD_VAL(thread);
- struct interface *ifp = if_lookup_by_index_all_vrf(ifindex);
+ struct bgp *bgp = THREAD_ARG(thread);
+ struct interface *ifp = if_lookup_by_index(ifindex, bgp->vrf_id);
if (!ifp)
return 0;
@@ -657,7 +658,7 @@ void bgp_nht_interface_events(struct peer *peer)
return;
if (bnc->ifindex)
- thread_add_event(bm->master, bgp_nht_ifp_initial, NULL,
+ thread_add_event(bm->master, bgp_nht_ifp_initial, bnc->bgp,
bnc->ifindex, NULL);
}
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index ca8b1e398b..e15690835a 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -572,6 +572,46 @@ static int bgp_capability_restart(struct peer *peer,
return 0;
}
+static int bgp_capability_llgr(struct peer *peer,
+ struct capability_header *caphdr)
+{
+ struct stream *s = BGP_INPUT(peer);
+ size_t end = stream_get_getp(s) + caphdr->length;
+
+ SET_FLAG(peer->cap, PEER_CAP_LLGR_RCV);
+
+ while (stream_get_getp(s) + 4 <= end) {
+ afi_t afi;
+ safi_t safi;
+ iana_afi_t pkt_afi = stream_getw(s);
+ iana_safi_t pkt_safi = stream_getc(s);
+ uint8_t flags = stream_getc(s);
+ uint32_t stale_time = stream_get3(s);
+
+ if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Addr-family %s/%s(afi/safi) not supported. Ignore the Long-lived Graceful Restart capability for this AFI/SAFI",
+ peer->host, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ } else if (!peer->afc[afi][safi]
+ || !CHECK_FLAG(peer->af_cap[afi][safi],
+ PEER_CAP_RESTART_AF_RCV)) {
+ if (bgp_debug_neighbor_events(peer))
+ zlog_debug(
+ "%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Long-lived Graceful Restart capability",
+ peer->host, iana_afi2str(pkt_afi),
+ iana_safi2str(pkt_safi));
+ } else {
+ peer->llgr[afi][safi].flags = flags;
+ peer->llgr[afi][safi].stale_time = stale_time;
+ SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_LLGR_AF_RCV);
+ }
+ }
+
+ return 0;
+}
+
/* Unlike other capability parsing routines, this one returns 0 on error */
static as_t bgp_capability_as4(struct peer *peer, struct capability_header *hdr)
{
@@ -954,6 +994,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
case CAPABILITY_CODE_RESTART:
ret = bgp_capability_restart(peer, &caphdr);
break;
+ case CAPABILITY_CODE_LLGR:
+ ret = bgp_capability_llgr(peer, &caphdr);
+ break;
case CAPABILITY_CODE_DYNAMIC:
case CAPABILITY_CODE_DYNAMIC_OLD:
SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV);
@@ -1404,6 +1447,53 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
stream_putc_at(s, capp, len);
}
+static void bgp_peer_send_llgr_capability(struct stream *s, struct peer *peer,
+ unsigned long cp)
+{
+ int len;
+ iana_afi_t pkt_afi;
+ afi_t afi;
+ safi_t safi;
+ iana_safi_t pkt_safi;
+ unsigned long capp = 0;
+ unsigned long rcapp = 0;
+
+ if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV))
+ return;
+
+ SET_FLAG(peer->cap, PEER_CAP_LLGR_ADV);
+
+ stream_putc(s, BGP_OPEN_OPT_CAP);
+ capp = stream_get_endp(s); /* Set Capability Len Pointer */
+ stream_putc(s, 0); /* Capability Length */
+ stream_putc(s, CAPABILITY_CODE_LLGR);
+
+ rcapp = stream_get_endp(s);
+ stream_putc(s, 0);
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (!peer->afc[afi][safi])
+ continue;
+
+ bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi);
+
+ stream_putw(s, pkt_afi);
+ stream_putc(s, pkt_safi);
+ stream_putc(s, LLGR_F_BIT);
+ stream_put3(s, peer->bgp->llgr_stale_time);
+
+ SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_LLGR_AF_ADV);
+ }
+
+ /* Total Long-lived Graceful Restart capability Len. */
+ len = stream_get_endp(s) - rcapp - 1;
+ stream_putc_at(s, rcapp, len);
+
+ /* Total Capability Len. */
+ len = stream_get_endp(s) - capp - 1;
+ stream_putc_at(s, capp, len);
+}
+
/* Fill in capability open option to the packet. */
void bgp_open_capability(struct stream *s, struct peer *peer)
{
@@ -1632,6 +1722,7 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
}
bgp_peer_send_gr_capability(s, peer, cp);
+ bgp_peer_send_llgr_capability(s, peer, cp);
/* Total Opt Parm Len. */
len = stream_get_endp(s) - cp - 1;
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index bc6eedac85..0d616926a2 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -50,6 +50,7 @@ struct graceful_restart_af {
#define CAPABILITY_CODE_DYNAMIC 67 /* Dynamic Capability */
#define CAPABILITY_CODE_ADDPATH 69 /* Addpath Capability */
#define CAPABILITY_CODE_ENHANCED_RR 70 /* Enhanced Route Refresh capability */
+#define CAPABILITY_CODE_LLGR 71 /* Long-lived Graceful Restart */
#define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capability */
#define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */
#define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */
@@ -66,6 +67,7 @@ struct graceful_restart_af {
#define CAPABILITY_CODE_ENHE_LEN 6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */
#define CAPABILITY_CODE_MIN_FQDN_LEN 2
#define CAPABILITY_CODE_ENHANCED_LEN 0
+#define CAPABILITY_CODE_LLGR_LEN 0
#define CAPABILITY_CODE_ORF_LEN 5
#define CAPABILITY_CODE_EXT_MESSAGE_LEN 0 /* Extended Message Support */
@@ -88,6 +90,9 @@ struct graceful_restart_af {
#define RESTART_R_BIT 0x8000
#define RESTART_F_BIT 0x80
+/* Long-lived Graceful Restart */
+#define LLGR_F_BIT 0x80
+
extern int bgp_open_option_parse(struct peer *, uint8_t, int *);
extern void bgp_open_capability(struct stream *, struct peer *);
extern void bgp_capability_vty_out(struct vty *vty, struct peer *peer,
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 772e20dc85..65806bb5f4 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -3168,6 +3168,36 @@ DEFUN (no_bgp_graceful_restart_rib_stale_time,
return CMD_SUCCESS;
}
+DEFUN(bgp_llgr_stalepath_time, bgp_llgr_stalepath_time_cmd,
+ "bgp long-lived-graceful-restart stale-time (0-4294967295)", BGP_STR
+ "Enable Long-lived Graceful Restart\n"
+ "Specifies maximum time to wait before purging long-lived stale routes\n"
+ "Stale time value (seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ uint32_t llgr_stale_time;
+
+ llgr_stale_time = strtoul(argv[3]->arg, NULL, 10);
+ bgp->llgr_stale_time = llgr_stale_time;
+
+ return CMD_SUCCESS;
+}
+
+DEFUN(no_bgp_llgr_stalepath_time, no_bgp_llgr_stalepath_time_cmd,
+ "no bgp long-lived-graceful-restart stale-time [(0-4294967295)]",
+ NO_STR BGP_STR
+ "Enable Long-lived Graceful Restart\n"
+ "Specifies maximum time to wait before purging long-lived stale routes\n"
+ "Stale time value (seconds)\n")
+{
+ VTY_DECLVAR_CONTEXT(bgp, bgp);
+
+ bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME;
+
+ return CMD_SUCCESS;
+}
+
static inline void bgp_initiate_graceful_shut_unshut(struct vty *vty,
struct bgp *bgp)
{
@@ -12838,6 +12868,61 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
}
}
+ /* Long-lived Graceful Restart */
+ if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV)
+ || CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) {
+ json_object *json_llgr = NULL;
+ const char *afi_safi_str;
+
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_LLGR_ADV)
+ && CHECK_FLAG(p->cap,
+ PEER_CAP_LLGR_RCV))
+ json_object_string_add(
+ json_cap,
+ "longLivedGracefulRestart",
+ "advertisedAndReceived");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_LLGR_ADV))
+ json_object_string_add(
+ json_cap,
+ "longLivedGracefulRestart",
+ "advertised");
+ else if (CHECK_FLAG(p->cap,
+ PEER_CAP_LLGR_RCV))
+ json_object_string_add(
+ json_cap,
+ "longLivedGracefulRestart",
+ "received");
+
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_LLGR_RCV)) {
+ json_llgr =
+ json_object_new_object();
+
+ FOREACH_AFI_SAFI (afi, safi) {
+ if (CHECK_FLAG(
+ p->af_cap
+ [afi]
+ [safi],
+ PEER_CAP_ENHE_AF_RCV)) {
+ afi_safi_str = get_afi_safi_str(
+ afi,
+ safi,
+ true);
+ json_object_string_add(
+ json_llgr,
+ afi_safi_str,
+ "received");
+ }
+ }
+ json_object_object_add(
+ json_cap,
+ "longLivedGracefulRestartByPeer",
+ json_llgr);
+ }
+ }
+
/* Route Refresh */
if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV)
|| CHECK_FLAG(p->cap,
@@ -13278,6 +13363,43 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
}
}
+ /* Long-lived Graceful Restart */
+ if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV)
+ || CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) {
+ vty_out(vty,
+ " Long-lived Graceful Restart:");
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_LLGR_ADV))
+ vty_out(vty, " advertised");
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_LLGR_RCV))
+ vty_out(vty, " %sreceived",
+ CHECK_FLAG(
+ p->cap,
+ PEER_CAP_LLGR_ADV)
+ ? "and "
+ : "");
+ vty_out(vty, "\n");
+
+ if (CHECK_FLAG(p->cap,
+ PEER_CAP_LLGR_RCV)) {
+ vty_out(vty,
+ " Address families by peer:\n");
+ FOREACH_AFI_SAFI (afi, safi)
+ if (CHECK_FLAG(
+ p->af_cap
+ [afi]
+ [safi],
+ PEER_CAP_LLGR_AF_RCV))
+ vty_out(vty,
+ " %s\n",
+ get_afi_safi_str(
+ afi,
+ safi,
+ false));
+ }
+ }
+
/* Route Refresh */
if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV)
|| CHECK_FLAG(p->cap,
@@ -17253,6 +17375,12 @@ int bgp_config_write(struct vty *vty)
if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN))
vty_out(vty, " bgp graceful-shutdown\n");
+ /* Long-lived Graceful Restart */
+ if (bgp->llgr_stale_time != BGP_DEFAULT_LLGR_STALE_TIME)
+ vty_out(vty,
+ " bgp long-lived-graceful-restart stale-time %u\n",
+ bgp->llgr_stale_time);
+
/* BGP graceful-restart. */
if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME)
vty_out(vty,
@@ -17830,6 +17958,10 @@ void bgp_vty_init(void)
install_element(BGP_NODE, &bgp_graceful_shutdown_cmd);
install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd);
+ /* "bgp long-lived-graceful-restart" commands */
+ install_element(BGP_NODE, &bgp_llgr_stalepath_time_cmd);
+ install_element(BGP_NODE, &no_bgp_llgr_stalepath_time_cmd);
+
/* "bgp fast-external-failover" commands */
install_element(BGP_NODE, &bgp_fast_external_failover_cmd);
install_element(BGP_NODE, &no_bgp_fast_external_failover_cmd);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index c5a5e49a48..9316d71baf 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -3169,6 +3169,7 @@ static struct bgp *bgp_create(as_t *as, const char *name,
bgp_addpath_init_bgp_data(&bgp->tx_addpath);
bgp->fast_convergence = false;
bgp->as = *as;
+ bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME;
#ifdef ENABLE_BGP_VNC
if (inst_type != BGP_INSTANCE_TYPE_VRF) {
@@ -4752,6 +4753,10 @@ int peer_ebgp_multihop_set(struct peer *peer, int ttl)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
+
+ /* Reconfigure BFD peer with new TTL. */
+ if (peer->bfd_config)
+ bgp_peer_bfd_update_source(peer);
}
} else {
group = peer->group;
@@ -4766,6 +4771,10 @@ int peer_ebgp_multihop_set(struct peer *peer, int ttl)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
+
+ /* Reconfigure BFD peer with new TTL. */
+ if (peer->bfd_config)
+ bgp_peer_bfd_update_source(peer);
}
}
return 0;
@@ -4799,6 +4808,10 @@ int peer_ebgp_multihop_unset(struct peer *peer)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
else
bgp_session_reset(peer);
+
+ /* Reconfigure BFD peer with new TTL. */
+ if (peer->bfd_config)
+ bgp_peer_bfd_update_source(peer);
} else {
group = peer->group;
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
@@ -4815,6 +4828,10 @@ int peer_ebgp_multihop_unset(struct peer *peer)
else
bgp_session_reset(peer);
}
+
+ /* Reconfigure BFD peer with new TTL. */
+ if (peer->bfd_config)
+ bgp_peer_bfd_update_source(peer);
}
}
return 0;
@@ -4860,6 +4877,10 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname)
} else
bgp_session_reset(peer);
+ /* Apply new source configuration to BFD session. */
+ if (peer->bfd_config)
+ bgp_peer_bfd_update_source(peer);
+
/* Skip peer-group mechanics for regular peers. */
return 0;
}
@@ -4893,6 +4914,10 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
bgp_session_reset(member);
+
+ /* Apply new source configuration to BFD session. */
+ if (member->bfd_config)
+ bgp_peer_bfd_update_source(member);
}
return 0;
@@ -4923,6 +4948,10 @@ int peer_update_source_addr_set(struct peer *peer, const union sockunion *su)
} else
bgp_session_reset(peer);
+ /* Apply new source configuration to BFD session. */
+ if (peer->bfd_config)
+ bgp_peer_bfd_update_source(peer);
+
/* Skip peer-group mechanics for regular peers. */
return 0;
}
@@ -4955,6 +4984,10 @@ int peer_update_source_addr_set(struct peer *peer, const union sockunion *su)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
bgp_session_reset(member);
+
+ /* Apply new source configuration to BFD session. */
+ if (member->bfd_config)
+ bgp_peer_bfd_update_source(member);
}
return 0;
@@ -4992,6 +5025,10 @@ int peer_update_source_unset(struct peer *peer)
} else
bgp_session_reset(peer);
+ /* Apply new source configuration to BFD session. */
+ if (peer->bfd_config)
+ bgp_peer_bfd_update_source(peer);
+
/* Skip peer-group mechanics for regular peers. */
return 0;
}
@@ -5023,6 +5060,10 @@ int peer_update_source_unset(struct peer *peer)
BGP_NOTIFY_CEASE_CONFIG_CHANGE);
} else
bgp_session_reset(member);
+
+ /* Apply new source configuration to BFD session. */
+ if (member->bfd_config)
+ bgp_peer_bfd_update_source(member);
}
return 0;
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 5e1eacbb9e..e60acecfae 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -613,6 +613,9 @@ struct bgp {
struct graceful_restart_info gr_info[AFI_MAX][SAFI_MAX];
uint32_t rib_stale_time;
+ /* BGP Long-lived Graceful Restart */
+ uint32_t llgr_stale_time;
+
#define BGP_ROUTE_SELECT_DELAY 1
#define BGP_MAX_BEST_ROUTE_SELECT 10000
/* Maximum-paths configuration */
@@ -1052,6 +1055,11 @@ enum bgp_fsm_status {
#define PEER_HOSTNAME(peer) ((peer)->host ? (peer)->host : "(unknown peer)")
+struct llgr_info {
+ uint32_t stale_time;
+ uint8_t flags;
+};
+
/* BGP neighbor structure. */
struct peer {
/* BGP structure. */
@@ -1182,6 +1190,8 @@ struct peer {
#define PEER_CAP_ENHANCED_RR_RCV (1U << 18) /* enhanced rr received */
#define PEER_CAP_EXTENDED_MESSAGE_ADV (1U << 19)
#define PEER_CAP_EXTENDED_MESSAGE_RCV (1U << 20)
+#define PEER_CAP_LLGR_ADV (1U << 21)
+#define PEER_CAP_LLGR_RCV (1U << 22)
/* Capability flags (reset in bgp_stop) */
uint32_t af_cap[AFI_MAX][SAFI_MAX];
@@ -1200,6 +1210,8 @@ struct peer {
#define PEER_CAP_ENHE_AF_ADV (1U << 12) /* Extended nexthopi afi/safi advertised */
#define PEER_CAP_ENHE_AF_RCV (1U << 13) /* Extended nexthop afi/safi received */
#define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */
+#define PEER_CAP_LLGR_AF_ADV (1U << 15)
+#define PEER_CAP_LLGR_AF_RCV (1U << 16)
/* Global configuration flags. */
/*
@@ -1657,6 +1669,9 @@ struct peer {
/* set TCP max segment size */
uint32_t tcp_mss;
+ /* Long-lived Graceful Restart */
+ struct llgr_info llgr[AFI_MAX][SAFI_MAX];
+
QOBJ_FIELDS;
};
DECLARE_QOBJ_TYPE(peer);
@@ -1869,6 +1884,9 @@ struct bgp_nlri {
#define BGP_DEFAULT_RIB_STALE_TIME 500
#define BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME 1
+/* BGP Long-lived Graceful Restart */
+#define BGP_DEFAULT_LLGR_STALE_TIME 360
+
/* BGP uptime string length. */
#define BGP_UPTIME_LEN 25
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 1793ae3d27..68b4d74dd6 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -989,6 +989,18 @@ BGP GR Peer Mode Commands
at the peer level.
+Long-lived Graceful Restart
+---------------------------
+
+Currently, only restarter mode is supported. This capability is advertised only
+if graceful restart capability is negotiated.
+
+.. clicmd:: bgp long-lived-graceful-restart stale-time (0-4294967295)
+
+ Specifies the maximum time to wait before purging long-lived stale routes for
+ helper routers.
+
+
.. _bgp-shutdown:
Administrative Shutdown
@@ -1432,9 +1444,6 @@ Configuring Peers
IPv4 session addresses, see the ``neighbor PEER update-source`` command
below.
- This command is deprecated and may be removed in a future release. Its use
- should be avoided.
-
.. clicmd:: neighbor PEER interface remote-as <internal|external|ASN>
Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The
diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst
index de327dfe21..c5440ef88d 100644
--- a/doc/user/zebra.rst
+++ b/doc/user/zebra.rst
@@ -143,8 +143,8 @@ Standard Commands
Configure an IPv4 Point-to-Point address on the interface. (The concept of
PtP addressing does not exist for IPv6.)
- `local-addr` has no subnet mask since the local side in PtP addressing is
- always a single (/32) address. `peer-addr/prefix` can be an arbitrary subnet
+ ``local-addr`` has no subnet mask since the local side in PtP addressing is
+ always a single (/32) address. ``peer-addr/prefix`` can be an arbitrary subnet
behind the other end of the link (or even on the link in Point-to-Multipoint
setups), though generally /32s are used.
@@ -157,7 +157,7 @@ Standard Commands
.. clicmd:: multicast
- Enable or disables multicast flag for the interface.
+ Enable or disable multicast flag for the interface.
.. clicmd:: bandwidth (1-10000000)
@@ -171,7 +171,7 @@ Standard Commands
.. clicmd:: link-detect
- Enable/disable link-detect on platforms which support this. Currently only
+ Enable or disable link-detect on platforms which support this. Currently only
Linux, and only where network interface drivers support reporting
link-state via the ``IFF_RUNNING`` flag.
@@ -430,7 +430,7 @@ commands in relationship to VRF. Here is an extract of some of those commands:
.. clicmd:: show ip route vrf VRF tables
- This command will dump the routing tables within the vrf scope. If `vrf all`
+ This command will dump the routing tables within the vrf scope. If ``vrf all``
is executed, all routing tables will be dumped.
.. clicmd:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix]
@@ -444,7 +444,7 @@ By using the :option:`-n` option, the *Linux network namespace* will be mapped
over the *Zebra* VRF. One nice feature that is possible by handling *Linux
network namespace* is the ability to name default VRF. At startup, *Zebra*
discovers the available *Linux network namespace* by parsing folder
-`/var/run/netns`. Each file stands for a *Linux network namespace*, but not all
+``/var/run/netns``. Each file stands for a *Linux network namespace*, but not all
*Linux network namespaces* are available under that folder. This is the case for
default VRF. It is possible to name the default VRF, by creating a file, by
executing following commands.
@@ -455,19 +455,19 @@ executing following commands.
mount --bind /proc/self/ns/net /var/run/netns/vrf0
Above command illustrates what happens when the default VRF is visible under
-`var/run/netns/`. Here, the default VRF file is `vrf0`.
+``/var/run/netns``. Here, the default VRF file is ``vrf0``.
At startup, FRR detects the presence of that file. It detects that the file
statistics information matches the same file statistics information as
-`/proc/self/ns/net` ( through stat() function). As statistics information
-matches, then `vrf0` stands for the new default namespace name.
-Consequently, the VRF naming `Default` will be overridden by the new discovered
-namespace name `vrf0`.
+``/proc/self/ns/net`` ( through stat() function). As statistics information
+matches, then ``vrf0`` stands for the new default namespace name.
+Consequently, the VRF naming ``Default`` will be overridden by the new discovered
+namespace name ``vrf0``.
For those who don't use VRF backend with *Linux network namespace*, it is
possible to statically configure and recompile FRR. It is possible to choose an
alternate name for default VRF. Then, the default VRF naming will automatically
be updated with the new name. To illustrate, if you want to recompile with
-`global` value, use the following command:
+``global`` value, use the following command:
.. code-block:: shell
@@ -499,7 +499,7 @@ options on compilation if the end operator desires to do so. Individual
protocols each have their own way of dictating ECMP policy and their
respective documentation should be read.
-ECMP can be inspected in zebra by doing a `show ip route X` command.
+ECMP can be inspected in zebra by doing a ``show ip route X`` command.
.. code-block:: shell
@@ -528,11 +528,11 @@ ECMP can be inspected in zebra by doing a `show ip route X` command.
* via 192.168.161.15, enp39s0, weight 1, 00:00:02
* via 192.168.161.16, enp39s0, weight 1, 00:00:02
-In this example we have 16 way ecmp for the 4.4.4.4/32 route. The `*` character
+In this example we have 16 way ecmp for the 4.4.4.4/32 route. The ``*`` character
tells us that the route is installed in the Data Plane, or FIB.
If you are using the Linux kernel as a Data Plane, this can be inspected
-via a `ip route show X` command:
+via a ``ip route show X`` command:
.. code-block:: shell
@@ -557,7 +557,7 @@ via a `ip route show X` command:
Once installed into the FIB, FRR currently has little control over what
nexthops are choosen to forward packets on. Currently the Linux kernel
-has a `fib_multipath_hash_policy` sysctl which dictates how the hashing
+has a ``fib_multipath_hash_policy`` sysctl which dictates how the hashing
algorithm is used to forward packets.
.. _zebra-mpls:
@@ -811,7 +811,7 @@ unicast topology!
with the longer prefix length is used; if they're equal, the
Multicast RIB takes precedence.
- The `mrib-then-urib` setting is the default behavior if nothing is
+ The ``mrib-then-urib`` setting is the default behavior if nothing is
configured. If this is the desired behavior, it should be explicitly
configured to make the configuration immune against possible changes in
what the default behavior is.
@@ -904,8 +904,8 @@ that sets the preferred source address, and applies the route-map to all
ip prefix-list ANY permit 0.0.0.0/0 le 32
route-map RM1 permit 10
- match ip address prefix-list ANY
- set src 10.0.0.1
+ match ip address prefix-list ANY
+ set src 10.0.0.1
ip protocol rip route-map RM1
@@ -915,8 +915,8 @@ IPv6 example for OSPFv3.
ipv6 prefix-list ANY seq 10 permit any
route-map RM6 permit 10
- match ipv6 address prefix-list ANY
- set src 2001:db8:425:1000::3
+ match ipv6 address prefix-list ANY
+ set src 2001:db8:425:1000::3
ipv6 protocol ospf6 route-map RM6
@@ -951,7 +951,7 @@ latter information makes up the Forwarding Information Base
(FIB). Zebra feeds the FIB to the kernel, which allows the IP stack in
the kernel to forward packets according to the routes computed by
FRR. The kernel FIB is updated in an OS-specific way. For example,
-the `Netlink` interface is used on Linux, and route sockets are
+the ``Netlink`` interface is used on Linux, and route sockets are
used on FreeBSD.
The FIB push interface aims to provide a cross-platform mechanism to
@@ -1353,6 +1353,15 @@ Optional sysctl settings
When ndisc_notify is set to 0, no U-NA is sent.
When ndisc_notify is set to 1, a U-NA is sent when the interface comes UP.
+Useful sysctl settings
+----------------------
+
+.. option:: net.ipv6.conf.all.use_oif_addrs_only = 1
+
+ When enabled, the candidate source addresses for destinations routed via this interface are
+ restricted to the set of addresses configured on this interface (RFC 6724 section 4). If
+ an operator has hundreds of IP addresses per interface this solves the latency problem.
+
Debugging
=========
@@ -1422,7 +1431,7 @@ Scripting
.. clicmd:: zebra on-rib-process script SCRIPT
Set a Lua script for :ref:`on-rib-process-dplane-results` hook call.
- SCRIPT is the basename of the script, without `.lua`.
+ SCRIPT is the basename of the script, without ``.lua``.
Data structures
---------------
diff --git a/lib/bfd.c b/lib/bfd.c
index 70cbe0f2a6..9800ed4924 100644
--- a/lib/bfd.c
+++ b/lib/bfd.c
@@ -552,7 +552,8 @@ static bool bfd_sess_address_changed(const struct bfd_session_params *bsp,
}
void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
- struct in_addr *src, struct in_addr *dst)
+ const struct in_addr *src,
+ const struct in_addr *dst)
{
if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src,
(struct in6_addr *)dst))
@@ -576,10 +577,10 @@ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
}
void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
- struct in6_addr *src, struct in6_addr *dst)
+ const struct in6_addr *src,
+ const struct in6_addr *dst)
{
- if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src,
- (struct in6_addr *)dst))
+ if (!bfd_sess_address_changed(bsp, AF_INET6, src, dst))
return;
/* If already installed, remove the old setting. */
diff --git a/lib/bfd.h b/lib/bfd.h
index 6c0d1c177e..cc9659ff79 100644
--- a/lib/bfd.h
+++ b/lib/bfd.h
@@ -124,7 +124,8 @@ void bfd_sess_free(struct bfd_session_params **bsp);
* \param dst remote address (mandatory).
*/
void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
- struct in_addr *src, struct in_addr *dst);
+ const struct in_addr *src,
+ const struct in_addr *dst);
/**
* Set the local and peer address of the BFD session.
@@ -138,7 +139,8 @@ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp,
* \param dst remote address (mandatory).
*/
void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp,
- struct in6_addr *src, struct in6_addr *dst);
+ const struct in6_addr *src,
+ const struct in6_addr *dst);
/**
* Configure the BFD session interface.
diff --git a/lib/if.c b/lib/if.c
index 4ccb36d091..71d2f5d9cc 100644
--- a/lib/if.c
+++ b/lib/if.c
@@ -48,6 +48,7 @@ DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters");
static void if_set_name(struct interface *ifp, const char *name);
static struct interface *if_lookup_by_ifindex(ifindex_t ifindex,
vrf_id_t vrf_id);
+static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex);
static int if_cmp_func(const struct interface *, const struct interface *);
static int if_cmp_index_func(const struct interface *ifp1,
const struct interface *ifp2);
@@ -440,7 +441,7 @@ static struct interface *if_lookup_by_name_all_vrf(const char *name)
return NULL;
}
-struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
+static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex)
{
struct vrf *vrf;
struct interface *ifp;
diff --git a/lib/if.h b/lib/if.h
index 1d32c2b088..506c14ff59 100644
--- a/lib/if.h
+++ b/lib/if.h
@@ -515,7 +515,6 @@ extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id);
extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id);
extern struct interface *if_vrf_lookup_by_index_next(ifindex_t ifindex,
vrf_id_t vrf_id);
-extern struct interface *if_lookup_by_index_all_vrf(ifindex_t);
extern struct interface *if_lookup_exact_address(const void *matchaddr,
int family, vrf_id_t vrf_id);
extern struct connected *if_lookup_address(const void *matchaddr, int family,
diff --git a/lib/vrf.c b/lib/vrf.c
index 847899f0ba..aaedb63800 100644
--- a/lib/vrf.c
+++ b/lib/vrf.c
@@ -256,10 +256,8 @@ void vrf_delete(struct vrf *vrf)
* the ID mapping. Interfaces assigned to this VRF should've been
* removed already as part of the VRF going down.
*/
- if (vrf_is_user_cfged(vrf)) {
- vrf->ns_ctxt = NULL;
+ if (vrf_is_user_cfged(vrf))
return;
- }
/* Do not delete the VRF if it has interfaces configured in it. */
if (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name))
@@ -541,10 +539,13 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *),
static void vrf_terminate_single(struct vrf *vrf)
{
+ int enabled = vrf_is_enabled(vrf);
+
/* Clear configured flag and invoke delete. */
UNSET_FLAG(vrf->status, VRF_CONFIGURED);
if_terminate(vrf);
- vrf_delete(vrf);
+ if (enabled)
+ vrf_delete(vrf);
}
/* Terminate VRF module. */
diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c
index 64992bbcee..4205be38ba 100644
--- a/ospf6d/ospf6_interface.c
+++ b/ospf6d/ospf6_interface.c
@@ -675,7 +675,8 @@ uint8_t dr_election(struct ospf6_interface *oi)
if (on->state < OSPF6_NEIGHBOR_TWOWAY)
continue;
/* Schedule AdjOK. */
- thread_add_event(master, adj_ok, on, 0, NULL);
+ thread_add_event(master, adj_ok, on, 0,
+ &on->thread_adj_ok);
}
}
diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c
index a81c3e728f..49a379aa17 100644
--- a/ospf6d/ospf6_message.c
+++ b/ospf6d/ospf6_message.c
@@ -772,7 +772,8 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh,
/* More bit check */
if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT)
&& !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT))
- thread_add_event(master, exchange_done, on, 0, NULL);
+ thread_add_event(master, exchange_done, on, 0,
+ &on->thread_exchange_done);
else {
thread_add_event(master, ospf6_dbdesc_send_newone, on, 0,
&on->thread_send_dbdesc);
@@ -2261,7 +2262,8 @@ int ospf6_dbdesc_send_newone(struct thread *thread)
if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */
!CHECK_FLAG(on->dbdesc_last.bits, OSPF6_DBDESC_MBIT)
&& !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT))
- thread_add_event(master, exchange_done, on, 0, NULL);
+ thread_add_event(master, exchange_done, on, 0,
+ &on->thread_exchange_done);
thread_execute(master, ospf6_dbdesc_send, on, 0);
return 0;
diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c
index 36948dc0a7..3d0dde8c65 100644
--- a/ospf6d/ospf6_neighbor.c
+++ b/ospf6d/ospf6_neighbor.c
@@ -168,6 +168,9 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on)
THREAD_OFF(on->thread_send_lsreq);
THREAD_OFF(on->thread_send_lsupdate);
THREAD_OFF(on->thread_send_lsack);
+ THREAD_OFF(on->thread_exchange_done);
+ THREAD_OFF(on->thread_adj_ok);
+
THREAD_OFF(on->gr_helper_info.t_grace_timer);
bfd_sess_free(&on->bfd_session);
@@ -603,6 +606,8 @@ int oneway_received(struct thread *thread)
THREAD_OFF(on->thread_send_lsreq);
THREAD_OFF(on->thread_send_lsupdate);
THREAD_OFF(on->thread_send_lsack);
+ THREAD_OFF(on->thread_exchange_done);
+ THREAD_OFF(on->thread_adj_ok);
return 0;
}
diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h
index f7735b87b9..de59a1ccf5 100644
--- a/ospf6d/ospf6_neighbor.h
+++ b/ospf6d/ospf6_neighbor.h
@@ -136,6 +136,8 @@ struct ospf6_neighbor {
struct thread *thread_send_lsreq;
struct thread *thread_send_lsupdate;
struct thread *thread_send_lsack;
+ struct thread *thread_exchange_done;
+ struct thread *thread_adj_ok;
/* BFD information */
struct bfd_session_params *bfd_session;
diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c
index d0c8e3c970..35b567c768 100644
--- a/ospf6d/ospf6_route.c
+++ b/ospf6d/ospf6_route.c
@@ -1114,6 +1114,7 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route,
json_object *json_route = NULL;
json_object *json_array_next_hops = NULL;
json_object *json_next_hop;
+ vrf_id_t vrf_id = route->ospf6->vrf_id;
monotime(&now);
timersub(&now, &route->changed, &res);
@@ -1147,16 +1148,15 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route,
else
i = 0;
for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
- struct interface *ifp;
/* nexthop */
inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop));
- ifp = if_lookup_by_index_all_vrf(nh->ifindex);
if (use_json) {
json_next_hop = json_object_new_object();
json_object_string_add(json_next_hop, "nextHop",
nexthop);
- json_object_string_add(json_next_hop, "interfaceName",
- ifp->name);
+ json_object_string_add(
+ json_next_hop, "interfaceName",
+ ifindex2ifname(nh->ifindex, vrf_id));
json_object_array_add(json_array_next_hops,
json_next_hop);
} else {
@@ -1168,12 +1168,14 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route,
OSPF6_PATH_TYPE_SUBSTR(
route->path.type),
destination, nexthop, IFNAMSIZ,
- ifp->name, duration);
+ ifindex2ifname(nh->ifindex, vrf_id),
+ duration);
i++;
} else
vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n",
' ', "", "", "", nexthop, IFNAMSIZ,
- ifp->name, "");
+ ifindex2ifname(nh->ifindex, vrf_id),
+ "");
}
}
if (use_json) {
@@ -1197,6 +1199,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
json_object *json_route = NULL;
json_object *json_array_next_hops = NULL;
json_object *json_next_hop;
+ vrf_id_t vrf_id = route->ospf6->vrf_id;
monotime(&now);
@@ -1347,8 +1350,6 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
vty_out(vty, "Nexthop:\n");
for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) {
- struct interface *ifp;
- ifp = if_lookup_by_index_all_vrf(nh->ifindex);
/* nexthop */
if (use_json) {
inet_ntop(AF_INET6, &nh->address, nexthop,
@@ -1356,13 +1357,14 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route,
json_next_hop = json_object_new_object();
json_object_string_add(json_next_hop, "nextHop",
nexthop);
- json_object_string_add(json_next_hop, "interfaceName",
- ifp->name);
+ json_object_string_add(
+ json_next_hop, "interfaceName",
+ ifindex2ifname(nh->ifindex, vrf_id));
json_object_array_add(json_array_next_hops,
json_next_hop);
} else
vty_out(vty, " %pI6 %.*s\n", &nh->address, IFNAMSIZ,
- ifp->name);
+ ifindex2ifname(nh->ifindex, vrf_id));
}
if (use_json) {
json_object_object_add(json_route, "nextHops",
diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c
index b1aeefcd43..fab5b7d3cc 100644
--- a/ospfd/ospf_dump.c
+++ b/ospfd/ospf_dump.c
@@ -127,7 +127,9 @@ const char *ospf_area_desc_string(struct ospf_area *area)
return buf;
}
-#define OSPF_IF_STRING_MAXLEN 40
+#define OSPF_IF_STRING_MAXLEN 40
+
+/* Display both nbr and ism state of the ospf neighbor.*/
const char *ospf_if_name_string(struct ospf_interface *oi)
{
static char buf[OSPF_IF_STRING_MAXLEN] = "";
@@ -146,6 +148,13 @@ const char *ospf_if_name_string(struct ospf_interface *oi)
return buf;
}
+/* Display only the nbr state.*/
+void ospf_nbr_state_message(struct ospf_neighbor *nbr, char *buf, size_t size)
+{
+ snprintf(buf, size, "%s",
+ lookup_msg(ospf_nsm_state_msg, nbr->state, NULL));
+}
+
int ospf_nbr_ism_state(struct ospf_neighbor *nbr)
{
int state;
@@ -161,9 +170,23 @@ int ospf_nbr_ism_state(struct ospf_neighbor *nbr)
return state;
}
-void ospf_nbr_state_message(struct ospf_neighbor *nbr, char *buf, size_t size)
+void ospf_nbr_ism_state_message(struct ospf_neighbor *nbr, char *buf,
+ size_t size)
{
- int state = ospf_nbr_ism_state(nbr);
+ int state;
+ struct ospf_interface *oi = nbr->oi;
+
+ if (!oi)
+ return;
+
+ /* network type is point-to-point */
+ if (oi->type == OSPF_IFTYPE_POINTOPOINT) {
+ snprintf(buf, size, "%s/-",
+ lookup_msg(ospf_nsm_state_msg, nbr->state, NULL));
+ return;
+ }
+
+ state = ospf_nbr_ism_state(nbr);
snprintf(buf, size, "%s/%s",
lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h
index 031ec2f428..58227d038e 100644
--- a/ospfd/ospf_dump.h
+++ b/ospfd/ospf_dump.h
@@ -151,7 +151,10 @@ extern const char *ospf_area_name_string(struct ospf_area *);
extern const char *ospf_area_desc_string(struct ospf_area *);
extern const char *ospf_if_name_string(struct ospf_interface *);
extern int ospf_nbr_ism_state(struct ospf_neighbor *nbr);
-extern void ospf_nbr_state_message(struct ospf_neighbor *, char *, size_t);
+extern void ospf_nbr_state_message(struct ospf_neighbor *nbr, char *buf,
+ size_t size);
+extern void ospf_nbr_ism_state_message(struct ospf_neighbor *nbr, char *buf,
+ size_t size);
extern const char *ospf_timer_dump(struct thread *, char *, size_t);
extern const char *ospf_timeval_dump(struct timeval *, char *, size_t);
extern void ospf_packet_dump(struct stream *);
diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c
index 432f95f9dd..a1ea4e45d7 100644
--- a/ospfd/ospf_snmp.c
+++ b/ospfd/ospf_snmp.c
@@ -2432,7 +2432,7 @@ static void ospfTrapNbrStateChange(struct ospf_neighbor *on)
oid index[sizeof(oid) * (IN_ADDR_SIZE + 1)];
char msgbuf[16];
- ospf_nbr_state_message(on, msgbuf, sizeof(msgbuf));
+ ospf_nbr_ism_state_message(on, msgbuf, sizeof(msgbuf));
if (IS_DEBUG_OSPF_EVENT)
zlog_info("%s: trap sent: %pI4 now %s", __func__,
&on->address.u.prefix4, msgbuf);
diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c
index 2239f31609..bbb458d8ef 100644
--- a/ospfd/ospf_vty.c
+++ b/ospfd/ospf_vty.c
@@ -4335,9 +4335,9 @@ DEFUN (show_ip_ospf_interface_traffic,
static void show_ip_ospf_neighbour_header(struct vty *vty)
{
- vty_out(vty, "\n%-15s %3s %-15s %9s %-15s %-32s %5s %5s %5s\n",
- "Neighbor ID", "Pri", "State", "Dead Time", "Address",
- "Interface", "RXmtL", "RqstL", "DBsmL");
+ vty_out(vty, "\n%-15s %-3s %-15s %-15s %-9s %-15s %-32s %5s %5s %5s\n",
+ "Neighbor ID", "Pri", "State", "Up Time", "Dead Time",
+ "Address", "Interface", "RXmtL", "RqstL", "DBsmL");
}
static void show_ip_ospf_neighbor_sub(struct vty *vty,
@@ -4350,6 +4350,9 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty,
char buf[PREFIX_STRLEN];
char timebuf[OSPF_TIME_DUMP_SIZE];
json_object *json_neighbor = NULL, *json_neigh_array = NULL;
+ struct timeval res;
+ long time_val = 0;
+ char uptime[OSPF_TIME_DUMP_SIZE];
for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
if ((nbr = rn->info)) {
@@ -4359,6 +4362,13 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty,
/* Down state is not shown. */
if (nbr->state == NSM_Down)
continue;
+
+ if (nbr->ts_last_progress.tv_sec
+ || nbr->ts_last_progress.tv_usec)
+ time_val = monotime_since(
+ &nbr->ts_last_progress, &res)
+ / 1000LL;
+
if (use_json) {
char neigh_str[INET_ADDRSTRLEN];
@@ -4390,7 +4400,7 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty,
json_neighbor = json_object_new_object();
- ospf_nbr_state_message(nbr, msgbuf, 16);
+ ospf_nbr_ism_state_message(nbr, msgbuf, 16);
json_object_int_add(json_neighbor, "priority",
nbr->priority);
@@ -4416,8 +4426,22 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty,
NULL)
/ 1000LL;
json_object_int_add(json_neighbor,
+ "upTimeInMsec",
+ time_val);
+ json_object_int_add(json_neighbor,
"deadTimeMsecs",
time_store);
+ json_object_string_add(
+ json_neighbor, "upTime",
+ ospf_timeval_dump(
+ &res, uptime,
+ sizeof(uptime)));
+ json_object_string_add(
+ json_neighbor, "deadTime",
+ ospf_timer_dump(
+ nbr->t_inactivity,
+ timebuf,
+ sizeof(timebuf)));
} else {
json_object_string_add(json_neighbor,
"deadTimeMsecs",
@@ -4443,7 +4467,7 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty,
json_object_array_add(json_neigh_array,
json_neighbor);
} else {
- ospf_nbr_state_message(nbr, msgbuf, 16);
+ ospf_nbr_ism_state_message(nbr, msgbuf, 16);
if (nbr->state == NSM_Attempt
&& nbr->router_id.s_addr == INADDR_ANY)
@@ -4451,8 +4475,12 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty,
nbr->priority, msgbuf);
else
vty_out(vty, "%-15pI4 %3d %-15s ",
- &nbr->router_id,
- nbr->priority, msgbuf);
+ &nbr->router_id, nbr->priority,
+ msgbuf);
+
+ vty_out(vty, "%-15s ",
+ ospf_timeval_dump(&res, uptime,
+ sizeof(uptime)));
vty_out(vty, "%9s ",
ospf_timer_dump(nbr->t_inactivity,
diff --git a/pceplib/test/pcep_msg_tools_test.c b/pceplib/test/pcep_msg_tools_test.c
index e25ddb2179..05f8bfb547 100644
--- a/pceplib/test/pcep_msg_tools_test.c
+++ b/pceplib/test/pcep_msg_tools_test.c
@@ -35,6 +35,8 @@
#include <CUnit/CUnit.h>
+#include <zebra.h>
+
#include "pcep_msg_encoding.h"
#include "pcep_msg_messages.h"
#include "pcep_msg_tools.h"
@@ -143,7 +145,7 @@ const char *pcep_initiate_cisco_pcc_hexbyte_strs[] = {
struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class,
uint8_t obj2_class, uint8_t obj3_class,
uint8_t obj4_class);
-int convert_hexstrs_to_binary(const char *hexbyte_strs[],
+int convert_hexstrs_to_binary(char *filename, const char *hexbyte_strs[],
uint16_t hexbyte_strs_length);
int pcep_tools_test_suite_setup(void)
@@ -167,18 +169,24 @@ void pcep_tools_test_teardown(void)
{
}
+static const char BASE_TMPFILE[] = "/tmp/pceplib_XXXXXX";
+static int BASE_TMPFILE_SIZE = sizeof(BASE_TMPFILE);
+
/* Reads an array of hexbyte strs, and writes them to a temporary file.
* The caller should close the returned file. */
-int convert_hexstrs_to_binary(const char *hexbyte_strs[],
+int convert_hexstrs_to_binary(char *filename,
+ const char *hexbyte_strs[],
uint16_t hexbyte_strs_length)
{
mode_t oldumask;
oldumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH);
/* Set umask before anything for security */
umask(0027);
- char tmpfile[] = "/tmp/pceplib_XXXXXX";
- int fd = mkstemp(tmpfile);
+
+ strlcpy(filename, BASE_TMPFILE, BASE_TMPFILE_SIZE);
+ int fd = mkstemp(filename);
umask(oldumask);
+
if (fd == -1)
return -1;
@@ -206,7 +214,10 @@ static bool pcep_obj_has_tlv(struct pcep_object_header *obj_hdr)
void test_pcep_msg_read_pcep_initiate()
{
- int fd = convert_hexstrs_to_binary(pcep_initiate_hexbyte_strs,
+ char filename[BASE_TMPFILE_SIZE];
+
+ int fd = convert_hexstrs_to_binary(filename,
+ pcep_initiate_hexbyte_strs,
pcep_initiate_hexbyte_strs_length);
if(fd == -1){
CU_ASSERT_TRUE(fd>=0);
@@ -302,12 +313,16 @@ void test_pcep_msg_read_pcep_initiate()
pcep_msg_free_message_list(msg_list);
close(fd);
+ unlink(filename);
}
void test_pcep_msg_read_pcep_initiate2()
{
- int fd = convert_hexstrs_to_binary(pcep_initiate2_hexbyte_strs,
+ char filename[BASE_TMPFILE_SIZE];
+
+ int fd = convert_hexstrs_to_binary(filename,
+ pcep_initiate2_hexbyte_strs,
pcep_initiate2_hexbyte_strs_length);
if(fd == -1){
CU_ASSERT_TRUE(fd>=0);
@@ -392,11 +407,15 @@ void test_pcep_msg_read_pcep_initiate2()
pcep_msg_free_message_list(msg_list);
close(fd);
+ unlink(filename);
}
void test_pcep_msg_read_pcep_open()
{
- int fd = convert_hexstrs_to_binary(pcep_open_odl_hexbyte_strs,
+ char filename[BASE_TMPFILE_SIZE];
+
+ int fd = convert_hexstrs_to_binary(filename,
+ pcep_open_odl_hexbyte_strs,
pcep_open_hexbyte_strs_length);
if(fd == -1){
CU_ASSERT_TRUE(fd>=0);
@@ -437,11 +456,15 @@ void test_pcep_msg_read_pcep_open()
pcep_msg_free_message_list(msg_list);
close(fd);
+ unlink(filename);
}
void test_pcep_msg_read_pcep_update()
{
- int fd = convert_hexstrs_to_binary(pcep_update_hexbyte_strs,
+ char filename[BASE_TMPFILE_SIZE];
+
+ int fd = convert_hexstrs_to_binary(filename,
+ pcep_update_hexbyte_strs,
pcep_update_hexbyte_strs_length);
if(fd == -1){
CU_ASSERT_TRUE(fd>=0);
@@ -520,12 +543,15 @@ void test_pcep_msg_read_pcep_update()
pcep_msg_free_message_list(msg_list);
close(fd);
+ unlink(filename);
}
void test_pcep_msg_read_pcep_open_initiate()
{
+ char filename[BASE_TMPFILE_SIZE];
+
int fd = convert_hexstrs_to_binary(
- pcep_open_initiate_odl_hexbyte_strs,
+ filename, pcep_open_initiate_odl_hexbyte_strs,
pcep_open_initiate_hexbyte_strs_length);
if(fd == -1){
CU_ASSERT_TRUE(fd>=0);
@@ -550,12 +576,15 @@ void test_pcep_msg_read_pcep_open_initiate()
pcep_msg_free_message_list(msg_list);
close(fd);
+ unlink(filename);
}
void test_pcep_msg_read_pcep_open_cisco_pce()
{
+ char filename[BASE_TMPFILE_SIZE];
+
int fd = convert_hexstrs_to_binary(
- pcep_open_cisco_pce_hexbyte_strs,
+ filename, pcep_open_cisco_pce_hexbyte_strs,
pcep_open_cisco_pce_hexbyte_strs_length);
if(fd == -1){
CU_ASSERT_TRUE(fd>=0);
@@ -614,12 +643,15 @@ void test_pcep_msg_read_pcep_open_cisco_pce()
pcep_msg_free_message_list(msg_list);
close(fd);
+ unlink(filename);
}
void test_pcep_msg_read_pcep_update_cisco_pce()
{
+ char filename[BASE_TMPFILE_SIZE];
+
int fd = convert_hexstrs_to_binary(
- pcep_update_cisco_pce_hexbyte_strs,
+ filename, pcep_update_cisco_pce_hexbyte_strs,
pcep_update_cisco_pce_hexbyte_strs_length);
if(fd == -1){
CU_ASSERT_TRUE(fd>=0);
@@ -759,12 +791,15 @@ void test_pcep_msg_read_pcep_update_cisco_pce()
pcep_msg_free_message_list(msg_list);
close(fd);
+ unlink(filename);
}
void test_pcep_msg_read_pcep_report_cisco_pcc()
{
+ char filename[BASE_TMPFILE_SIZE];
+
int fd = convert_hexstrs_to_binary(
- pcep_report_cisco_pcc_hexbyte_strs,
+ filename, pcep_report_cisco_pcc_hexbyte_strs,
pcep_report_cisco_pcc_hexbyte_strs_length);
if(fd == -1){
CU_ASSERT_TRUE(fd>=0);
@@ -921,12 +956,15 @@ void test_pcep_msg_read_pcep_report_cisco_pcc()
pcep_msg_free_message_list(msg_list);
close(fd);
+ unlink(filename);
}
void test_pcep_msg_read_pcep_initiate_cisco_pcc()
{
+ char filename[BASE_TMPFILE_SIZE];
+
int fd = convert_hexstrs_to_binary(
- pcep_initiate_cisco_pcc_hexbyte_strs,
+ filename, pcep_initiate_cisco_pcc_hexbyte_strs,
pcep_initiate_cisco_pcc_hexbyte_strs_length);
if(fd == -1){
CU_ASSERT_TRUE(fd>=0);
@@ -1030,6 +1068,7 @@ void test_pcep_msg_read_pcep_initiate_cisco_pcc()
pcep_msg_free_message_list(msg_list);
close(fd);
+ unlink(filename);
}
void test_validate_message_header()
diff --git a/pceplib/test/pcep_session_logic_loop_test.c b/pceplib/test/pcep_session_logic_loop_test.c
index 4dfed7321f..96beceac59 100644
--- a/pceplib/test/pcep_session_logic_loop_test.c
+++ b/pceplib/test/pcep_session_logic_loop_test.c
@@ -191,6 +191,7 @@ void test_session_logic_msg_ready_handler()
destroy_pcep_versioning(versioning);
pceplib_free(PCEPLIB_INFRA, socket_event);
close(fd);
+ unlink(tmpfile);
}
diff --git a/pimd/pim_join.c b/pimd/pim_join.c
index c7a80ca8e0..4606aec6a1 100644
--- a/pimd/pim_join.c
+++ b/pimd/pim_join.c
@@ -1,3 +1,5 @@
+
+
/*
* PIM for Quagga
* Copyright (C) 2008 Everton da Silva Marques
@@ -39,6 +41,7 @@
#include "pim_rp.h"
#include "pim_jp_agg.h"
#include "pim_util.h"
+#include "pim_ssm.h"
static void on_trace(const char *label, struct interface *ifp,
struct in_addr src)
@@ -105,6 +108,13 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh,
return;
}
+ if (pim_is_grp_ssm(pim_ifp->pim, sg->grp)) {
+ zlog_warn(
+ "%s: Specified Group(%pI4) in join is now in SSM, not allowed to create PIM state",
+ __func__, &sg->grp);
+ return;
+ }
+
sg->src.s_addr = INADDR_ANY;
}
diff --git a/pimd/pim_register.c b/pimd/pim_register.c
index 9d5b864ab0..e2538da36f 100644
--- a/pimd/pim_register.c
+++ b/pimd/pim_register.c
@@ -381,6 +381,16 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr,
pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp);
}
+ if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) {
+ if (sg.src.s_addr == INADDR_ANY) {
+ zlog_warn(
+ "%s: Received Register message for Group(%pI4) is now in SSM, dropping the packet",
+ __func__, &sg.grp);
+ /* Drop Packet Silently */
+ return 0;
+ }
+ }
+
if (i_am_rp
&& (dest_addr.s_addr
== ((RP(pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) {
diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c
index 1da33af006..0ef0ad533e 100644
--- a/pimd/pim_zebra.c
+++ b/pimd/pim_zebra.c
@@ -548,6 +548,7 @@ void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
struct pim_interface *pim_ifp = ifp->info;
struct listnode *grpnode;
struct igmp_group *grp;
+ struct pim_ifchannel *ch, *ch_temp;
if (!pim_ifp)
continue;
@@ -562,9 +563,17 @@ void igmp_source_forward_reevaluate_all(struct pim_instance *pim)
for (ALL_LIST_ELEMENTS_RO(grp->group_source_list,
srcnode, src)) {
igmp_source_forward_reevaluate_one(pim, src);
- } /* scan group sources */
- } /* scan igmp groups */
- } /* scan interfaces */
+ } /* scan group sources */
+ } /* scan igmp groups */
+
+ RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb,
+ ch_temp) {
+ if (pim_is_grp_ssm(pim, ch->sg.grp)) {
+ if (ch->sg.src.s_addr == INADDR_ANY)
+ pim_ifchannel_delete(ch);
+ }
+ }
+ } /* scan interfaces */
}
void igmp_source_forward_start(struct pim_instance *pim,
diff --git a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
index 4769a19d63..ca8c005f9e 100644
--- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
+++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py
@@ -1503,6 +1503,14 @@ def test_nexthop_group_replace():
'vtysh -c "c t" -c "nexthop-group replace" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"'
)
+ # At the moment there is absolutely no real easy way to query sharpd
+ # for the nexthop group actually installed. If it is not installed
+ # sharpd will just transmit the nexthops down instead of the nexthop
+ # group id. Leading to a situation where the replace is not actually
+ # being tested. So let's just wait some time here because this
+ # is hard and this test fails all the time
+ sleep(5)
+
# Create with sharpd using nexthop-group
net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"')
diff --git a/tests/topotests/ldp_vpls_topo1/r1/show_ip_route_after_link_down.ref b/tests/topotests/ldp_vpls_topo1/r1/show_ip_route_after_link_down.ref
new file mode 100644
index 0000000000..84113a0383
--- /dev/null
+++ b/tests/topotests/ldp_vpls_topo1/r1/show_ip_route_after_link_down.ref
@@ -0,0 +1,20 @@
+{
+ "2.2.2.2/32":[
+ {
+ "prefix":"2.2.2.2/32",
+ "protocol":"ospf",
+ "selected":true,
+ "distance":110,
+ "metric":20,
+ "nexthops":[
+ {
+ "fib":true,
+ "ip":"10.0.2.3",
+ "afi":"ipv4",
+ "interfaceName":"r1-eth2",
+ "active":true
+ }
+ ]
+ }
+ ]
+}
diff --git a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py
index 86128a629d..8a41ea510e 100644
--- a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py
+++ b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py
@@ -272,9 +272,15 @@ def test_ldp_pseudowires_after_link_down():
# Shut down r1-r2 link */
tgen = get_topogen()
- tgen.gears["r1"].peer_link_enable("r1-eth1", False)
- topotest.sleep(5, "Waiting for the network to reconverge")
-
+ rname = "r1"
+ tgen.gears[rname].peer_link_enable("r1-eth1", False)
+ router_compare_json_output(
+ rname,
+ "show ip route json",
+ "show_ip_route_after_link_down.ref",
+ count=160,
+ wait=1,
+ )
# check if the pseudowire is still up (using an alternate path
# for nexthop resolution). Give some extra wait time.
for rname in ["r1", "r2", "r3"]:
diff --git a/tests/topotests/ospf_topo1/test_ospf_topo1.py b/tests/topotests/ospf_topo1/test_ospf_topo1.py
index 710895cc6b..e2a6ff64a4 100644
--- a/tests/topotests/ospf_topo1/test_ospf_topo1.py
+++ b/tests/topotests/ospf_topo1/test_ospf_topo1.py
@@ -30,6 +30,7 @@ import os
import re
import sys
from functools import partial
+from time import sleep
import pytest
# Save the Current Working Directory to find configuration files.
@@ -475,7 +476,18 @@ def test_ospf_link_down_kernel_route():
assertmsg = 'OSPF IPv4 route mismatch in router "{}" after link down'.format(
router.name
)
- assert topotest.json_cmp(routes, expected) is None, assertmsg
+ count = 0
+ not_found = True
+ while not_found and count < 10:
+ not_found = topotest.json_cmp(routes, expected)
+ if not_found:
+ sleep(1)
+ routes = topotest.ip4_route(router)
+ count += 1
+ else:
+ not_found = False
+ break
+ assert not_found is False, assertmsg
def test_ospf6_link_down():
@@ -547,7 +559,19 @@ def test_ospf6_link_down_kernel_route():
assertmsg = 'OSPF IPv6 route mismatch in router "{}" after link down'.format(
router.name
)
- assert topotest.json_cmp(routes, expected) is None, assertmsg
+ count = 0
+ not_found = True
+ while not_found and count < 10:
+ not_found = topotest.json_cmp(routes, expected)
+ if not_found:
+ sleep(1)
+ routes = topotest.ip6_route(router)
+ count += 1
+ else:
+ not_found = False
+ break
+
+ assert not_found is False, assertmsg
def test_memory_leak():
diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py
index 03b4368e42..6cea521aa9 100644
--- a/tests/topotests/pim_basic/test_pim.py
+++ b/tests/topotests/pim_basic/test_pim.py
@@ -172,7 +172,11 @@ def test_pim_send_mcast_stream():
}
}
- assert topotest.json_cmp(out, expected) is None, "failed to converge pim"
+ test_func = partial(
+ topotest.router_json_cmp, r1, "show ip pim upstream json", expected
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assert result is None, "failed to converge pim"
# tgen.mininet_cli()
diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c
index c1bb19d4e5..6fc01925eb 100644
--- a/zebra/zebra_evpn_mac.c
+++ b/zebra/zebra_evpn_mac.c
@@ -106,19 +106,6 @@ static void zebra_evpn_mac_ifp_new(struct zebra_if *zif)
listset_app_node_mem(zif->mac_list);
}
-/* Free up the mac_list if any as a part of the interface del/cleanup */
-void zebra_evpn_mac_ifp_del(struct interface *ifp)
-{
- struct zebra_if *zif = ifp->info;
-
- if (zif->mac_list) {
- if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
- zlog_debug("MAC list deleted for ifp %s (%u)",
- zif->ifp->name, zif->ifp->ifindex);
- list_delete(&zif->mac_list);
- }
-}
-
/* Unlink local mac from a destination access port */
static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac)
{
@@ -139,6 +126,25 @@ static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac)
zmac->ifp = NULL;
}
+/* Free up the mac_list if any as a part of the interface del/cleanup */
+void zebra_evpn_mac_ifp_del(struct interface *ifp)
+{
+ struct zebra_if *zif = ifp->info;
+ struct listnode *node;
+ struct zebra_mac *zmac;
+
+ if (zif->mac_list) {
+ if (IS_ZEBRA_DEBUG_EVPN_MH_MAC)
+ zlog_debug("MAC list deleted for ifp %s (%u)",
+ zif->ifp->name, zif->ifp->ifindex);
+
+ for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) {
+ zebra_evpn_mac_ifp_unlink(zmac);
+ }
+ list_delete(&zif->mac_list);
+ }
+}
+
/* Link local mac to destination access port. This is done only if the
* local mac is associated with a zero ESI i.e. single attach or lacp-bypass
* bridge port member
diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c
index 30e74902aa..420bed7064 100644
--- a/zebra/zebra_l2.c
+++ b/zebra/zebra_l2.c
@@ -162,7 +162,7 @@ void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf_id)
struct zebra_if *bond_zif;
struct zebra_l2info_bondslave *bond_slave = &zif->bondslave_info;
- bond_if = if_lookup_by_index_all_vrf(bond_slave->bond_ifindex);
+ bond_if = if_lookup_by_index(bond_slave->bond_ifindex, vrf_id);
if (bond_if == bond_slave->bond_if)
return;
diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c
index 0d260ad639..5b9539904f 100644
--- a/zebra/zebra_netns_notify.c
+++ b/zebra/zebra_netns_notify.c
@@ -165,6 +165,7 @@ static int zebra_ns_delete(char *name)
/* the deletion order is the same
* as the one used when siging signal is received
*/
+ vrf->ns_ctxt = NULL;
vrf_delete(vrf);
if (ns)
ns_delete(ns);
diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c
index c13c867d2a..bb46a1e62e 100644
--- a/zebra/zebra_vxlan.c
+++ b/zebra/zebra_vxlan.c
@@ -4736,13 +4736,11 @@ void zebra_vxlan_macvlan_down(struct interface *ifp)
assert(zif);
link_ifp = zif->link;
if (!link_ifp) {
- if (IS_ZEBRA_DEBUG_VXLAN) {
- struct interface *ifp;
-
- ifp = if_lookup_by_index_all_vrf(zif->link_ifindex);
- zlog_debug("macvlan parent link is not found. Parent index %d ifp %s",
- zif->link_ifindex, ifp ? ifp->name : " ");
- }
+ if (IS_ZEBRA_DEBUG_VXLAN)
+ zlog_debug(
+ "macvlan parent link is not found. Parent index %d ifp %s",
+ zif->link_ifindex,
+ ifindex2ifname(zif->link_ifindex, ifp->vrf_id));
return;
}
link_zif = link_ifp->info;