diff options
| -rw-r--r-- | bfdd/bfd.c | 21 | ||||
| -rw-r--r-- | bfdd/bfd.h | 3 | ||||
| -rw-r--r-- | bfdd/bfd_packet.c | 16 | ||||
| -rw-r--r-- | bgpd/bgp_nht.c | 5 | ||||
| -rw-r--r-- | bgpd/bgp_open.c | 91 | ||||
| -rw-r--r-- | bgpd/bgp_open.h | 5 | ||||
| -rw-r--r-- | bgpd/bgp_vty.c | 132 | ||||
| -rw-r--r-- | bgpd/bgpd.c | 1 | ||||
| -rw-r--r-- | bgpd/bgpd.h | 18 | ||||
| -rw-r--r-- | doc/user/bgp.rst | 12 | ||||
| -rw-r--r-- | doc/user/zebra.rst | 55 | ||||
| -rw-r--r-- | lib/if.c | 3 | ||||
| -rw-r--r-- | lib/if.h | 1 | ||||
| -rw-r--r-- | lib/vrf.c | 9 | ||||
| -rw-r--r-- | ospf6d/ospf6_route.c | 24 | ||||
| -rw-r--r-- | ospfd/ospf_dump.c | 29 | ||||
| -rw-r--r-- | ospfd/ospf_dump.h | 5 | ||||
| -rw-r--r-- | ospfd/ospf_snmp.c | 2 | ||||
| -rw-r--r-- | ospfd/ospf_vty.c | 42 | ||||
| -rw-r--r-- | pimd/pim_join.c | 10 | ||||
| -rw-r--r-- | pimd/pim_register.c | 12 | ||||
| -rw-r--r-- | pimd/pim_zebra.c | 15 | ||||
| -rw-r--r-- | tests/topotests/ldp_vpls_topo1/r1/show_ip_route_after_link_down.ref | 20 | ||||
| -rw-r--r-- | tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py | 12 | ||||
| -rw-r--r-- | tests/topotests/ospf_topo1/test_ospf_topo1.py | 28 | ||||
| -rw-r--r-- | tests/topotests/pim_basic/test_pim.py | 6 | ||||
| -rw-r--r-- | zebra/zebra_evpn_mac.c | 32 | ||||
| -rw-r--r-- | zebra/zebra_l2.c | 2 | ||||
| -rw-r--r-- | zebra/zebra_netns_notify.c | 1 | ||||
| -rw-r--r-- | zebra/zebra_vxlan.c | 12 |
30 files changed, 516 insertions, 108 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_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 c35d35d623..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) { 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..38d215e765 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 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 --------------- @@ -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; @@ -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, @@ -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_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/pimd/pim_join.c b/pimd/pim_join.c index c7a80ca8e0..652b27476d 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -39,6 +39,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) @@ -55,6 +56,7 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, struct prefix_sg *sg, uint8_t source_flags) { struct pim_interface *pim_ifp = NULL; + char buf[PREFIX_STRLEN]; if (PIM_DEBUG_PIM_TRACE) { char up_str[INET_ADDRSTRLEN]; @@ -105,6 +107,14 @@ 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(%s) in join is now in SSM, not allowed to create PIM state", + __func__, + inet_ntop(AF_INET, &sg->grp, buf, sizeof(buf))); + return; + } + sg->src.s_addr = INADDR_ANY; } diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 9d5b864ab0..fc464753e0 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -323,6 +323,7 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, int i_am_rp = 0; struct pim_interface *pim_ifp = ifp->info; struct pim_instance *pim = pim_ifp->pim; + char buf[PREFIX_STRLEN]; #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); @@ -381,6 +382,17 @@ 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(%s) is now in SSM, dropping the packet", + __func__, + inet_ntop(AF_INET, &sg.grp, buf, sizeof(buf))); + /* 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/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; |
