diff --git a/.clang-format b/.clang-format index 06769c9661..7aefafa58f 100644 --- a/.clang-format +++ b/.clang-format @@ -224,4 +224,8 @@ WhitespaceSensitiveMacros: - "DEFUN_YANG_NOSH" - "DEFUNSH" - "DEFUNSH_HIDDEN" + - "ALIAS" + - "ALIAS_HIDDEN" + - "ALIAS_YANG" + - "ALIAS_DEPRECATED" ... diff --git a/alpine/APKBUILD.in b/alpine/APKBUILD.in index 2cb3feec15..855b585903 100644 --- a/alpine/APKBUILD.in +++ b/alpine/APKBUILD.in @@ -33,6 +33,8 @@ _libdir=/usr/lib _user=frr build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" + cd "$builddir" ./configure \ diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index c4349b509e..76ecd4fe4e 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -108,6 +108,7 @@ babel_interface_address_add (ZAPI_CALLBACK_ARGS) if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); + assert (babel_ifp != NULL); if (babel_ifp->ipv4 == NULL) { babel_ifp->ipv4 = malloc(4); if (babel_ifp->ipv4 == NULL) { @@ -144,6 +145,7 @@ babel_interface_address_delete (ZAPI_CALLBACK_ARGS) if (prefix->family == AF_INET) { flush_interface_routes(ifc->ifp, 0); babel_ifp = babel_get_if_nfo(ifc->ifp); + assert (babel_ifp != NULL); if (babel_ifp->ipv4 != NULL && memcmp(babel_ifp->ipv4, &prefix->u.prefix4, IPV4_MAX_BYTELEN) == 0) { @@ -542,7 +544,10 @@ DEFPY (babel_set_channel, unsigned jitter(babel_interface_nfo *babel_ifp, int urgent) { - unsigned interval = babel_ifp->hello_interval; + unsigned interval; + + assert (babel_ifp != NULL); + interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else @@ -553,7 +558,10 @@ jitter(babel_interface_nfo *babel_ifp, int urgent) unsigned update_jitter(babel_interface_nfo *babel_ifp, int urgent) { - unsigned interval = babel_ifp->hello_interval; + unsigned interval; + + assert (babel_ifp != NULL); + interval = babel_ifp->hello_interval; if(urgent) interval = MIN(interval, 100); else @@ -566,10 +574,11 @@ update_jitter(babel_interface_nfo *babel_ifp, int urgent) static int interface_recalculate(struct interface *ifp) { - babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); unsigned char *tmp = NULL; int mtu, rc; struct ipv6_mreq mreq; + babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert (babel_ifp != NULL); if (!IS_ENABLE(ifp)) return -1; @@ -656,6 +665,7 @@ interface_reset(struct interface *ifp) int rc; struct ipv6_mreq mreq; babel_interface_nfo *babel_ifp = babel_get_if_nfo(ifp); + assert (babel_ifp != NULL); if (!CHECK_FLAG(babel_ifp->flags, BABEL_IF_IS_UP)) return 0; @@ -777,6 +787,7 @@ show_babel_interface_sub (struct vty *vty, struct interface *ifp) return; } babel_ifp = babel_get_if_nfo (ifp); + assert (babel_ifp != NULL); vty_out (vty, " Babel protocol is running on this interface\n"); vty_out (vty, " Operating mode is \"%s\"\n", CHECK_FLAG(babel_ifp->flags, BABEL_IF_WIRED) ? "wired" : "wireless"); @@ -1228,6 +1239,7 @@ interface_config_write (struct vty *vty) if (ifp->desc) vty_out (vty, " description %s\n",ifp->desc); babel_interface_nfo *babel_ifp = babel_get_if_nfo (ifp); + assert (babel_ifp != NULL); /* wireless is the default*/ if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) { @@ -1330,6 +1342,7 @@ babel_interface_allocate (void) { babel_interface_nfo *babel_ifp; babel_ifp = XCALLOC(MTYPE_BABEL_IF, sizeof(babel_interface_nfo)); + assert (babel_ifp != NULL); /* All flags are unset */ babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket = BUCKET_TOKENS_MAX; @@ -1349,6 +1362,8 @@ babel_interface_allocate (void) static void babel_interface_free (babel_interface_nfo *babel_ifp) { + assert (babel_ifp != NULL); + if (babel_ifp->ipv4){ free(babel_ifp->ipv4); babel_ifp->ipv4 = NULL; diff --git a/bfdd/bfd.c b/bfdd/bfd.c index 3096f47d5c..eb9c300313 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -256,19 +256,8 @@ void gen_bfd_key(struct bfd_key *key, struct sockaddr_any *peer, struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc) { - struct bfd_session *bs; - struct peer_label *pl; struct bfd_key key; - /* Try to find label first. */ - if (bpc->bpc_has_label) { - pl = pl_find(bpc->bpc_label); - if (pl != NULL) { - bs = pl->pl_bs; - return bs; - } - } - /* Otherwise fallback to peer/local hash lookup. */ gen_bfd_key(&key, &bpc->bpc_peer, &bpc->bpc_local, bpc->bpc_mhop, bpc->bpc_localif, bpc->bpc_vrfname); @@ -327,10 +316,8 @@ int bfd_session_enable(struct bfd_session *bs) bs->ifp = ifp; /* Attempt to use data plane. */ - if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) { - control_notify_config(BCM_NOTIFY_CONFIG_ADD, bs); + if (bglobal.bg_use_dplane && bfd_dplane_add_session(bs) == 0) return 0; - } /* Sanity check: don't leak open sockets. */ if (bs->sock != -1) { @@ -410,8 +397,8 @@ static uint32_t ptm_bfd_gen_ID(void) * random session identification numbers. */ do { - session_id = ((frr_weak_random() << 16) & 0xFFFF0000) - | (frr_weak_random() & 0x0000FFFF); + session_id = CHECK_FLAG((frr_weak_random() << 16), 0xFFFF0000) | + CHECK_FLAG(frr_weak_random(), 0x0000FFFF); } while (session_id == 0 || bfd_id_lookup(session_id) != NULL); return session_id; @@ -502,7 +489,7 @@ void ptm_bfd_sess_up(struct bfd_session *bfd) /* Start sending control packets with poll bit immediately. */ ptm_bfd_snd(bfd, 0); - control_notify(bfd, bfd->ses_state); + ptm_bfd_notify(bfd, bfd->ses_state); if (old_state != bfd->ses_state) { bfd->stats.session_up++; @@ -538,7 +525,7 @@ void ptm_bfd_sess_dn(struct bfd_session *bfd, uint8_t diag) /* only signal clients when going from up->down state */ if (old_state == PTM_BFD_UP) - control_notify(bfd, PTM_BFD_DOWN); + ptm_bfd_notify(bfd, PTM_BFD_DOWN); /* Stop echo packet transmission if they are active */ if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_ECHO_ACTIVE)) @@ -690,38 +677,6 @@ struct bfd_session *bfd_session_new(void) return bs; } -int bfd_session_update_label(struct bfd_session *bs, const char *nlabel) -{ - /* New label treatment: - * - Check if the label is taken; - * - Try to allocate the memory for it and register; - */ - if (bs->pl == NULL) { - if (pl_find(nlabel) != NULL) { - /* Someone is already using it. */ - return -1; - } - - pl_new(nlabel, bs); - - return 0; - } - - /* - * Test label change consistency: - * - Do nothing if it's the same label; - * - Check if the future label is already taken; - * - Change label; - */ - if (strcmp(nlabel, bs->pl->pl_label) == 0) - return -1; - if (pl_find(nlabel) != NULL) - return -1; - - strlcpy(bs->pl->pl_label, nlabel, sizeof(bs->pl->pl_label)); - return 0; -} - static void _bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) { @@ -750,9 +705,6 @@ static void _bfd_session_update(struct bfd_session *bs, bs->peer_profile.min_echo_tx = bs->timers.desired_min_echo_tx; } - if (bpc->bpc_has_label) - bfd_session_update_label(bs, bpc->bpc_label); - if (bpc->bpc_cbit) SET_FLAG(bs->flags, BFD_SESS_FLAG_CBIT); else @@ -792,8 +744,6 @@ static int bfd_session_update(struct bfd_session *bs, struct bfd_peer_cfg *bpc) _bfd_session_update(bs, bpc); - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); - return 0; } @@ -819,8 +769,6 @@ void bfd_session_free(struct bfd_session *bs) if (bso != NULL) bs_observer_del(bso); - pl_free(bs->pl); - XFREE(MTYPE_BFDD_PROFILE, bs->profile_name); XFREE(MTYPE_BFDD_CONFIG, bs); } @@ -917,8 +865,6 @@ struct bfd_session *bs_registrate(struct bfd_session *bfd) if (bglobal.debug_peer_event) zlog_debug("session-new: %s", bs_to_string(bfd)); - control_notify_config(BCM_NOTIFY_CONFIG_ADD, bfd); - return bfd; } @@ -941,8 +887,6 @@ int ptm_bfd_sess_del(struct bfd_peer_cfg *bpc) if (bglobal.debug_peer_event) zlog_debug("%s: %s", __func__, bs_to_string(bs)); - control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs); - bfd_session_free(bs); return 0; @@ -1166,11 +1110,8 @@ void bs_final_handler(struct bfd_session *bs) * When using demand mode we must disable the detection timer * for lost control packets. */ - if (bs->demand_mode) { - /* Notify watchers about changed timers. */ - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); + if (bs->demand_mode) return; - } /* * Calculate transmission time based on new timers. @@ -1189,9 +1130,6 @@ void bs_final_handler(struct bfd_session *bs) /* Apply new transmission timer immediately. */ ptm_bfd_start_xmt_timer(bs, false); - - /* Notify watchers about changed timers. */ - control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); } void bs_set_slow_timers(struct bfd_session *bs) @@ -1261,7 +1199,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) if (bs->bdc) { bs->ses_state = PTM_BFD_ADM_DOWN; bfd_dplane_update_session(bs); - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); return; } @@ -1273,7 +1211,7 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) /* Change and notify state change. */ bs->ses_state = PTM_BFD_ADM_DOWN; - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* Don't try to send packets with a disabled session. */ if (bs->sock != -1) @@ -1289,13 +1227,13 @@ void bfd_set_shutdown(struct bfd_session *bs, bool shutdown) if (bs->bdc) { bs->ses_state = PTM_BFD_DOWN; bfd_dplane_update_session(bs); - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); return; } /* Change and notify state change. */ bs->ses_state = PTM_BFD_DOWN; - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* Enable timers if non passive, otherwise stop them. */ if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_PASSIVE)) { diff --git a/bfdd/bfd.h b/bfdd/bfd.h index f4ff884e00..2f83b245eb 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -20,19 +20,73 @@ #include "lib/queue.h" #include "lib/vrf.h" -#include "bfdctl.h" - #ifdef BFD_DEBUG #define BFDD_JSON_CONV_OPTIONS (JSON_C_TO_STRING_PRETTY) #else #define BFDD_JSON_CONV_OPTIONS (0) #endif +#ifndef MAXNAMELEN +#define MAXNAMELEN 32 +#endif + +#define BPC_DEF_DETECTMULTIPLIER 3 +#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ +#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ +#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */ +#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */ + DECLARE_MGROUP(BFDD); -DECLARE_MTYPE(BFDD_CONTROL); -DECLARE_MTYPE(BFDD_NOTIFICATION); +DECLARE_MTYPE(BFDD_CLIENT); +DECLARE_MTYPE(BFDD_CLIENT_NOTIFICATION); + +struct sockaddr_any { + union { + struct sockaddr_in sa_sin; + struct sockaddr_in6 sa_sin6; + }; +}; + +struct bfd_peer_cfg { + bool bpc_mhop; + bool bpc_ipv4; + struct sockaddr_any bpc_peer; + struct sockaddr_any bpc_local; + + bool bpc_has_localif; + char bpc_localif[MAXNAMELEN + 1]; + + bool bpc_has_vrfname; + char bpc_vrfname[MAXNAMELEN + 1]; + + bool bpc_has_detectmultiplier; + uint8_t bpc_detectmultiplier; + + bool bpc_has_recvinterval; + uint64_t bpc_recvinterval; + + bool bpc_has_txinterval; + uint64_t bpc_txinterval; -#define BFDD_SOCK_NAME "%s/bfdd.sock", frr_runstatedir + bool bpc_has_echorecvinterval; + uint64_t bpc_echorecvinterval; + + bool bpc_has_echotxinterval; + uint64_t bpc_echotxinterval; + + bool bpc_has_minimum_ttl; + uint8_t bpc_minimum_ttl; + + bool bpc_echo; + bool bpc_createonly; + bool bpc_shutdown; + + bool bpc_cbit; + bool bpc_passive; + + bool bpc_has_profile; + char bpc_profile[64]; +}; /* bfd Authentication Type. */ #define BFD_AUTH_NULL 0 @@ -97,8 +151,9 @@ struct bfd_echo_pkt { /* Macros for manipulating control packets */ #define BFD_VERMASK 0x07 #define BFD_DIAGMASK 0x1F -#define BFD_GETVER(diag) ((diag >> 5) & BFD_VERMASK) -#define BFD_SETVER(diag, val) ((diag) |= (val & BFD_VERMASK) << 5) +#define BFD_GETVER(diag) (CHECK_FLAG((diag >> 5), BFD_VERMASK)) +#define BFD_SETVER(diag, val) \ + SET_FLAG((diag), CHECK_FLAG(val, BFD_VERMASK) << 5) #define BFD_VERSION 1 #define BFD_PBIT 0x20 #define BFD_FBIT 0x10 @@ -106,36 +161,36 @@ struct bfd_echo_pkt { #define BFD_ABIT 0x04 #define BFD_DEMANDBIT 0x02 #define BFD_MBIT 0x01 -#define BFD_GETMBIT(flags) (flags & BFD_MBIT) +#define BFD_GETMBIT(flags) (CHECK_FLAG(flags, BFD_MBIT)) #define BFD_SETDEMANDBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_DEMANDBIT; \ + SET_FLAG(flags, BFD_DEMANDBIT); \ } #define BFD_SETPBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_PBIT; \ + SET_FLAG(flags, BFD_PBIT); \ } -#define BFD_GETPBIT(flags) (flags & BFD_PBIT) +#define BFD_GETPBIT(flags) (CHECK_FLAG(flags, BFD_PBIT)) #define BFD_SETFBIT(flags, val) \ { \ if ((val)) \ - flags |= BFD_FBIT; \ + SET_FLAG(flags, BFD_FBIT); \ } -#define BFD_GETFBIT(flags) (flags & BFD_FBIT) +#define BFD_GETFBIT(flags) (CHECK_FLAG(flags, BFD_FBIT)) #define BFD_SETSTATE(flags, val) \ { \ if ((val)) \ - flags |= (val & 0x3) << 6; \ + SET_FLAG(flags, (CHECK_FLAG(val, 0x3) << 6)); \ } -#define BFD_GETSTATE(flags) ((flags >> 6) & 0x3) +#define BFD_GETSTATE(flags) (CHECK_FLAG((flags >> 6), 0x3)) #define BFD_SETCBIT(flags, val) \ { \ if ((val)) \ - flags |= val; \ + SET_FLAG(flags, val); \ } -#define BFD_GETCBIT(flags) (flags & BFD_CBIT) +#define BFD_GETCBIT(flags) (CHECK_FLAG(flags, BFD_CBIT)) #define BFD_ECHO_VERSION 1 #define BFD_ECHO_PKT_LEN sizeof(struct bfd_echo_pkt) @@ -245,9 +300,6 @@ struct bfd_profile { /** Profile list type. */ TAILQ_HEAD(bfdproflist, bfd_profile); -/* bfd_session shortcut label forwarding. */ -struct peer_label; - struct bfd_config_timers { uint32_t desired_min_tx; uint32_t required_min_rx; @@ -325,14 +377,6 @@ struct bfd_session { uint64_t rtt[BFD_RTT_SAMPLE]; /* RRT in usec for echo to be looped */ }; -struct peer_label { - TAILQ_ENTRY(peer_label) pl_entry; - - struct bfd_session *pl_bs; - char pl_label[MAXNAMELEN]; -}; -TAILQ_HEAD(pllist, peer_label); - struct bfd_diag_str_list { const char *str; int type; @@ -384,64 +428,6 @@ TAILQ_HEAD(obslist, bfd_session_observer); #define BFD_DEF_ECHO_PORT 3785 #define BFD_DEF_MHOP_DEST_PORT 4784 -/* - * control.c - * - * Daemon control code to speak with local consumers. - */ - -/* See 'bfdctrl.h' for client protocol definitions. */ - -struct bfd_control_buffer { - size_t bcb_left; - size_t bcb_pos; - union { - struct bfd_control_msg *bcb_bcm; - uint8_t *bcb_buf; - }; -}; - -struct bfd_control_queue { - TAILQ_ENTRY(bfd_control_queue) bcq_entry; - - struct bfd_control_buffer bcq_bcb; -}; -TAILQ_HEAD(bcqueue, bfd_control_queue); - -struct bfd_notify_peer { - TAILQ_ENTRY(bfd_notify_peer) bnp_entry; - - struct bfd_session *bnp_bs; -}; -TAILQ_HEAD(bnplist, bfd_notify_peer); - -struct bfd_control_socket { - TAILQ_ENTRY(bfd_control_socket) bcs_entry; - - int bcs_sd; - struct event *bcs_ev; - struct event *bcs_outev; - struct bcqueue bcs_bcqueue; - - /* Notification data */ - uint64_t bcs_notify; - struct bnplist bcs_bnplist; - - enum bc_msg_version bcs_version; - enum bc_msg_type bcs_type; - - /* Message buffering */ - struct bfd_control_buffer bcs_bin; - struct bfd_control_buffer *bcs_bout; -}; -TAILQ_HEAD(bcslist, bfd_control_socket); - -int control_init(const char *path); -void control_shutdown(void); -int control_notify(struct bfd_session *bs, uint8_t notify_state); -int control_notify_config(const char *op, struct bfd_session *bs); -void control_accept(struct event *t); - /* * bfdd.c @@ -467,9 +453,6 @@ TAILQ_HEAD(dplane_queue, bfd_dplane_ctx); struct bfd_global { int bg_csock; struct event *bg_csockev; - struct bcslist bg_bcslist; - - struct pllist bg_pllist; struct obslist bg_obslist; @@ -515,27 +498,6 @@ extern const struct bfd_state_str_list state_list[]; void socket_close(int *s); -/* - * config.c - * - * Contains the code related with loading/reloading configuration. - */ -int parse_config(const char *fname); -int config_request_add(const char *jsonstr); -int config_request_del(const char *jsonstr); -char *config_response(const char *status, const char *error); -char *config_notify(struct bfd_session *bs); -char *config_notify_config(const char *op, struct bfd_session *bs); - -typedef int (*bpc_handle)(struct bfd_peer_cfg *, void *arg); -int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, - bpc_handle bh); - -struct peer_label *pl_new(const char *label, struct bfd_session *bs); -struct peer_label *pl_find(const char *label); -void pl_free(struct peer_label *pl); - - /* * logging - alias to zebra log */ @@ -620,7 +582,6 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, bool is_mhop); struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc); -int bfd_session_update_label(struct bfd_session *bs, const char *nlabel); void bfd_set_polling(struct bfd_session *bs); void bs_state_handler(struct bfd_session *bs, int nstate); void bs_echo_timer_handler(struct bfd_session *bs); diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 8110f434c2..f9397fa128 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -982,7 +982,7 @@ void bfd_recv_cb(struct event *t) } /* Save remote diagnostics before state switch. */ - bfd->remote_diag = cp->diag & BFD_DIAGMASK; + bfd->remote_diag = CHECK_FLAG(cp->diag, BFD_DIAGMASK); /* Update remote timers settings. */ bfd->remote_timers.desired_min_tx = ntohl(cp->timers.desired_min_tx); @@ -1738,7 +1738,7 @@ void bfd_peer_mac_set(int sd, struct bfd_session *bfd, if (CHECK_FLAG(bfd->flags, BFD_SESS_FLAG_MAC_SET)) return; - if (ifp->flags & IFF_NOARP) + if (CHECK_FLAG(ifp->flags, IFF_NOARP)) return; if (peer->sa_sin.sin_family == AF_INET) { diff --git a/bfdd/bfdctl.h b/bfdd/bfdctl.h deleted file mode 100644 index f1f8185c3b..0000000000 --- a/bfdd/bfdctl.h +++ /dev/null @@ -1,157 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * bfdctl.h: all BFDd control socket protocol definitions. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#ifndef _BFDCTRL_H_ -#define _BFDCTRL_H_ - -#include - -#include -#include - -/* - * Auxiliary definitions - */ -struct sockaddr_any { - union { - struct sockaddr_in sa_sin; - struct sockaddr_in6 sa_sin6; - }; -}; - -#ifndef MAXNAMELEN -#define MAXNAMELEN 32 -#endif - -#define BPC_DEF_DETECTMULTIPLIER 3 -#define BPC_DEF_RECEIVEINTERVAL 300 /* milliseconds */ -#define BPC_DEF_TRANSMITINTERVAL 300 /* milliseconds */ -#define BPC_DEF_ECHORECEIVEINTERVAL 50 /* milliseconds */ -#define BPC_DEF_ECHOTRANSMITINTERVAL 50 /* milliseconds */ - -/* Peer status */ -enum bfd_peer_status { - BPS_SHUTDOWN = 0, /* == PTM_BFD_ADM_DOWN, "adm-down" */ - BPS_DOWN = 1, /* == PTM_BFD_DOWN, "down" */ - BPS_INIT = 2, /* == PTM_BFD_INIT, "init" */ - BPS_UP = 3, /* == PTM_BFD_UP, "up" */ -}; - -struct bfd_peer_cfg { - bool bpc_mhop; - bool bpc_ipv4; - struct sockaddr_any bpc_peer; - struct sockaddr_any bpc_local; - - bool bpc_has_label; - char bpc_label[MAXNAMELEN]; - - bool bpc_has_localif; - char bpc_localif[MAXNAMELEN + 1]; - - bool bpc_has_vrfname; - char bpc_vrfname[MAXNAMELEN + 1]; - - bool bpc_has_detectmultiplier; - uint8_t bpc_detectmultiplier; - - bool bpc_has_recvinterval; - uint64_t bpc_recvinterval; - - bool bpc_has_txinterval; - uint64_t bpc_txinterval; - - bool bpc_has_echorecvinterval; - uint64_t bpc_echorecvinterval; - - bool bpc_has_echotxinterval; - uint64_t bpc_echotxinterval; - - bool bpc_has_minimum_ttl; - uint8_t bpc_minimum_ttl; - - bool bpc_echo; - bool bpc_createonly; - bool bpc_shutdown; - - bool bpc_cbit; - bool bpc_passive; - - bool bpc_has_profile; - char bpc_profile[64]; - - /* Status information */ - enum bfd_peer_status bpc_bps; - uint32_t bpc_id; - uint32_t bpc_remoteid; - uint8_t bpc_diag; - uint8_t bpc_remotediag; - uint8_t bpc_remote_detectmultiplier; - uint64_t bpc_remote_recvinterval; - uint64_t bpc_remote_txinterval; - uint64_t bpc_remote_echointerval; - uint64_t bpc_lastevent; -}; - - -/* - * Protocol definitions - */ -enum bc_msg_version { - BMV_VERSION_1 = 1, -}; - -enum bc_msg_type { - BMT_RESPONSE = 1, - BMT_REQUEST_ADD = 2, - BMT_REQUEST_DEL = 3, - BMT_NOTIFY = 4, - BMT_NOTIFY_ADD = 5, - BMT_NOTIFY_DEL = 6, -}; - -/* Notify flags to use with bcm_notify. */ -#define BCM_NOTIFY_ALL ((uint64_t)-1) -#define BCM_NOTIFY_PEER_STATE (1ULL << 0) -#define BCM_NOTIFY_CONFIG (1ULL << 1) -#define BCM_NOTIFY_NONE 0 - -/* Response 'status' definitions. */ -#define BCM_RESPONSE_OK "ok" -#define BCM_RESPONSE_ERROR "error" - -/* Notify operation. */ -#define BCM_NOTIFY_PEER_STATUS "status" -#define BCM_NOTIFY_CONFIG_ADD "add" -#define BCM_NOTIFY_CONFIG_DELETE "delete" -#define BCM_NOTIFY_CONFIG_UPDATE "update" - -/* Notification special ID. */ -#define BCM_NOTIFY_ID 0 - -struct bfd_control_msg { - /* Total length without the header. */ - uint32_t bcm_length; - /* - * Message request/response id. - * All requests will have a correspondent response with the - * same id. - */ - uint16_t bcm_id; - /* Message type. */ - uint8_t bcm_type; - /* Message version. */ - uint8_t bcm_ver; - /* Message payload. */ - uint8_t bcm_data[0]; -}; - -#endif diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 243cf5c129..c2d8e926bf 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -28,8 +28,8 @@ * FRR related code. */ DEFINE_MGROUP(BFDD, "Bidirectional Forwarding Detection Daemon"); -DEFINE_MTYPE(BFDD, BFDD_CONTROL, "control socket memory"); -DEFINE_MTYPE(BFDD, BFDD_NOTIFICATION, "control notification data"); +DEFINE_MTYPE(BFDD, BFDD_CLIENT, "BFD client data"); +DEFINE_MTYPE(BFDD, BFDD_CLIENT_NOTIFICATION, "BFD client notification data"); /* Master of threads. */ struct event_loop *master; @@ -67,9 +67,6 @@ static void sigterm_handler(void) /* Stop receiving message from zebra. */ bfdd_zclient_stop(); - /* Shutdown controller to avoid receiving anymore commands. */ - control_shutdown(); - /* Shutdown and free all protocol related memory. */ bfd_shutdown(); @@ -132,10 +129,8 @@ FRR_DAEMON_INFO(bfdd, BFD, ); /* clang-format on */ -#define OPTION_CTLSOCK 1001 #define OPTION_DPLANEADDR 2000 static const struct option longopts[] = { - {"bfdctl", required_argument, NULL, OPTION_CTLSOCK}, {"dplaneaddr", required_argument, NULL, OPTION_DPLANEADDR}, {0} }; @@ -319,7 +314,6 @@ static void bg_init(void) .cap_num_i = 0, }; - TAILQ_INIT(&bglobal.bg_bcslist); TAILQ_INIT(&bglobal.bg_obslist); memcpy(&bglobal.bfdd_privs, &bfdd_privs, @@ -328,8 +322,7 @@ static void bg_init(void) int main(int argc, char *argv[]) { - char ctl_path[512], dplane_addr[512]; - bool ctlsockused = false; + char dplane_addr[512]; int opt; bglobal.bg_use_dplane = false; @@ -339,7 +332,6 @@ int main(int argc, char *argv[]) frr_preinit(&bfdd_di, argc, argv); frr_opt_add("", longopts, - " --bfdctl Specify bfdd control socket\n" " --dplaneaddr Specify BFD data plane address\n"); while (true) { @@ -348,10 +340,6 @@ int main(int argc, char *argv[]) break; switch (opt) { - case OPTION_CTLSOCK: - strlcpy(ctl_path, optarg, sizeof(ctl_path)); - ctlsockused = true; - break; case OPTION_DPLANEADDR: strlcpy(dplane_addr, optarg, sizeof(dplane_addr)); bglobal.bg_use_dplane = true; @@ -362,15 +350,9 @@ int main(int argc, char *argv[]) } } - if (!ctlsockused) - snprintf(ctl_path, sizeof(ctl_path), BFDD_SOCK_NAME); - /* Initialize FRR infrastructure. */ master = frr_init(); - /* Initialize control socket. */ - control_init(ctl_path); - /* Initialize BFD data structures. */ bfd_initialize(); @@ -381,9 +363,6 @@ int main(int argc, char *argv[]) /* Initialize zebra connection. */ bfdd_zclient_init(&bglobal.bfdd_privs); - event_add_read(master, control_accept, NULL, bglobal.bg_csock, - &bglobal.bg_csockev); - /* Install commands. */ bfdd_vty_init(); diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 496d5019b5..26554e1496 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -84,9 +84,6 @@ static void _display_peer_header(struct vty *vty, struct bfd_session *bs) if (bs->key.ifname[0]) vty_out(vty, " interface %s", bs->key.ifname); vty_out(vty, "\n"); - - if (bs->pl) - vty_out(vty, "\t\tlabel: %s\n", bs->pl->pl_label); } static void _display_peer(struct vty *vty, struct bfd_session *bs) @@ -200,9 +197,6 @@ static struct json_object *_peer_json_header(struct bfd_session *bs) if (bs->key.ifname[0]) json_object_string_add(jo, "interface", bs->key.ifname); - if (bs->pl) - json_object_string_add(jo, "label", bs->pl->pl_label); - return jo; } @@ -561,17 +555,11 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, int idx; bool mhop; struct bfd_session *bs = NULL; - struct peer_label *pl; struct bfd_peer_cfg bpc; struct sockaddr_any psa, lsa, *lsap; char errormsg[128]; - /* Look up the BFD peer. */ - if (label) { - pl = pl_find(label); - if (pl) - bs = pl->pl_bs; - } else if (peer_str) { + if (peer_str) { strtosa(peer_str, &psa); if (local_str) { strtosa(local_str, &lsa); @@ -879,7 +867,6 @@ static int bfd_configure_peer(struct bfd_peer_cfg *bpc, bool mhop, bpc->bpc_txinterval = BPC_DEF_TRANSMITINTERVAL; bpc->bpc_echorecvinterval = BPC_DEF_ECHORECEIVEINTERVAL; bpc->bpc_echotxinterval = BPC_DEF_ECHOTRANSMITINTERVAL; - bpc->bpc_lastevent = monotime(NULL); /* Safety check: when no error buf is provided len must be zero. */ if (ebuf == NULL) diff --git a/bfdd/config.c b/bfdd/config.c deleted file mode 100644 index 22d7d7deee..0000000000 --- a/bfdd/config.c +++ /dev/null @@ -1,592 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * config.c: implements the BFD daemon configuration handling. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#include - -#include - -#include "lib/json.h" - -#include "bfd.h" - -DEFINE_MTYPE_STATIC(BFDD, BFDD_LABEL, "long-lived label memory"); - -/* - * Definitions - */ -enum peer_list_type { - PLT_IPV4, - PLT_IPV6, - PLT_LABEL, -}; - - -/* - * Prototypes - */ -static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg); -static int parse_list(struct json_object *jo, enum peer_list_type plt, - bpc_handle h, void *arg); -static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc); -static int parse_peer_label_config(struct json_object *jo, - struct bfd_peer_cfg *bpc); - -static int config_add(struct bfd_peer_cfg *bpc, void *arg); -static int config_del(struct bfd_peer_cfg *bpc, void *arg); - -static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs); - - -/* - * Implementation - */ -static int config_add(struct bfd_peer_cfg *bpc, - void *arg __attribute__((unused))) -{ - return ptm_bfd_sess_new(bpc) == NULL; -} - -static int config_del(struct bfd_peer_cfg *bpc, - void *arg __attribute__((unused))) -{ - return ptm_bfd_sess_del(bpc) != 0; -} - -static int parse_config_json(struct json_object *jo, bpc_handle h, void *arg) -{ - const char *key, *sval; - struct json_object *jo_val; - struct json_object_iterator joi, join; - int error = 0; - - JSON_FOREACH (jo, joi, join) { - key = json_object_iter_peek_name(&joi); - jo_val = json_object_iter_peek_value(&joi); - - if (strcmp(key, "ipv4") == 0) { - error += parse_list(jo_val, PLT_IPV4, h, arg); - } else if (strcmp(key, "ipv6") == 0) { - error += parse_list(jo_val, PLT_IPV6, h, arg); - } else if (strcmp(key, "label") == 0) { - error += parse_list(jo_val, PLT_LABEL, h, arg); - } else { - sval = json_object_get_string(jo_val); - zlog_warn("%s:%d invalid configuration: %s", __func__, - __LINE__, sval); - error++; - } - } - - /* - * Our callers never call free() on json_object and only expect - * the return value, so lets free() it here. - */ - json_object_put(jo); - - return error; -} - -int parse_config(const char *fname) -{ - struct json_object *jo; - - jo = json_object_from_file(fname); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_add, NULL); -} - -static int parse_list(struct json_object *jo, enum peer_list_type plt, - bpc_handle h, void *arg) -{ - struct json_object *jo_val; - struct bfd_peer_cfg bpc; - int allen, idx; - int error = 0, result; - - allen = json_object_array_length(jo); - for (idx = 0; idx < allen; idx++) { - jo_val = json_object_array_get_idx(jo, idx); - - /* Set defaults. */ - memset(&bpc, 0, sizeof(bpc)); - bpc.bpc_detectmultiplier = BFD_DEFDETECTMULT; - bpc.bpc_recvinterval = BFD_DEFREQUIREDMINRX; - bpc.bpc_txinterval = BFD_DEFDESIREDMINTX; - bpc.bpc_echorecvinterval = BFD_DEF_REQ_MIN_ECHO_RX; - bpc.bpc_echotxinterval = BFD_DEF_DES_MIN_ECHO_TX; - - switch (plt) { - case PLT_IPV4: - zlog_debug("ipv4 peers %d:", allen); - bpc.bpc_ipv4 = true; - break; - case PLT_IPV6: - zlog_debug("ipv6 peers %d:", allen); - bpc.bpc_ipv4 = false; - break; - case PLT_LABEL: - zlog_debug("label peers %d:", allen); - if (parse_peer_label_config(jo_val, &bpc) != 0) { - error++; - continue; - } - break; - - default: - error++; - zlog_err("%s:%d: unsupported peer type", __func__, - __LINE__); - break; - } - - result = parse_peer_config(jo_val, &bpc); - error += result; - if (result == 0) - error += (h(&bpc, arg) != 0); - } - - return error; -} - -static int parse_peer_config(struct json_object *jo, struct bfd_peer_cfg *bpc) -{ - const char *key, *sval; - struct json_object *jo_val; - struct json_object_iterator joi, join; - int family_type = (bpc->bpc_ipv4) ? AF_INET : AF_INET6; - int error = 0; - - zlog_debug(" peer: %s", bpc->bpc_ipv4 ? "ipv4" : "ipv6"); - - JSON_FOREACH (jo, joi, join) { - key = json_object_iter_peek_name(&joi); - jo_val = json_object_iter_peek_value(&joi); - - if (strcmp(key, "multihop") == 0) { - bpc->bpc_mhop = json_object_get_boolean(jo_val); - zlog_debug(" multihop: %s", - bpc->bpc_mhop ? "true" : "false"); - } else if (strcmp(key, "peer-address") == 0) { - sval = json_object_get_string(jo_val); - if (strtosa(sval, &bpc->bpc_peer) != 0 - || bpc->bpc_peer.sa_sin.sin_family != family_type) { - zlog_debug( - "%s:%d failed to parse peer-address '%s'", - __func__, __LINE__, sval); - error++; - } - zlog_debug(" peer-address: %s", sval); - } else if (strcmp(key, "local-address") == 0) { - sval = json_object_get_string(jo_val); - if (strtosa(sval, &bpc->bpc_local) != 0 - || bpc->bpc_local.sa_sin.sin_family - != family_type) { - zlog_debug( - "%s:%d failed to parse local-address '%s'", - __func__, __LINE__, sval); - error++; - } - zlog_debug(" local-address: %s", sval); - } else if (strcmp(key, "local-interface") == 0) { - bpc->bpc_has_localif = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_localif, sval, - sizeof(bpc->bpc_localif)) - > sizeof(bpc->bpc_localif)) { - zlog_debug( - " local-interface: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" local-interface: %s", sval); - } - } else if (strcmp(key, "vrf-name") == 0) { - bpc->bpc_has_vrfname = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_vrfname, sval, - sizeof(bpc->bpc_vrfname)) - > sizeof(bpc->bpc_vrfname)) { - zlog_debug(" vrf-name: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" vrf-name: %s", sval); - } - } else if (strcmp(key, "detect-multiplier") == 0) { - bpc->bpc_detectmultiplier = - json_object_get_int64(jo_val); - bpc->bpc_has_detectmultiplier = true; - zlog_debug(" detect-multiplier: %u", - bpc->bpc_detectmultiplier); - } else if (strcmp(key, "receive-interval") == 0) { - bpc->bpc_recvinterval = json_object_get_int64(jo_val); - bpc->bpc_has_recvinterval = true; - zlog_debug(" receive-interval: %" PRIu64, - bpc->bpc_recvinterval); - } else if (strcmp(key, "transmit-interval") == 0) { - bpc->bpc_txinterval = json_object_get_int64(jo_val); - bpc->bpc_has_txinterval = true; - zlog_debug(" transmit-interval: %" PRIu64, - bpc->bpc_txinterval); - } else if (strcmp(key, "echo-receive-interval") == 0) { - bpc->bpc_echorecvinterval = json_object_get_int64(jo_val); - bpc->bpc_has_echorecvinterval = true; - zlog_debug(" echo-receive-interval: %" PRIu64, - bpc->bpc_echorecvinterval); - } else if (strcmp(key, "echo-transmit-interval") == 0) { - bpc->bpc_echotxinterval = json_object_get_int64(jo_val); - bpc->bpc_has_echotxinterval = true; - zlog_debug(" echo-transmit-interval: %" PRIu64, - bpc->bpc_echotxinterval); - } else if (strcmp(key, "create-only") == 0) { - bpc->bpc_createonly = json_object_get_boolean(jo_val); - zlog_debug(" create-only: %s", - bpc->bpc_createonly ? "true" : "false"); - } else if (strcmp(key, "shutdown") == 0) { - bpc->bpc_shutdown = json_object_get_boolean(jo_val); - zlog_debug(" shutdown: %s", - bpc->bpc_shutdown ? "true" : "false"); - } else if (strcmp(key, "echo-mode") == 0) { - bpc->bpc_echo = json_object_get_boolean(jo_val); - zlog_debug(" echo-mode: %s", - bpc->bpc_echo ? "true" : "false"); - } else if (strcmp(key, "label") == 0) { - bpc->bpc_has_label = true; - sval = json_object_get_string(jo_val); - if (strlcpy(bpc->bpc_label, sval, - sizeof(bpc->bpc_label)) - > sizeof(bpc->bpc_label)) { - zlog_debug(" label: %s (truncated)", - sval); - error++; - } else { - zlog_debug(" label: %s", sval); - } - } else { - sval = json_object_get_string(jo_val); - zlog_warn("%s:%d invalid configuration: '%s: %s'", - __func__, __LINE__, key, sval); - error++; - } - } - - if (bpc->bpc_peer.sa_sin.sin_family == 0) { - zlog_debug("%s:%d no peer address provided", __func__, - __LINE__); - error++; - } - - return error; -} - -static int parse_peer_label_config(struct json_object *jo, - struct bfd_peer_cfg *bpc) -{ - struct peer_label *pl; - struct json_object *label; - const char *sval; - - /* Get label and translate it to BFD daemon key. */ - if (!json_object_object_get_ex(jo, "label", &label)) - return 1; - - sval = json_object_get_string(label); - - pl = pl_find(sval); - if (pl == NULL) - return 1; - - zlog_debug(" peer-label: %s", sval); - - /* Translate the label into BFD address keys. */ - bs_to_bpc(pl->pl_bs, bpc); - - return 0; -} - - -/* - * Control socket JSON parsing. - */ -int config_request_add(const char *jsonstr) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_add, NULL); -} - -int config_request_del(const char *jsonstr) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, config_del, NULL); -} - -char *config_response(const char *status, const char *error) -{ - struct json_object *resp, *jo; - char *jsonstr; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - /* Add 'status' response key. */ - jo = json_object_new_string(status); - if (jo == NULL) { - json_object_put(resp); - return NULL; - } - - json_object_object_add(resp, "status", jo); - - /* Add 'error' response key. */ - if (error != NULL) { - jo = json_object_new_string(error); - if (jo == NULL) { - json_object_put(resp); - return NULL; - } - - json_object_object_add(resp, "error", jo); - } - - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -char *config_notify(struct bfd_session *bs) -{ - struct json_object *resp; - char *jsonstr; - time_t now; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - json_object_string_add(resp, "op", BCM_NOTIFY_PEER_STATUS); - - json_object_add_peer(resp, bs); - - /* Add status information */ - json_object_int_add(resp, "id", bs->discrs.my_discr); - json_object_int_add(resp, "remote-id", bs->discrs.my_discr); - - switch (bs->ses_state) { - case PTM_BFD_UP: - json_object_string_add(resp, "state", "up"); - - now = monotime(NULL); - json_object_int_add(resp, "uptime", now - bs->uptime.tv_sec); - break; - case PTM_BFD_ADM_DOWN: - json_object_string_add(resp, "state", "adm-down"); - break; - case PTM_BFD_DOWN: - json_object_string_add(resp, "state", "down"); - - now = monotime(NULL); - json_object_int_add(resp, "downtime", - now - bs->downtime.tv_sec); - break; - case PTM_BFD_INIT: - json_object_string_add(resp, "state", "init"); - break; - - default: - json_object_string_add(resp, "state", "unknown"); - break; - } - - json_object_int_add(resp, "diagnostics", bs->local_diag); - json_object_int_add(resp, "remote-diagnostics", bs->remote_diag); - - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -char *config_notify_config(const char *op, struct bfd_session *bs) -{ - struct json_object *resp; - char *jsonstr; - - resp = json_object_new_object(); - if (resp == NULL) - return NULL; - - json_object_string_add(resp, "op", op); - - json_object_add_peer(resp, bs); - - /* On peer deletion we don't need to add any additional information. */ - if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0) - goto skip_config; - - json_object_int_add(resp, "detect-multiplier", bs->detect_mult); - json_object_int_add(resp, "receive-interval", - bs->timers.required_min_rx / 1000); - json_object_int_add(resp, "transmit-interval", - bs->timers.desired_min_tx / 1000); - json_object_int_add(resp, "echo-receive-interval", - bs->timers.required_min_echo_rx / 1000); - json_object_int_add(resp, "echo-transmit-interval", - bs->timers.desired_min_echo_tx / 1000); - - json_object_int_add(resp, "remote-detect-multiplier", - bs->remote_detect_mult); - json_object_int_add(resp, "remote-receive-interval", - bs->remote_timers.required_min_rx / 1000); - json_object_int_add(resp, "remote-transmit-interval", - bs->remote_timers.desired_min_tx / 1000); - json_object_int_add(resp, "remote-echo-receive-interval", - bs->remote_timers.required_min_echo / 1000); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_ECHO)) - json_object_boolean_true_add(resp, "echo-mode"); - else - json_object_boolean_false_add(resp, "echo-mode"); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_SHUTDOWN)) - json_object_boolean_true_add(resp, "shutdown"); - else - json_object_boolean_false_add(resp, "shutdown"); - -skip_config: - /* Generate JSON response. */ - jsonstr = XSTRDUP( - MTYPE_BFDD_NOTIFICATION, - json_object_to_json_string_ext(resp, BFDD_JSON_CONV_OPTIONS)); - json_object_put(resp); - - return jsonstr; -} - -int config_notify_request(struct bfd_control_socket *bcs, const char *jsonstr, - bpc_handle bh) -{ - struct json_object *jo; - - jo = json_tokener_parse(jsonstr); - if (jo == NULL) - return -1; - - return parse_config_json(jo, bh, bcs); -} - -static int json_object_add_peer(struct json_object *jo, struct bfd_session *bs) -{ - char addr_buf[INET6_ADDRSTRLEN]; - - /* Add peer 'key' information. */ - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_IPV6)) - json_object_boolean_true_add(jo, "ipv6"); - else - json_object_boolean_false_add(jo, "ipv6"); - - if (CHECK_FLAG(bs->flags, BFD_SESS_FLAG_MH)) { - json_object_boolean_true_add(jo, "multihop"); - json_object_string_add(jo, "peer-address", - inet_ntop(bs->key.family, &bs->key.peer, - addr_buf, sizeof(addr_buf))); - json_object_string_add(jo, "local-address", - inet_ntop(bs->key.family, &bs->key.local, - addr_buf, sizeof(addr_buf))); - if (bs->key.vrfname[0]) - json_object_string_add(jo, "vrf-name", bs->key.vrfname); - } else { - json_object_boolean_false_add(jo, "multihop"); - json_object_string_add(jo, "peer-address", - inet_ntop(bs->key.family, &bs->key.peer, - addr_buf, sizeof(addr_buf))); - if (memcmp(&bs->key.local, &zero_addr, sizeof(bs->key.local))) - json_object_string_add( - jo, "local-address", - inet_ntop(bs->key.family, &bs->key.local, - addr_buf, sizeof(addr_buf))); - if (bs->key.ifname[0]) - json_object_string_add(jo, "local-interface", - bs->key.ifname); - } - - if (bs->pl) - json_object_string_add(jo, "label", bs->pl->pl_label); - - return 0; -} - - -/* - * Label handling - */ -struct peer_label *pl_find(const char *label) -{ - struct peer_label *pl; - - TAILQ_FOREACH (pl, &bglobal.bg_pllist, pl_entry) { - if (strcmp(pl->pl_label, label) != 0) - continue; - - return pl; - } - - return NULL; -} - -struct peer_label *pl_new(const char *label, struct bfd_session *bs) -{ - struct peer_label *pl; - - pl = XCALLOC(MTYPE_BFDD_LABEL, sizeof(*pl)); - - if (strlcpy(pl->pl_label, label, sizeof(pl->pl_label)) - > sizeof(pl->pl_label)) - zlog_warn("%s:%d: label was truncated", __func__, __LINE__); - - pl->pl_bs = bs; - bs->pl = pl; - - TAILQ_INSERT_HEAD(&bglobal.bg_pllist, pl, pl_entry); - - return pl; -} - -void pl_free(struct peer_label *pl) -{ - if (pl == NULL) - return; - - /* Remove the pointer back. */ - pl->pl_bs->pl = NULL; - - TAILQ_REMOVE(&bglobal.bg_pllist, pl, pl_entry); - XFREE(MTYPE_BFDD_LABEL, pl); -} diff --git a/bfdd/control.c b/bfdd/control.c deleted file mode 100644 index 98fd813ef7..0000000000 --- a/bfdd/control.c +++ /dev/null @@ -1,844 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0-or-later -/********************************************************************* - * Copyright 2017-2018 Network Device Education Foundation, Inc. ("NetDEF") - * - * control.c: implements the BFD daemon control socket. It will be used - * to talk with clients daemon/scripts/consumers. - * - * Authors - * ------- - * Rafael Zalamena - */ - -#include - -#include -#include - -#include - -#include "bfd.h" - -/* - * Prototypes - */ -static int sock_set_nonblock(int fd); -struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs); -static void control_queue_free(struct bfd_control_socket *bcs, - struct bfd_control_queue *bcq); -static int control_queue_dequeue(struct bfd_control_socket *bcs); -static int control_queue_enqueue(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static int control_queue_enqueue_first(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs, - struct bfd_session *bs); -static void control_notifypeer_free(struct bfd_control_socket *bcs, - struct bfd_notify_peer *bnp); -struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs, - struct bfd_session *bs); - - -struct bfd_control_socket *control_new(int sd); -static void control_free(struct bfd_control_socket *bcs); -static void control_reset_buf(struct bfd_control_buffer *bcb); -static void control_read(struct event *t); -static void control_write(struct event *t); - -static void control_handle_request_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_handle_request_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg); -static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg); -static void control_handle_notify_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_handle_notify_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void _control_handle_notify(struct hash_bucket *hb, void *arg); -static void control_handle_notify(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm); -static void control_response(struct bfd_control_socket *bcs, uint16_t id, - const char *status, const char *error); - -static void _control_notify_config(struct bfd_control_socket *bcs, - const char *op, struct bfd_session *bs); -static void _control_notify(struct bfd_control_socket *bcs, - struct bfd_session *bs); - - -/* - * Functions - */ -static int sock_set_nonblock(int fd) -{ - int flags; - - flags = fcntl(fd, F_GETFL, 0); - if (flags == -1) { - zlog_warn("%s: fcntl F_GETFL: %s", __func__, strerror(errno)); - return -1; - } - - flags |= O_NONBLOCK; - if (fcntl(fd, F_SETFL, flags) == -1) { - zlog_warn("%s: fcntl F_SETFL: %s", __func__, strerror(errno)); - return -1; - } - - return 0; -} - -int control_init(const char *path) -{ - int sd; - mode_t umval; - struct sockaddr_un sun_ = { - .sun_family = AF_UNIX, - }; - - assert(path); - - strlcpy(sun_.sun_path, path, sizeof(sun_.sun_path)); - - /* Remove previously created sockets. */ - unlink(sun_.sun_path); - - sd = socket(AF_UNIX, SOCK_STREAM, PF_UNSPEC); - if (sd == -1) { - zlog_err("%s: socket: %s", __func__, strerror(errno)); - return -1; - } - - umval = umask(0); - if (bind(sd, (struct sockaddr *)&sun_, sizeof(sun_)) == -1) { - zlog_err("%s: bind: %s", __func__, strerror(errno)); - close(sd); - return -1; - } - umask(umval); - - if (listen(sd, SOMAXCONN) == -1) { - zlog_err("%s: listen: %s", __func__, strerror(errno)); - close(sd); - return -1; - } - - sock_set_nonblock(sd); - - bglobal.bg_csock = sd; - - return 0; -} - -void control_shutdown(void) -{ - struct bfd_control_socket *bcs; - - event_cancel(&bglobal.bg_csockev); - - socket_close(&bglobal.bg_csock); - - while (!TAILQ_EMPTY(&bglobal.bg_bcslist)) { - bcs = TAILQ_FIRST(&bglobal.bg_bcslist); - control_free(bcs); - } -} - -void control_accept(struct event *t) -{ - int csock, sd = EVENT_FD(t); - - csock = accept(sd, NULL, 0); - if (csock == -1) { - zlog_warn("%s: accept: %s", __func__, strerror(errno)); - return; - } - - control_new(csock); - - event_add_read(master, control_accept, NULL, sd, &bglobal.bg_csockev); -} - - -/* - * Client handling - */ -struct bfd_control_socket *control_new(int sd) -{ - struct bfd_control_socket *bcs; - - bcs = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bcs)); - - /* Disable notifications by default. */ - bcs->bcs_notify = 0; - - bcs->bcs_sd = sd; - event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev); - - TAILQ_INIT(&bcs->bcs_bcqueue); - TAILQ_INIT(&bcs->bcs_bnplist); - TAILQ_INSERT_TAIL(&bglobal.bg_bcslist, bcs, bcs_entry); - - return bcs; -} - -static void control_free(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - struct bfd_notify_peer *bnp; - - event_cancel(&(bcs->bcs_ev)); - event_cancel(&(bcs->bcs_outev)); - - close(bcs->bcs_sd); - - TAILQ_REMOVE(&bglobal.bg_bcslist, bcs, bcs_entry); - - /* Empty output queue. */ - while (!TAILQ_EMPTY(&bcs->bcs_bcqueue)) { - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - control_queue_free(bcs, bcq); - } - - /* Empty notification list. */ - while (!TAILQ_EMPTY(&bcs->bcs_bnplist)) { - bnp = TAILQ_FIRST(&bcs->bcs_bnplist); - control_notifypeer_free(bcs, bnp); - } - - control_reset_buf(&bcs->bcs_bin); - XFREE(MTYPE_BFDD_CONTROL, bcs); -} - -struct bfd_notify_peer *control_notifypeer_new(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_notify_peer *bnp; - - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - return bnp; - - bnp = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*bnp)); - - TAILQ_INSERT_TAIL(&bcs->bcs_bnplist, bnp, bnp_entry); - bnp->bnp_bs = bs; - bs->refcount++; - - return bnp; -} - -static void control_notifypeer_free(struct bfd_control_socket *bcs, - struct bfd_notify_peer *bnp) -{ - TAILQ_REMOVE(&bcs->bcs_bnplist, bnp, bnp_entry); - bnp->bnp_bs->refcount--; - XFREE(MTYPE_BFDD_CONTROL, bnp); -} - -struct bfd_notify_peer *control_notifypeer_find(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_notify_peer *bnp; - - TAILQ_FOREACH (bnp, &bcs->bcs_bnplist, bnp_entry) { - if (bnp->bnp_bs == bs) - return bnp; - } - - return NULL; -} - -struct bfd_control_queue *control_queue_new(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - - bcq = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*bcq)); - - control_reset_buf(&bcq->bcq_bcb); - TAILQ_INSERT_TAIL(&bcs->bcs_bcqueue, bcq, bcq_entry); - - return bcq; -} - -static void control_queue_free(struct bfd_control_socket *bcs, - struct bfd_control_queue *bcq) -{ - control_reset_buf(&bcq->bcq_bcb); - TAILQ_REMOVE(&bcs->bcs_bcqueue, bcq, bcq_entry); - XFREE(MTYPE_BFDD_NOTIFICATION, bcq); -} - -static int control_queue_dequeue(struct bfd_control_socket *bcs) -{ - struct bfd_control_queue *bcq; - - /* List is empty, nothing to do. */ - if (TAILQ_EMPTY(&bcs->bcs_bcqueue)) - goto empty_list; - - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - control_queue_free(bcs, bcq); - - /* Get the next buffer to send. */ - if (TAILQ_EMPTY(&bcs->bcs_bcqueue)) - goto empty_list; - - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - bcs->bcs_bout = &bcq->bcq_bcb; - - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - - return 1; - -empty_list: - event_cancel(&(bcs->bcs_outev)); - bcs->bcs_bout = NULL; - return 0; -} - -static int control_queue_enqueue(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - struct bfd_control_queue *bcq; - struct bfd_control_buffer *bcb; - - bcq = control_queue_new(bcs); - - bcb = &bcq->bcq_bcb; - bcb->bcb_left = sizeof(struct bfd_control_msg) + ntohl(bcm->bcm_length); - bcb->bcb_pos = 0; - bcb->bcb_bcm = bcm; - - /* If this is the first item, then dequeue and start using it. */ - if (bcs->bcs_bout == NULL) { - bcs->bcs_bout = bcb; - - /* New messages, active write events. */ - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - } - - return 0; -} - -static int control_queue_enqueue_first(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - struct bfd_control_queue *bcq, *bcqn; - struct bfd_control_buffer *bcb; - - /* Enqueue it somewhere. */ - if (control_queue_enqueue(bcs, bcm) == -1) - return -1; - - /* - * The item is either the first or the last. So we must first - * check the best case where the item is already the first. - */ - bcq = TAILQ_FIRST(&bcs->bcs_bcqueue); - bcb = &bcq->bcq_bcb; - if (bcm == bcb->bcb_bcm) - return 0; - - /* - * The item was not the first, so it is the last. We'll try to - * assign it to the head of the queue, however if there is a - * transfer in progress, then we have to make the item as the - * next one. - * - * Interrupting the transfer of in progress message will cause - * the client to lose track of the message position/data. - */ - bcqn = TAILQ_LAST(&bcs->bcs_bcqueue, bcqueue); - TAILQ_REMOVE(&bcs->bcs_bcqueue, bcqn, bcq_entry); - if (bcb->bcb_pos != 0) { - /* - * First position is already being sent, insert into - * second position. - */ - TAILQ_INSERT_AFTER(&bcs->bcs_bcqueue, bcq, bcqn, bcq_entry); - } else { - /* - * Old message didn't start being sent, we still have - * time to put this one in the head of the queue. - */ - TAILQ_INSERT_HEAD(&bcs->bcs_bcqueue, bcqn, bcq_entry); - bcb = &bcqn->bcq_bcb; - bcs->bcs_bout = bcb; - } - - return 0; -} - -static void control_reset_buf(struct bfd_control_buffer *bcb) -{ - /* Get ride of old data. */ - XFREE(MTYPE_BFDD_NOTIFICATION, bcb->bcb_buf); - bcb->bcb_pos = 0; - bcb->bcb_left = 0; -} - -static void control_read(struct event *t) -{ - struct bfd_control_socket *bcs = EVENT_ARG(t); - struct bfd_control_buffer *bcb = &bcs->bcs_bin; - int sd = bcs->bcs_sd; - struct bfd_control_msg bcm; - ssize_t bread; - size_t plen; - - /* - * Check if we have already downloaded message content, if so then skip - * to - * download the rest of it and process. - * - * Otherwise download a new message header and allocate the necessary - * memory. - */ - if (bcb->bcb_buf != NULL) - goto skip_header; - - bread = read(sd, &bcm, sizeof(bcm)); - if (bread == 0) { - control_free(bcs); - return; - } - if (bread < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - goto schedule_next_read; - - zlog_warn("%s: read: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - /* Validate header fields. */ - plen = ntohl(bcm.bcm_length); - if (plen < 2) { - zlog_debug("%s: client closed due small message length: %d", - __func__, bcm.bcm_length); - control_free(bcs); - return; - } - -#define FRR_BFD_MAXLEN 10 * 1024 - - if (plen > FRR_BFD_MAXLEN) { - zlog_debug("%s: client closed, invalid message length: %d", - __func__, bcm.bcm_length); - control_free(bcs); - return; - } - - if (bcm.bcm_ver != BMV_VERSION_1) { - zlog_debug("%s: client closed due bad version: %d", __func__, - bcm.bcm_ver); - control_free(bcs); - return; - } - - /* Prepare the buffer to load the message. */ - bcs->bcs_version = bcm.bcm_ver; - bcs->bcs_type = bcm.bcm_type; - - bcb->bcb_pos = sizeof(bcm); - bcb->bcb_left = plen; - bcb->bcb_buf = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(bcm) + bcb->bcb_left + 1); - if (bcb->bcb_buf == NULL) { - zlog_warn("%s: not enough memory for message size: %zu", - __func__, bcb->bcb_left); - control_free(bcs); - return; - } - - memcpy(bcb->bcb_buf, &bcm, sizeof(bcm)); - - /* Terminate data string with NULL for later processing. */ - bcb->bcb_buf[sizeof(bcm) + bcb->bcb_left] = 0; - -skip_header: - /* Download the remaining data of the message and process it. */ - bread = read(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); - if (bread == 0) { - control_free(bcs); - return; - } - if (bread < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) - goto schedule_next_read; - - zlog_warn("%s: read: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - bcb->bcb_pos += bread; - bcb->bcb_left -= bread; - /* We need more data, return to wait more. */ - if (bcb->bcb_left > 0) - goto schedule_next_read; - - switch (bcb->bcb_bcm->bcm_type) { - case BMT_REQUEST_ADD: - control_handle_request_add(bcs, bcb->bcb_bcm); - break; - case BMT_REQUEST_DEL: - control_handle_request_del(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY: - control_handle_notify(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY_ADD: - control_handle_notify_add(bcs, bcb->bcb_bcm); - break; - case BMT_NOTIFY_DEL: - control_handle_notify_del(bcs, bcb->bcb_bcm); - break; - - default: - zlog_debug("%s: unhandled message type: %d", __func__, - bcb->bcb_bcm->bcm_type); - control_response(bcs, bcb->bcb_bcm->bcm_id, BCM_RESPONSE_ERROR, - "invalid message type"); - break; - } - - bcs->bcs_version = 0; - bcs->bcs_type = 0; - control_reset_buf(bcb); - -schedule_next_read: - bcs->bcs_ev = NULL; - event_add_read(master, control_read, bcs, sd, &bcs->bcs_ev); -} - -static void control_write(struct event *t) -{ - struct bfd_control_socket *bcs = EVENT_ARG(t); - struct bfd_control_buffer *bcb = bcs->bcs_bout; - int sd = bcs->bcs_sd; - ssize_t bwrite; - - bwrite = write(sd, &bcb->bcb_buf[bcb->bcb_pos], bcb->bcb_left); - if (bwrite == 0) { - control_free(bcs); - return; - } - if (bwrite < 0) { - if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - return; - } - - zlog_warn("%s: write: %s", __func__, strerror(errno)); - control_free(bcs); - return; - } - - bcb->bcb_pos += bwrite; - bcb->bcb_left -= bwrite; - if (bcb->bcb_left > 0) { - bcs->bcs_outev = NULL; - event_add_write(master, control_write, bcs, bcs->bcs_sd, - &bcs->bcs_outev); - return; - } - - control_queue_dequeue(bcs); -} - - -/* - * Message processing - */ -static void control_handle_request_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_request_add(json) == 0) - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - else - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "request add failed"); -} - -static void control_handle_request_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_request_del(json) == 0) - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - else - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "request del failed"); -} - -static struct bfd_session *_notify_find_peer(struct bfd_peer_cfg *bpc) -{ - struct peer_label *pl; - - if (bpc->bpc_has_label) { - pl = pl_find(bpc->bpc_label); - if (pl) - return pl->pl_bs; - } - - return bs_peer_find(bpc); -} - -static void _control_handle_notify(struct hash_bucket *hb, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = hb->data; - - /* Notify peer configuration. */ - if (bcs->bcs_notify & BCM_NOTIFY_CONFIG) - _control_notify_config(bcs, BCM_NOTIFY_CONFIG_ADD, bs); - - /* Notify peer status. */ - if (bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) - _control_notify(bcs, bs); -} - -static void control_handle_notify(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - memcpy(&bcs->bcs_notify, bcm->bcm_data, sizeof(bcs->bcs_notify)); - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - - /* - * If peer asked for notification configuration, send everything that - * was configured until the moment to sync up. - */ - if (bcs->bcs_notify & (BCM_NOTIFY_CONFIG | BCM_NOTIFY_PEER_STATE)) - bfd_id_iterate(_control_handle_notify, bcs); -} - -static int notify_add_cb(struct bfd_peer_cfg *bpc, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = _notify_find_peer(bpc); - - if (bs == NULL) - return -1; - - control_notifypeer_new(bcs, bs); - - /* Notify peer status. */ - _control_notify(bcs, bs); - - return 0; -} - -static int notify_del_cb(struct bfd_peer_cfg *bpc, void *arg) -{ - struct bfd_control_socket *bcs = arg; - struct bfd_session *bs = _notify_find_peer(bpc); - struct bfd_notify_peer *bnp; - - if (bs == NULL) - return -1; - - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - control_notifypeer_free(bcs, bnp); - - return 0; -} - -static void control_handle_notify_add(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_notify_request(bcs, json, notify_add_cb) == 0) { - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - return; - } - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "failed to parse notify data"); -} - -static void control_handle_notify_del(struct bfd_control_socket *bcs, - struct bfd_control_msg *bcm) -{ - const char *json = (const char *)bcm->bcm_data; - - if (config_notify_request(bcs, json, notify_del_cb) == 0) { - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_OK, NULL); - return; - } - - control_response(bcs, bcm->bcm_id, BCM_RESPONSE_ERROR, - "failed to parse notify data"); -} - - -/* - * Internal functions used by the BFD daemon. - */ -static void control_response(struct bfd_control_socket *bcs, uint16_t id, - const char *status, const char *error) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_response(status, error); - if (jsonstr == NULL) { - zlog_warn("%s: config_response: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_RESPONSE; - bcm->bcm_id = id; - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue_first(bcs, bcm); -} - -static void _control_notify(struct bfd_control_socket *bcs, - struct bfd_session *bs) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_notify(bs); - if (jsonstr == NULL) { - zlog_warn("%s: config_notify: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_NOTIFY; - bcm->bcm_id = htons(BCM_NOTIFY_ID); - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue(bcs, bcm); -} - -int control_notify(struct bfd_session *bs, uint8_t notify_state) -{ - struct bfd_control_socket *bcs; - struct bfd_notify_peer *bnp; - - /* Notify zebra listeners as well. */ - ptm_bfd_notify(bs, notify_state); - - /* - * PERFORMANCE: reuse the bfd_control_msg allocated data for - * all control sockets to avoid wasting memory. - */ - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - /* - * Test for all notifications first, then search for - * specific peers. - */ - if ((bcs->bcs_notify & BCM_NOTIFY_PEER_STATE) == 0) { - bnp = control_notifypeer_find(bcs, bs); - /* - * If the notification is not configured here, - * don't send it. - */ - if (bnp == NULL) - continue; - } - - _control_notify(bcs, bs); - } - - return 0; -} - -static void _control_notify_config(struct bfd_control_socket *bcs, - const char *op, struct bfd_session *bs) -{ - struct bfd_control_msg *bcm; - char *jsonstr; - size_t jsonstrlen; - - /* Generate JSON response. */ - jsonstr = config_notify_config(op, bs); - if (jsonstr == NULL) { - zlog_warn("%s: config_notify_config: failed to get JSON str", - __func__); - return; - } - - /* Allocate data and answer. */ - jsonstrlen = strlen(jsonstr); - bcm = XMALLOC(MTYPE_BFDD_NOTIFICATION, - sizeof(struct bfd_control_msg) + jsonstrlen); - - bcm->bcm_length = htonl(jsonstrlen); - bcm->bcm_ver = BMV_VERSION_1; - bcm->bcm_type = BMT_NOTIFY; - bcm->bcm_id = htons(BCM_NOTIFY_ID); - memcpy(bcm->bcm_data, jsonstr, jsonstrlen); - XFREE(MTYPE_BFDD_NOTIFICATION, jsonstr); - - control_queue_enqueue(bcs, bcm); -} - -int control_notify_config(const char *op, struct bfd_session *bs) -{ - struct bfd_control_socket *bcs; - struct bfd_notify_peer *bnp; - - /* Remove the control sockets notification for this peer. */ - if (strcmp(op, BCM_NOTIFY_CONFIG_DELETE) == 0 && bs->refcount > 0) { - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - bnp = control_notifypeer_find(bcs, bs); - if (bnp) - control_notifypeer_free(bcs, bnp); - } - } - - /* - * PERFORMANCE: reuse the bfd_control_msg allocated data for - * all control sockets to avoid wasting memory. - */ - TAILQ_FOREACH (bcs, &bglobal.bg_bcslist, bcs_entry) { - /* - * Test for all notifications first, then search for - * specific peers. - */ - if ((bcs->bcs_notify & BCM_NOTIFY_CONFIG) == 0) - continue; - - _control_notify_config(bcs, op, bs); - } - - return 0; -} diff --git a/bfdd/dplane.c b/bfdd/dplane.c index d8539812e0..7f55f34073 100644 --- a/bfdd/dplane.c +++ b/bfdd/dplane.c @@ -354,7 +354,7 @@ bfd_dplane_session_state_change(struct bfd_dplane_ctx *bdc, bs->remote_timers.required_min_echo = ntohl(state->required_echo_rx); /* Notify and update counters. */ - control_notify(bs, bs->ses_state); + ptm_bfd_notify(bs, bs->ses_state); /* No state change. */ if (old_state == bs->ses_state) diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index b5ab2ef1d0..f6ebefb7be 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -148,7 +148,6 @@ static void _ptm_bfd_session_del(struct bfd_session *bs, uint8_t diag) "ptm-del-session: [%s] session refcount is zero but it was configured by CLI", bs_to_string(bs)); } else { - control_notify_config(BCM_NOTIFY_CONFIG_DELETE, bs); bfd_session_free(bs); } } @@ -892,7 +891,7 @@ static struct ptm_client *pc_new(uint32_t pid) return pc; /* Allocate the client data and save it. */ - pc = XCALLOC(MTYPE_BFDD_CONTROL, sizeof(*pc)); + pc = XCALLOC(MTYPE_BFDD_CLIENT, sizeof(*pc)); pc->pc_pid = pid; TAILQ_INSERT_HEAD(&pcqueue, pc, pc_entry); @@ -910,7 +909,7 @@ static void pc_free(struct ptm_client *pc) pcn_free(pcn); } - XFREE(MTYPE_BFDD_CONTROL, pc); + XFREE(MTYPE_BFDD_CLIENT, pc); } static void pc_free_all(void) @@ -934,7 +933,7 @@ static struct ptm_client_notification *pcn_new(struct ptm_client *pc, return pcn; /* Save the client notification data. */ - pcn = XCALLOC(MTYPE_BFDD_NOTIFICATION, sizeof(*pcn)); + pcn = XCALLOC(MTYPE_BFDD_CLIENT_NOTIFICATION, sizeof(*pcn)); TAILQ_INSERT_HEAD(&pc->pc_pcnqueue, pcn, pcn_entry); pcn->pcn_pc = pc; @@ -982,5 +981,5 @@ static void pcn_free(struct ptm_client_notification *pcn) pcn->pcn_pc = NULL; TAILQ_REMOVE(&pc->pc_pcnqueue, pcn, pcn_entry); - XFREE(MTYPE_BFDD_NOTIFICATION, pcn); + XFREE(MTYPE_BFDD_CLIENT_NOTIFICATION, pcn); } diff --git a/bfdd/subdir.am b/bfdd/subdir.am index b86a18967e..5d2d8fda5c 100644 --- a/bfdd/subdir.am +++ b/bfdd/subdir.am @@ -17,8 +17,6 @@ bfdd_libbfd_a_SOURCES = \ bfdd/bfdd_vty.c \ bfdd/bfdd_cli.c \ bfdd/bfd_packet.c \ - bfdd/config.c \ - bfdd/control.c \ bfdd/dplane.c \ bfdd/event.c \ bfdd/ptm_adapter.c \ @@ -37,7 +35,6 @@ clippy_scan += \ # end noinst_HEADERS += \ - bfdd/bfdctl.h \ bfdd/bfdd_nb.h \ bfdd/bfd.h \ # end diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index e4ee589a38..ac5d08b6fe 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -2575,7 +2575,6 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) struct peer *const peer = args->peer; struct attr *const attr = args->attr; const bgp_size_t length = args->length; - uint8_t sticky = 0; bool proxy = false; struct ecommunity *ecomm; @@ -2605,21 +2604,20 @@ bgp_attr_ext_communities(struct bgp_attr_parser_args *args) attr->df_pref = bgp_attr_df_pref_from_ec(attr, &attr->df_alg); /* Extract MAC mobility sequence number, if any. */ - attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr, &sticky); - attr->sticky = sticky; + attr->mm_seqnum = bgp_attr_mac_mobility_seqnum(attr); /* Check if this is a Gateway MAC-IP advertisement */ - attr->default_gw = bgp_attr_default_gw(attr); + bgp_attr_default_gw(attr); /* Handle scenario where router flag ecommunity is not * set but default gw ext community is present. * Use default gateway, set and propogate R-bit. */ - if (attr->default_gw) - attr->router_flag = 1; + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER); /* Check EVPN Neighbor advertisement flags, R-bit */ - bgp_attr_evpn_na_flag(attr, &attr->router_flag, &proxy); + bgp_attr_evpn_na_flag(attr, &proxy); if (proxy) attr->es_flags |= ATTR_ES_PROXY_ADVERT; @@ -4476,6 +4474,8 @@ bgp_size_t bgp_packet_attribute(struct bgp *bgp, struct peer *peer, bgp_packet_mpattr_end(s, mpattrlen_pos); } + (void)peer_sort(peer); + /* Origin attribute. */ stream_putc(s, BGP_ATTR_FLAG_TRANS); stream_putc(s, BGP_ATTR_ORIGIN); diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index f353e76913..561024e7c8 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -197,9 +197,6 @@ struct attr { #define ATTR_ES_L3_NHG_ACTIVE (1 << 6) #define ATTR_ES_L3_NHG (ATTR_ES_L3_NHG_USE | ATTR_ES_L3_NHG_ACTIVE) - /* NA router flag (R-bit) support in EVPN */ - uint8_t router_flag; - /* Distance as applied by Route map */ uint8_t distance; @@ -212,7 +209,7 @@ struct attr { /* has the route-map changed any attribute? Used on the peer outbound side. */ - uint32_t rmap_change_flags; + uint16_t rmap_change_flags; /* Multi-Protocol Nexthop, AFI IPv6 */ struct in6_addr mp_nexthop_global; @@ -256,11 +253,12 @@ struct attr { /* MP Nexthop length */ uint8_t mp_nexthop_len; - /* Static MAC for EVPN */ - uint8_t sticky; - - /* Flag for default gateway extended community in EVPN */ - uint8_t default_gw; + /* EVPN flags */ + uint8_t evpn_flags; +#define ATTR_EVPN_FLAG_STICKY (1 << 0) +#define ATTR_EVPN_FLAG_DEFAULT_GW (1 << 1) +/* NA router flag (R-bit) support in EVPN */ +#define ATTR_EVPN_FLAG_ROUTER (1 << 2) /* route tag */ route_tag_t tag; @@ -295,7 +293,7 @@ struct attr { /* EVPN local router-mac */ struct ethaddr rmac; - uint16_t encap_tunneltype; + uint8_t encap_tunneltype; /* rmap set table */ uint32_t rmap_table_id; diff --git a/bgpd/bgp_attr_evpn.c b/bgpd/bgp_attr_evpn.c index bbc4ba9525..086c36f36c 100644 --- a/bgpd/bgp_attr_evpn.c +++ b/bgpd/bgp_attr_evpn.c @@ -115,14 +115,14 @@ bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac) /* * return true if attr contains default gw extended community */ -uint8_t bgp_attr_default_gw(struct attr *attr) +void bgp_attr_default_gw(struct attr *attr) { struct ecommunity *ecom; uint32_t i; ecom = bgp_attr_get_ecommunity(attr); if (!ecom || !ecom->size) - return 0; + return; /* If there is a default gw extendd community return true otherwise * return 0 */ @@ -136,10 +136,9 @@ uint8_t bgp_attr_default_gw(struct attr *attr) if ((type == ECOMMUNITY_ENCODE_OPAQUE && sub_type == ECOMMUNITY_EVPN_SUBTYPE_DEF_GW)) - return 1; + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } - - return 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); } /* @@ -183,7 +182,7 @@ uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg) * Fetch and return the sequence number from MAC Mobility extended * community, if present, else 0. */ -uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) +uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr) { struct ecommunity *ecom; uint32_t i; @@ -213,9 +212,9 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) flags = *pnt++; if (flags & ECOMMUNITY_EVPN_SUBTYPE_MACMOBILITY_FLAG_STICKY) - *sticky = 1; + SET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); else - *sticky = 0; + UNSET_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY); pnt++; pnt = ptr_get_be32(pnt, &seq_num); @@ -229,8 +228,7 @@ uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, uint8_t *sticky) /* * return true if attr contains router flag extended community */ -void bgp_attr_evpn_na_flag(struct attr *attr, - uint8_t *router_flag, bool *proxy) +void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy) { struct ecommunity *ecom; uint32_t i; @@ -254,7 +252,8 @@ void bgp_attr_evpn_na_flag(struct attr *attr, val = *pnt++; if (val & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG) - *router_flag = 1; + SET_FLAG(attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER); if (val & ECOMMUNITY_EVPN_SUBTYPE_PROXY_FLAG) *proxy = true; diff --git a/bgpd/bgp_attr_evpn.h b/bgpd/bgp_attr_evpn.h index f8d3978b96..e12fc3a86c 100644 --- a/bgpd/bgp_attr_evpn.h +++ b/bgpd/bgp_attr_evpn.h @@ -36,12 +36,10 @@ extern void bgp_add_routermac_ecom(struct attr *attr, extern int bgp_build_evpn_prefix(int type, uint32_t eth_tag, struct prefix *dst); extern bool bgp_attr_rmac(struct attr *attr, struct ethaddr *rmac); -extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr, - uint8_t *sticky); -extern uint8_t bgp_attr_default_gw(struct attr *attr); +extern uint32_t bgp_attr_mac_mobility_seqnum(struct attr *attr); +extern void bgp_attr_default_gw(struct attr *attr); -extern void bgp_attr_evpn_na_flag(struct attr *attr, uint8_t *router_flag, - bool *proxy); +extern void bgp_attr_evpn_na_flag(struct attr *attr, bool *proxy); extern uint16_t bgp_attr_df_pref_from_ec(struct attr *attr, uint8_t *alg); diff --git a/bgpd/bgp_evpn.c b/bgpd/bgp_evpn.c index e660ca5c16..55896ee7ea 100644 --- a/bgpd/bgp_evpn.c +++ b/bgpd/bgp_evpn.c @@ -1159,9 +1159,8 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add MAC mobility (sticky) if needed. */ - if (attr->sticky) { + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_STICKY)) { seqnum = 0; - memset(&ecom_sticky, 0, sizeof(ecom_sticky)); encode_mac_mobility_extcomm(1, seqnum, &eval_sticky); ecom_sticky.size = 1; ecom_sticky.unit_size = ECOMMUNITY_SIZE; @@ -1179,8 +1178,7 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } /* Add default gateway, if needed. */ - if (attr->default_gw) { - memset(&ecom_default_gw, 0, sizeof(ecom_default_gw)); + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { encode_default_gw_extcomm(&eval_default_gw); ecom_default_gw.size = 1; ecom_default_gw.unit_size = ECOMMUNITY_SIZE; @@ -1191,9 +1189,11 @@ static void build_evpn_route_extcomm(struct bgpevpn *vpn, struct attr *attr, } proxy = !!(attr->es_flags & ATTR_ES_PROXY_ADVERT); - if (attr->router_flag || proxy) { - memset(&ecom_na, 0, sizeof(ecom_na)); - encode_na_flag_extcomm(&eval_na, attr->router_flag, proxy); + if (CHECK_FLAG(attr->evpn_flags, ATTR_EVPN_FLAG_ROUTER) || proxy) { + encode_na_flag_extcomm(&eval_na, + CHECK_FLAG(attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER), + proxy); ecom_na.size = 1; ecom_na.unit_size = ECOMMUNITY_SIZE; ecom_na.val = (uint8_t *)eval_na.val; @@ -1278,12 +1278,15 @@ enum zclient_send_status evpn_zebra_install(struct bgp *bgp, struct bgpevpn *vpn flags = 0; if (pi->sub_type == BGP_ROUTE_IMPORTED) { - if (pi->attr->sticky) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_STICKY)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY); - if (pi->attr->default_gw) + if (CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_DEFAULT_GW)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_GW); if (is_evpn_prefix_ipaddr_v6(p) && - pi->attr->router_flag) + CHECK_FLAG(pi->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) SET_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG); seq = mac_mobility_seqnum(pi->attr); @@ -1840,7 +1843,8 @@ static void bgp_evpn_get_sync_info(struct bgp *bgp, esi_t *esi, *active_on_peer = true; } - if (second_best_path->attr->router_flag) + if (CHECK_FLAG(second_best_path->attr->evpn_flags, + ATTR_EVPN_FLAG_ROUTER)) *peer_router = true; /* we use both proxy and non-proxy imports to @@ -1940,7 +1944,6 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, struct attr local_attr; struct bgp_labels bgp_labels = {}; int route_change = 1; - uint8_t sticky = 0; const struct prefix_evpn *evp; *pi = NULL; @@ -1972,9 +1975,7 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, local_attr = *attr; /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = - bgp_attr_mac_mobility_seqnum(&local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum(&local_attr); /* Add (or update) attribute to hash. */ attr_new = bgp_attr_intern(&local_attr); @@ -2069,9 +2070,8 @@ static int update_evpn_route_entry(struct bgp *bgp, struct bgpevpn *vpn, BGP_PATH_ATTR_CHANGED); /* Extract MAC mobility sequence number, if any. */ - local_attr.mm_seqnum = bgp_attr_mac_mobility_seqnum( - &local_attr, &sticky); - local_attr.sticky = sticky; + local_attr.mm_seqnum = + bgp_attr_mac_mobility_seqnum(&local_attr); attr_new = bgp_attr_intern(&local_attr); @@ -2204,10 +2204,12 @@ static int update_evpn_route(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY) ? 1 : 0; - attr.default_gw = CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW) ? 1 : 0; - attr.router_flag = CHECK_FLAG(flags, - ZEBRA_MACIP_TYPE_ROUTER_FLAG) ? 1 : 0; + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_STICKY); + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_GW)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); + if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_ROUTER_FLAG)) + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); if (CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_PROXY_ADVERT)) attr.es_flags |= ATTR_ES_PROXY_ADVERT; @@ -2509,13 +2511,12 @@ void bgp_evpn_update_type2_route_entry(struct bgp *bgp, struct bgpevpn *vpn, attr.nexthop = vpn->originator_ip; attr.mp_nexthop_global_in = vpn->originator_ip; attr.mp_nexthop_len = BGP_ATTR_NHLEN_IPV4; - attr.sticky = (local_pi->attr->sticky) ? 1 : 0; - attr.router_flag = (local_pi->attr->router_flag) ? 1 : 0; + attr.evpn_flags = local_pi->attr->evpn_flags; attr.es_flags = local_pi->attr->es_flags; - if (local_pi->attr->default_gw) { - attr.default_gw = 1; + if (CHECK_FLAG(local_pi->attr->evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW)) { + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_DEFAULT_GW); if (is_evpn_prefix_ipaddr_v6(&evp)) - attr.router_flag = 1; + SET_FLAG(attr.evpn_flags, ATTR_EVPN_FLAG_ROUTER); } memcpy(&attr.esi, &local_pi->attr->esi, sizeof(esi_t)); bgp_evpn_get_rmac_nexthop(vpn, &evp, &attr, diff --git a/bgpd/bgp_evpn_private.h b/bgpd/bgp_evpn_private.h index 07bba9b426..b05df3d82a 100644 --- a/bgpd/bgp_evpn_private.h +++ b/bgpd/bgp_evpn_private.h @@ -382,7 +382,7 @@ static inline void encode_mac_mobility_extcomm(int static_mac, uint32_t seq, } static inline void encode_na_flag_extcomm(struct ecommunity_val *eval, - uint8_t na_flag, bool proxy) + bool na_flag, bool proxy) { memset(eval, 0, sizeof(*eval)); eval->val[0] = ECOMMUNITY_ENCODE_EVPN; diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index 846a82ba90..c28cdb4a65 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -4840,7 +4840,7 @@ DEFUN(show_bgp_l2vpn_evpn_summary, show_bgp_l2vpn_evpn_summary_cmd, char *vrf = NULL; char *neighbor = NULL; as_t as = 0; /* 0 means AS filter not set */ - int as_type = AS_UNSPECIFIED; + enum peer_asn_type as_type = AS_UNSPECIFIED; uint16_t show_flags = 0; if (argv_find(argv, argc, "vrf", &idx_vrf)) diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index d41ef8abba..98ebf51385 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -602,6 +602,7 @@ const char *const peer_down_str[] = { "Socket Error", "Admin. shutdown (RTT)", "Suppress Fib Turned On or Off", + "Password config change", }; static void bgp_graceful_restart_timer_off(struct peer_connection *connection, @@ -1482,7 +1483,7 @@ enum bgp_fsm_state_progress bgp_stop(struct peer_connection *connection) EVENT_OFF(connection->t_connect); EVENT_OFF(connection->t_holdtime); EVENT_OFF(connection->t_routeadv); - EVENT_OFF(peer->connection->t_delayopen); + EVENT_OFF(connection->t_delayopen); /* Clear input and output buffer. */ frr_with_mutex (&connection->io_mtx) { @@ -2046,9 +2047,10 @@ static int bgp_start_deferral_timer(struct bgp *bgp, afi_t afi, safi_t safi, } gr_info->eor_required++; /* Send message to RIB indicating route update pending */ - if (gr_info->af_enabled[afi][safi] == false) { - gr_info->af_enabled[afi][safi] = true; - /* Send message to RIB */ + if (gr_info->af_enabled == false) { + gr_info->af_enabled = true; + gr_info->route_sync = false; + bgp->gr_route_sync_pending = true; bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_PENDING); } @@ -2082,7 +2084,7 @@ static int bgp_update_gr_info(struct peer *peer, afi_t afi, safi_t safi) if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer)) { /* Check if the forwarding state is preserved */ - if (CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)) { + if (bgp_gr_is_forwarding_preserved(bgp)) { gr_info = &(bgp->gr_info[afi][safi]); ret = bgp_start_deferral_timer(bgp, afi, safi, gr_info); } @@ -2199,8 +2201,7 @@ bgp_establish(struct peer_connection *connection) } else { if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && BGP_PEER_RESTARTING_MODE(peer) && - CHECK_FLAG(peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) + bgp_gr_is_forwarding_preserved(peer->bgp)) peer->bgp->gr_info[afi][safi] .eor_required++; } @@ -2695,53 +2696,61 @@ int bgp_event_update(struct peer_connection *connection, } /* BGP GR Code */ -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state) +static inline void +bgp_peer_inherit_global_gr_mode(struct peer *peer, + enum global_mode global_gr_mode) +{ + switch (global_gr_mode) { + case GLOBAL_HELPER: + BGP_PEER_GR_HELPER_ENABLE(peer); + break; + case GLOBAL_GR: + BGP_PEER_GR_ENABLE(peer); + break; + case GLOBAL_DISABLE: + BGP_PEER_GR_DISABLE(peer); + break; + case GLOBAL_INVALID: + default: + zlog_err("Unexpected Global GR mode %d", global_gr_mode); + } +} + +static void bgp_gr_update_mode_of_all_peers(struct bgp *bgp, + enum global_mode global_new_state) { struct peer *peer = {0}; struct listnode *node = {0}; struct listnode *nnode = {0}; enum peer_mode peer_old_state = PEER_INVALID; - for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] Peer: (%s) :", __func__, - peer->host); + /* TODO: Need to handle peer-groups. */ + for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { peer_old_state = bgp_peer_gr_mode_get(peer); + if (peer_old_state != PEER_GLOBAL_INHERIT) + continue; - if (peer_old_state == PEER_GLOBAL_INHERIT) { + bgp_peer_inherit_global_gr_mode(peer, global_new_state); + bgp_peer_gr_flags_update(peer); - /* - *Reset only these peers and send a - *new open message with the change capabilities. - *Considering the mode to be "global_new_state" and - *do all operation accordingly - */ - - switch (global_new_state) { - case GLOBAL_HELPER: - BGP_PEER_GR_HELPER_ENABLE(peer); - break; - case GLOBAL_GR: - BGP_PEER_GR_ENABLE(peer); - break; - case GLOBAL_DISABLE: - BGP_PEER_GR_DISABLE(peer); - break; - case GLOBAL_INVALID: - zlog_debug("%s [BGP_GR] GLOBAL_INVALID", - __func__); - return BGP_ERR_GR_OPERATION_FAILED; - } - } - } + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%pBP: Inherited Global GR mode, GR flags 0x%x peer flags 0x%" PRIx64 + "...resetting session", + peer, peer->peer_gr_new_status_flag, + peer->flags); - bgp->global_gr_present_state = global_new_state; + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - return BGP_GR_SUCCESS; + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. + */ + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset_safe(peer, &nnode); + } } int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) @@ -2749,46 +2758,27 @@ int bgp_gr_update_all(struct bgp *bgp, enum global_gr_command global_gr_cmd) enum global_mode global_new_state = GLOBAL_INVALID; enum global_mode global_old_state = GLOBAL_INVALID; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR]START: global_gr_cmd :%s:", __func__, - print_global_gr_cmd(global_gr_cmd)); - global_old_state = bgp_global_gr_mode_get(bgp); + global_new_state = bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_old_gr_state :%s:", - print_global_gr_mode(global_old_state)); + zlog_debug("%s: Handle GR command %s, current GR state %s, new GR state %s", + bgp->name_pretty, print_global_gr_cmd(global_gr_cmd), + print_global_gr_mode(global_old_state), + print_global_gr_mode(global_new_state)); - if (global_old_state != GLOBAL_INVALID) { - global_new_state = - bgp->GLOBAL_GR_FSM[global_old_state][global_gr_cmd]; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] global_new_gr_state :%s:", - print_global_gr_mode(global_new_state)); - } else { - zlog_err("%s [BGP_GR] global_old_state == GLOBAL_INVALID", - __func__); + if (global_old_state == GLOBAL_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - } - - if (global_new_state == GLOBAL_INVALID) { - zlog_err("%s [BGP_GR] global_new_state == GLOBAL_INVALID", - __func__); + if (global_new_state == GLOBAL_INVALID) return BGP_ERR_GR_INVALID_CMD; - } - if (global_new_state == global_old_state) { - /* Trace msg */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] global_new_state == global_old_state :%s", - __func__, - print_global_gr_mode(global_new_state)); + if (global_new_state == global_old_state) return BGP_GR_NO_OPERATION; - } - return bgp_gr_lookup_n_update_all_peer(bgp, global_new_state, - global_old_state); + /* Update global GR mode and process all peers in instance. */ + bgp->global_gr_present_state = global_new_state; + bgp_gr_update_mode_of_all_peers(bgp, global_new_state); + + return BGP_GR_SUCCESS; } const char *print_peer_gr_mode(enum peer_mode pr_mode) @@ -2903,179 +2893,102 @@ int bgp_neighbor_graceful_restart(struct peer *peer, { enum peer_mode peer_new_state = PEER_INVALID; enum peer_mode peer_old_state = PEER_INVALID; - struct bgp_peer_gr peer_state; + struct bgp_peer_gr gr_fsm; int result = BGP_GR_FAILURE; - /* - * fetch peer_old_state from peer structure also - * fetch global_old_state from bgp structure, - * peer had a back pointer to bgpo struct ; - */ - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] START:Peer: (%s) : peer_gr_cmd :%s:", - __func__, peer->host, - print_peer_gr_cmd(peer_gr_cmd)); - peer_old_state = bgp_peer_gr_mode_get(peer); + gr_fsm = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; + peer_new_state = gr_fsm.next_state; if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] peer_old_state: %d", __func__, - peer_old_state); + zlog_debug("%pBP: Handle GR command %s, current GR state %s, new GR state %s", + peer, print_peer_gr_cmd(peer_gr_cmd), + print_peer_gr_mode(peer_old_state), + print_peer_gr_mode(peer_new_state)); if (peer_old_state == PEER_INVALID) return BGP_ERR_GR_OPERATION_FAILED; - peer_state = peer->PEER_GR_FSM[peer_old_state][peer_gr_cmd]; - peer_new_state = peer_state.next_state; - - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] peer_new_state: %d", __func__, - peer_new_state); - if (peer_new_state == PEER_INVALID) return BGP_ERR_GR_INVALID_CMD; - if (peer_new_state != peer_old_state) { - result = peer_state.action_fun(peer, peer_old_state, - peer_new_state); - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] peer_old_state == peer_new_state !"); + if (peer_new_state == peer_old_state) return BGP_GR_NO_OPERATION; - } - - if (result == BGP_GR_SUCCESS) { - - /* Update the mode i.e peer_new_state into the peer structure */ - peer->peer_gr_present_state = peer_new_state; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Successfully change the state of the peer to : %s : !", - print_peer_gr_mode(peer_new_state)); - return BGP_GR_SUCCESS; - } + result = gr_fsm.action_fun(peer, peer_old_state, peer_new_state); return result; } -unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, - enum peer_mode new_peer_state) +static inline bool gr_mode_matches(enum peer_mode peer_gr_mode, + enum global_mode global_gr_mode) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "%s [BGP_GR] Move peer from old_peer_state :%s: to new_peer_state :%s: !!!!", - __func__, print_peer_gr_mode(old_peer_state), - print_peer_gr_mode(new_peer_state)); + if ((peer_gr_mode == PEER_HELPER && global_gr_mode == GLOBAL_HELPER) || + (peer_gr_mode == PEER_GR && global_gr_mode == GLOBAL_GR) || + (peer_gr_mode == PEER_DISABLE && global_gr_mode == GLOBAL_DISABLE)) + return true; + return false; +} - enum global_mode bgp_gr_global_mode = GLOBAL_INVALID; - unsigned int ret = BGP_GR_FAILURE; +unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_state, + enum peer_mode new_state) +{ + enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + bool session_reset = true; - if (old_peer_state == new_peer_state) { - /* Nothing to do over here as the present and old state is the - * same */ + if (old_state == new_state) return BGP_GR_NO_OPERATION; - } - if ((old_peer_state == PEER_INVALID) - || (new_peer_state == PEER_INVALID)) { - /* something bad happend , print error message */ + if ((old_state == PEER_INVALID) || (new_state == PEER_INVALID)) return BGP_ERR_GR_INVALID_CMD; - } - bgp_gr_global_mode = bgp_global_gr_mode_get(peer->bgp); - - if ((old_peer_state == PEER_GLOBAL_INHERIT) - && (new_peer_state != PEER_GLOBAL_INHERIT)) { - - /* fetch the Mode running in the Global state machine - *from the bgp structure into a variable called - *bgp_gr_global_mode - */ - - /* Here we are checking if the - *1. peer_new_state == global_mode == helper_mode - *2. peer_new_state == global_mode == GR_mode - *3. peer_new_state == global_mode == disabled_mode - */ + global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + if ((old_state == PEER_GLOBAL_INHERIT) && + (new_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_UNSET(peer); - if ((int)new_peer_state == (int)bgp_gr_global_mode) { - /* This is incremental updates i.e no tear down - * of the existing session - * as the peer is already working in the same mode. + if (gr_mode_matches(new_state, global_gr_mode)) + /* Peer was inheriting the global state and + * its new state still is the same, so a + * session reset is not needed. */ - ret = BGP_GR_SUCCESS; - } else { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s ", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; - } - } - /* In the case below peer is going into Global inherit mode i.e. - * the peer would work as the mode configured at the global level - */ - else if ((new_peer_state == PEER_GLOBAL_INHERIT) - && (old_peer_state != PEER_GLOBAL_INHERIT)) { - /* Here in this case it would be destructive - * in all the cases except one case when, - * Global GR is configured Disabled - * and present_peer_state is not disable - */ - + session_reset = false; + } else if ((new_state == PEER_GLOBAL_INHERIT) && + (old_state != PEER_GLOBAL_INHERIT)) { BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - if ((int)old_peer_state == (int)bgp_gr_global_mode) { - /* This is incremental updates - *i.e no tear down of the existing session - *as the peer is already working in the same mode. - */ - ret = BGP_GR_SUCCESS; - } else { - /* Destructive always */ - /* Tear down the old session - * and send the new capability - * as per the bgp_gr_global_mode + if (gr_mode_matches(old_state, global_gr_mode)) + /* Peer is inheriting the global state and + * its old state was also the same, so a + * session reset is not needed. */ + session_reset = false; + } - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); + /* Ensure we move to the new state and update flags */ + bgp_peer_move_to_gr_mode(peer, new_state); - bgp_peer_move_to_gr_mode(peer, bgp_gr_global_mode); + if (session_reset) { + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - ret = BGP_GR_SUCCESS; - } - } else { - /* - *This else case, it include all the cases except --> - *(new_peer_state != Peer_Global) && - *( old_peer_state != Peer_Global ) + /* Reset session to match with behavior for other peer + * configs that require the session to be re-setup. */ - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed from :%s", - print_peer_gr_mode(old_peer_state)); - - bgp_peer_move_to_gr_mode(peer, new_peer_state); - - ret = BGP_GR_SUCCESS; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) + bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, + BGP_NOTIFY_CEASE_CONFIG_CHANGE); + else + bgp_session_reset(peer); } - return ret; + return BGP_GR_SUCCESS; } -inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state) { - int bgp_global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum global_mode global_gr_mode = bgp_global_gr_mode_get(peer->bgp); + enum peer_mode old_state = bgp_peer_gr_mode_get(peer); switch (new_state) { case PEER_HELPER: @@ -3089,57 +3002,38 @@ inline void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state) break; case PEER_GLOBAL_INHERIT: BGP_PEER_GR_GLOBAL_INHERIT_SET(peer); - - if (bgp_global_gr_mode == GLOBAL_HELPER) { - BGP_PEER_GR_HELPER_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_GR) { - BGP_PEER_GR_ENABLE(peer); - } else if (bgp_global_gr_mode == GLOBAL_DISABLE) { - BGP_PEER_GR_DISABLE(peer); - } else { - zlog_err( - "[BGP_GR] Default switch inherit mode ::: SOMETHING IS WRONG !!!"); - } + bgp_peer_inherit_global_gr_mode(peer, global_gr_mode); break; + case PEER_INVALID: default: zlog_err( "[BGP_GR] Default switch mode ::: SOMETHING IS WRONG !!!"); break; } + bgp_peer_gr_flags_update(peer); + peer->peer_gr_present_state = new_state; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Peer state changed --to--> : %d : !", - new_state); + zlog_debug("%pBP: Peer GR mode changed from %s to %s, GR flags 0x%x peer flags 0x%" PRIx64, + peer, print_peer_gr_mode(old_state), + print_peer_gr_mode(new_state), + peer->peer_gr_new_status_flag, peer->flags); } void bgp_peer_gr_flags_update(struct peer *peer) { - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("%s [BGP_GR] called !", __func__); if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_HELPER)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_HELPER : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_HELPER) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_RESTART)) SET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - ? "Set" - : "UnSet")); + if (CHECK_FLAG(peer->peer_gr_new_status_flag, PEER_GRACEFUL_RESTART_NEW_STATE_INHERIT)) SET_FLAG(peer->flags, @@ -3147,28 +3041,28 @@ void bgp_peer_gr_flags_update(struct peer *peer) else UNSET_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Peer %s Flag PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT : %s : !", - peer->host, - (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT) - ? "Set" - : "UnSet")); - - if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) - && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { - zlog_debug("[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_MODE!", - peer->host); + zlog_debug("%pBP: Peer flags updated to 0x%" PRIx64 + ", GR flags 0x%x, GR mode %s", + peer, peer->flags, peer->peer_gr_new_status_flag, + print_peer_gr_mode(bgp_peer_gr_mode_get(peer))); + /* + * If GR has been completely disabled for the peer and we were + * acting as the Helper for the peer (i.e., keeping stale routes + * and running the restart timer or stalepath timer), clear those + * states. + */ + if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) { UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) { - + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP: GR disabled, stopping NSF and clearing stale routes", + peer); peer_nsf_stop(peer); - zlog_debug( - "[BGP_GR] Peer %s UNSET PEER_STATUS_NSF_WAIT!", - peer->host); } } } diff --git a/bgpd/bgp_fsm.h b/bgpd/bgp_fsm.h index bcdd49193f..85c488962f 100644 --- a/bgpd/bgp_fsm.h +++ b/bgpd/bgp_fsm.h @@ -151,7 +151,7 @@ int bgp_neighbor_graceful_restart(struct peer *peer, enum peer_gr_command peer_gr_cmd); unsigned int bgp_peer_gr_action(struct peer *peer, enum peer_mode old_peer_state, enum peer_mode new_peer_state); -void bgp_peer_move_to_gr_mode(struct peer *peer, int new_state); +void bgp_peer_move_to_gr_mode(struct peer *peer, enum peer_mode new_state); unsigned int bgp_peer_gr_helper_enable(struct peer *peer); unsigned int bgp_peer_gr_enable(struct peer *peer); unsigned int bgp_peer_gr_global_inherit(struct peer *peer); @@ -160,9 +160,6 @@ enum peer_mode bgp_peer_gr_mode_get(struct peer *peer); enum global_mode bgp_global_gr_mode_get(struct bgp *bgp); enum peer_mode bgp_get_peer_gr_mode_from_flags(struct peer *peer); unsigned int bgp_peer_gr_global_inherit_unset(struct peer *peer); -int bgp_gr_lookup_n_update_all_peer(struct bgp *bgp, - enum global_mode global_new_state, - enum global_mode global_old_state); void bgp_peer_gr_flags_update(struct peer *peer); const char *print_peer_gr_mode(enum peer_mode pr_mode); const char *print_peer_gr_cmd(enum peer_gr_command pr_gr_cmd); diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 97658d340b..5e6a62c9b9 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -511,6 +511,7 @@ int main(int argc, char **argv) /* BGP master init. */ bgp_master_init(frr_init(), buffer_size, addresses); + bm->startup_time = monotime(NULL); bm->port = bgp_port; if (bgp_port == 0) bgp_option_set(BGP_OPT_NO_LISTEN); @@ -518,6 +519,9 @@ int main(int argc, char **argv) bgp_option_set(BGP_OPT_NO_FIB); if (no_zebra_flag) bgp_option_set(BGP_OPT_NO_ZEBRA); + if (bgpd_di.graceful_restart) + SET_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART); + bgp_error_init(); /* Initializations. */ libagentx_init(); diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index e12d84b84c..eadd52b8e0 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -605,31 +605,43 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, if (mp_node && (listgetdata(mp_node) == cur_mpath)) { list_delete_node(mp_list, mp_node); bgp_path_info_mpath_dequeue(cur_mpath); - if ((mpath_count < maxpaths) - && prev_mpath - && bgp_path_info_nexthop_cmp(prev_mpath, - cur_mpath)) { + if ((mpath_count < maxpaths) && prev_mpath) { + mpath_count++; + if (bgp_path_info_nexthop_cmp(prev_mpath, + cur_mpath)) { + if (ecommunity_linkbw_present( + bgp_attr_get_ecommunity( + cur_mpath->attr), + &bwval) || + ecommunity_linkbw_present( + bgp_attr_get_ipv6_ecommunity( + cur_mpath->attr), + &bwval)) + cum_bw += bwval; + else + all_paths_lb = false; + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + cur_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: %s is still multipath, cur count %d", + dest, path_buf, + mpath_count); + } + } else { + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + cur_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &cur_mpath->attr->nexthop, + mpath_count); + } + } bgp_path_info_mpath_enqueue(prev_mpath, cur_mpath); prev_mpath = cur_mpath; - mpath_count++; - if (ecommunity_linkbw_present(bgp_attr_get_ecommunity( - cur_mpath->attr), - &bwval) || - ecommunity_linkbw_present( - bgp_attr_get_ipv6_ecommunity( - cur_mpath->attr), - &bwval)) - cum_bw += bwval; - else - all_paths_lb = false; - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - cur_mpath, path_buf, - sizeof(path_buf)); - zlog_debug("%pBD: %s is still multipath, cur count %d", - dest, path_buf, mpath_count); - } } else { mpath_changed = 1; if (debug) { @@ -693,35 +705,50 @@ void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, list_delete_node(mp_list, mp_node); assert(new_mpath); assert(prev_mpath); - if ((mpath_count < maxpaths) && (new_mpath != new_best) - && bgp_path_info_nexthop_cmp(prev_mpath, - new_mpath)) { + if ((mpath_count < maxpaths) && (new_mpath != new_best)) { + /* keep duplicate nexthop */ bgp_path_info_mpath_dequeue(new_mpath); bgp_path_info_mpath_enqueue(prev_mpath, new_mpath); - prev_mpath = new_mpath; mpath_changed = 1; mpath_count++; - if (ecommunity_linkbw_present(bgp_attr_get_ecommunity( - new_mpath->attr), - &bwval) || - ecommunity_linkbw_present( - bgp_attr_get_ipv6_ecommunity( - new_mpath->attr), - &bwval)) - cum_bw += bwval; - else - all_paths_lb = false; - if (debug) { - bgp_path_info_path_with_addpath_rx_str( - new_mpath, path_buf, - sizeof(path_buf)); - zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d", - dest, path_buf, - &new_mpath->attr->nexthop, - mpath_count); + if (bgp_path_info_nexthop_cmp(prev_mpath, + new_mpath)) { + if (ecommunity_linkbw_present( + bgp_attr_get_ecommunity( + new_mpath->attr), + &bwval) || + ecommunity_linkbw_present( + bgp_attr_get_ipv6_ecommunity( + new_mpath->attr), + &bwval)) + cum_bw += bwval; + else + all_paths_lb = false; + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + new_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &new_mpath->attr + ->nexthop, + mpath_count); + } + } else { + if (debug) { + bgp_path_info_path_with_addpath_rx_str( + new_mpath, path_buf, + sizeof(path_buf)); + zlog_debug("%pBD: nexthop equal, however add mpath %s nexthop %pI4, cur count %d", + dest, path_buf, + &new_mpath->attr + ->nexthop, + mpath_count); + } } + prev_mpath = new_mpath; } mp_node = mp_next_node; } diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 1bc1a47c69..b03171b4c8 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -280,7 +280,8 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, * * Sending this vrf-label association is qualified by a) whether vrf->vpn * exporting is active ("export vpn" is enabled, vpn-policy RD and RT list - * are set) and b) whether vpn-policy label is set. + * are set), b) whether vpn-policy label is set and c) the vrf loopback + * interface is up. * * If any of these conditions do not hold, then we send MPLS_LABEL_NONE * for this vrf, which zebra interprets to mean "delete this vrf-label @@ -288,6 +289,7 @@ int bgp_nlri_parse_vpn(struct peer *peer, struct attr *attr, */ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) { + struct interface *ifp; mpls_label_t label = MPLS_LABEL_NONE; int debug = BGP_DEBUG(vpn, VPN_LEAK_LABEL); @@ -301,7 +303,9 @@ void vpn_leak_zebra_vrf_label_update(struct bgp *bgp, afi_t afi) } if (vpn_leak_to_vpn_active(bgp, afi, NULL, false)) { - label = bgp->vpn_policy[afi].tovpn_label; + ifp = if_get_vrf_loopback(bgp->vrf_id); + if (ifp && if_is_vrf(ifp) && if_is_up(ifp)) + label = bgp->vpn_policy[afi].tovpn_label; } if (debug) { diff --git a/bgpd/bgp_mplsvpn_snmp.c b/bgpd/bgp_mplsvpn_snmp.c index 3344e9e0a5..93d9f67245 100644 --- a/bgpd/bgp_mplsvpn_snmp.c +++ b/bgpd/bgp_mplsvpn_snmp.c @@ -590,6 +590,11 @@ static int bgp_vrf_check_update_active(struct bgp *bgp, struct interface *ifp) /* add trap in here */ bgp->snmp_stats->active = new_active; + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) { + bgp_mpls_l3vpn_update_last_changed(bgp); + return 0; + } + /* send relevent trap */ if (bgp->snmp_stats->active) trap = MPLSL3VPNVRFUP; diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index 248d478fe1..945076709c 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -519,20 +519,17 @@ static int bgp_capability_restart(struct peer *peer, UNSET_FLAG(restart_flag_time, 0xF000); peer->v_gr_restart = restart_flag_time; - if (bgp_debug_neighbor_events(peer)) { - zlog_debug( - "%s Peer has%srestarted. Restart Time: %d, N-bit set: %s", - peer->host, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) - ? " " - : " not ", - peer->v_gr_restart, - CHECK_FLAG(peer->cap, - PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) - ? "yes" - : "no"); - } + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%pBP OPEN has GR capability, Restart time %d R-bit %s N-bit %s", + peer, peer->v_gr_restart, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_RCV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV) + ? "SET" + : "NOT-SET"); while (stream_get_getp(s) + 4 <= end) { afi_t afi; @@ -556,14 +553,12 @@ static int bgp_capability_restart(struct peer *peer, iana_safi2str(pkt_safi)); } else { if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s Address family %s is%spreserved", - peer->host, get_afi_safi_str(afi, safi, false), - CHECK_FLAG( - peer->af_cap[afi][safi], - PEER_CAP_RESTART_AF_PRESERVE_RCV) - ? " " - : " not "); + zlog_debug("%pBP F-bit %s for %s", peer, + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV) + ? "SET" + : "NOT-SET", + get_afi_safi_str(afi, safi, false)); SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_RESTART_AF_RCV); @@ -1587,15 +1582,12 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, uint32_t restart_time; unsigned long capp = 0; unsigned long rcapp = 0; + struct bgp *bgp = peer->bgp; if (!CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART) && !CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART_HELPER)) return; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending helper Capability for Peer :%s :", - peer->host); - SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); capp = stream_get_endp(s); /* Set Capability Len Pointer */ @@ -1605,42 +1597,41 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, /* Set Restart Capability Len Pointer */ rcapp = stream_get_endp(s); stream_putc(s, 0); - restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + restart_time = bgp->restart_time; + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending R-Bit for peer: %s", - peer->host); } - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { + if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_NOTIFICATION)) { SET_FLAG(restart_time, GRACEFUL_RESTART_N_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV); - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] Sending N-Bit for peer: %s", - peer->host); } stream_putw(s, restart_time); + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Sending GR Capability, Restart time %d R-bit %s, N-bit %s", + peer->host, bgp->restart_time, + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV) + ? "SET" + : "NOT-SET", + CHECK_FLAG(peer->cap, + PEER_CAP_GRACEFUL_RESTART_N_BIT_ADV) + ? "SET" + : "NOT-SET"); + /* Send address-family specific graceful-restart capability * only when GR config is present */ if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) { - if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_GR_PRESERVE_FWD) - && BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug("[BGP_GR] F bit Set"); - FOREACH_AFI_SAFI (afi, safi) { + bool f_bit = false; + if (!peer->afc[afi][safi]) continue; - if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) - zlog_debug( - "[BGP_GR] Sending GR Capability for AFI :%d :, SAFI :%d:", - afi, safi); - /* Convert AFI, SAFI to values for * packet. */ @@ -1648,11 +1639,15 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, &pkt_safi); stream_putw(s, pkt_afi); stream_putc(s, pkt_safi); - if (CHECK_FLAG(peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) - stream_putc(s, GRACEFUL_RESTART_F_BIT); - else - stream_putc(s, 0); + + f_bit = bgp_gr_is_forwarding_preserved(bgp); + + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("... F-bit %s for %s", + f_bit ? "SET" : "NOT-SET", + get_afi_safi_str(afi, safi, false)); + + stream_putc(s, f_bit ? GRACEFUL_RESTART_F_BIT : 0); } } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index 010a31a3a8..2a2c9bdba9 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -651,6 +651,7 @@ void bgp_open_send(struct peer_connection *connection) uint16_t send_holdtime; as_t local_as; struct peer *peer = connection->peer; + bool ext_opt_params = false; if (CHECK_FLAG(peer->flags, PEER_FLAG_TIMER)) send_holdtime = peer->holdtime; @@ -677,15 +678,17 @@ void bgp_open_send(struct peer_connection *connection) /* Set capabilities */ if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { - (void)bgp_open_capability(s, peer, true); + ext_opt_params = true; + (void)bgp_open_capability(s, peer, ext_opt_params); } else { struct stream *tmp = stream_new(STREAM_SIZE(s)); stream_copy(tmp, s); - if (bgp_open_capability(tmp, peer, false) - > BGP_OPEN_NON_EXT_OPT_LEN) { + if (bgp_open_capability(tmp, peer, ext_opt_params) > + BGP_OPEN_NON_EXT_OPT_LEN) { stream_free(tmp); - (void)bgp_open_capability(s, peer, true); + ext_opt_params = true; + (void)bgp_open_capability(s, peer, ext_opt_params); } else { stream_copy(s, tmp); stream_free(tmp); @@ -696,10 +699,10 @@ void bgp_open_send(struct peer_connection *connection) bgp_packet_set_size(s); if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s sending OPEN, version %d, my as %u, holdtime %d, id %pI4", - peer->host, BGP_VERSION_4, local_as, send_holdtime, - &peer->local_id); + zlog_debug("%pBP fd %d sending OPEN%s, version %d, my as %u, holdtime %d, id %pI4", + peer, peer->connection->fd, + ext_opt_params ? " (Extended)" : "", BGP_VERSION_4, + local_as, send_holdtime, &peer->local_id); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ @@ -982,6 +985,7 @@ static void bgp_notify_send_internal(struct peer_connection *connection, peer->notify.code = bgp_notify.code; peer->notify.subcode = bgp_notify.subcode; peer->notify.length = bgp_notify.length; + peer->notify.hard_reset = hard_reset; if (bgp_notify.length && data) { bgp_notify.data = XMALLOC(MTYPE_BGP_NOTIFICATION, @@ -1295,7 +1299,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, stream_putc(s, 0); gr_restart_time = peer->bgp->restart_time; - if (peer->bgp->t_startup) { + if (peer->bgp->t_startup || bgp_in_graceful_restart()) { SET_FLAG(gr_restart_time, GRACEFUL_RESTART_R_BIT); SET_FLAG(peer->cap, PEER_CAP_GRACEFUL_RESTART_R_BIT_ADV); } @@ -1800,6 +1804,23 @@ static int bgp_open_receive(struct peer_connection *connection, mp_capability = 0; optlen = stream_getc(peer->curr); + /* If we previously had some more capabilities e.g.: + * FQDN, SOFT_VERSION, we MUST clear the values we used + * before, to avoid using stale data. + * Checking peer->cap is enough before checking for the real + * data, but we don't have this check everywhere in the code, + * thus let's clear the data here too before parsing the + * capabilities. + */ + if (peer->hostname) + XFREE(MTYPE_BGP_PEER_HOST, peer->hostname); + + if (peer->domainname) + XFREE(MTYPE_BGP_PEER_HOST, peer->domainname); + + if (peer->soft_version) + XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version); + /* Extended Optional Parameters Length for BGP OPEN Message */ if (optlen == BGP_OPEN_NON_EXT_OPT_LEN || CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { @@ -1977,6 +1998,14 @@ static int bgp_open_receive(struct peer_connection *connection, BGP_NOTIFY_OPEN_BAD_PEER_AS, notify_data_remote_as, 2); return BGP_Stop; + } else if (peer->as_type == AS_AUTO) { + if (remote_as == peer->bgp->as) { + peer->as = peer->local_as; + SET_FLAG(peer->as_type, AS_INTERNAL); + } else { + peer->as = remote_as; + SET_FLAG(peer->as_type, AS_EXTERNAL); + } } else if (peer->as_type == AS_INTERNAL) { if (remote_as != peer->bgp->as) { if (bgp_debug_neighbor_events(peer)) @@ -2378,13 +2407,13 @@ static int bgp_update_receive(struct peer_connection *connection, ret = bgp_dump_attr(&attr, peer->rcvd_attr_str, sizeof(peer->rcvd_attr_str)); - peer->stat_upd_7606++; - - if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) + if (attr_parse_ret == BGP_ATTR_PARSE_WITHDRAW) { + peer->stat_upd_7606++; flog_err( EC_BGP_UPDATE_RCV, "%pBP rcvd UPDATE with errors in attr(s)!! Withdrawing route.", peer); + } if (ret && bgp_debug_update(peer, NULL, NULL, 1) && BGP_DEBUG(update, UPDATE_DETAIL)) { diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 9e40e165fa..c8cf187f84 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -851,8 +851,13 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, * with the * sticky flag. */ - if (newattr->sticky != existattr->sticky) { - if (newattr->sticky && !existattr->sticky) { + bool new_sticky = CHECK_FLAG(newattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + bool exist_sticky = CHECK_FLAG(existattr->evpn_flags, + ATTR_EVPN_FLAG_STICKY); + + if (new_sticky != exist_sticky) { + if (new_sticky && !exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( @@ -861,7 +866,7 @@ int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 1; } - if (!newattr->sticky && existattr->sticky) { + if (!new_sticky && exist_sticky) { *reason = bgp_path_selection_evpn_sticky_mac; if (debug) zlog_debug( @@ -3256,15 +3261,6 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (!peer_established(pi->peer->connection)) continue; - if (!bgp_path_info_nexthop_cmp(pi, new_select)) { - if (debug) - zlog_debug( - "%pBD(%s): %s has the same nexthop as the bestpath, skip it", - dest, bgp->name_pretty, - path_buf); - continue; - } - bgp_path_info_cmp(bgp, pi, new_select, &paths_eq, mpath_cfg, debug, pfx_buf, afi, safi, &dest->reason); @@ -3886,6 +3882,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) struct bgp_dest *dest; int cnt = 0; struct afi_safi_info *thread_info; + bool route_sync_pending = false; if (bgp->gr_info[afi][safi].t_route_select) { struct event *t = bgp->gr_info[afi][safi].t_route_select; @@ -3895,7 +3892,7 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) EVENT_OFF(bgp->gr_info[afi][safi].t_route_select); } - if (BGP_DEBUG(update, UPDATE_OUT)) { + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) { zlog_debug("%s: processing route for %s : cnt %d", __func__, get_afi_safi_str(afi, safi, false), bgp->gr_info[afi][safi].gr_deferred); @@ -3928,6 +3925,21 @@ void bgp_best_path_select_defer(struct bgp *bgp, afi_t afi, safi_t safi) /* Send route processing complete message to RIB */ bgp_zebra_update(bgp, afi, safi, ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE); + bgp->gr_info[afi][safi].route_sync = true; + + /* If this instance is all done, check for GR completion overall */ + FOREACH_AFI_SAFI_NSF (afi, safi) { + if (bgp->gr_info[afi][safi].af_enabled && + !bgp->gr_info[afi][safi].route_sync) { + route_sync_pending = true; + break; + } + } + + if (!route_sync_pending) { + bgp->gr_route_sync_pending = false; + bgp_update_gr_completion(); + } return; } diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 97ae92c899..3ba368aaf7 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -680,9 +680,8 @@ route_match_address_prefix_list(void *rule, afi_t afi, plist = prefix_list_lookup(afi, (char *)rule); if (plist == NULL) { if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "%s: Prefix List %s specified does not exist defaulting to NO_MATCH", - __func__, (char *)rule); + zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH", + __func__, (char *)rule, afi2str(afi)); return RMAP_NOMATCH; } diff --git a/bgpd/bgp_snmp.c b/bgpd/bgp_snmp.c index 065ea7672c..eff7c5e0f6 100644 --- a/bgpd/bgp_snmp.c +++ b/bgpd/bgp_snmp.c @@ -50,6 +50,21 @@ DEFPY(bgp_snmp_traps_rfc4273, bgp_snmp_traps_rfc4273_cmd, return CMD_SUCCESS; } +DEFPY(bgp_snmp_traps_rfc4382, bgp_snmp_traps_rfc4382_cmd, + "[no$no] bgp snmp traps rfc4382", + NO_STR BGP_STR + "Configure BGP SNMP\n" + "Configure SNMP traps for BGP\n" + "Configure use of rfc4382 SNMP traps for BGP\n") +{ + if (no) { + UNSET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); + return CMD_SUCCESS; + } + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); + return CMD_SUCCESS; +} + DEFPY(bgp_snmp_traps_bgp4_mibv2, bgp_snmp_traps_bgp4_mibv2_cmd, "[no$no] bgp snmp traps bgp4-mibv2", NO_STR BGP_STR @@ -69,9 +84,12 @@ static void bgp_snmp_traps_init(void) { install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4273_cmd); install_element(CONFIG_NODE, &bgp_snmp_traps_bgp4_mibv2_cmd); + install_element(CONFIG_NODE, &bgp_snmp_traps_rfc4382_cmd); SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4273); /* BGP4MIBv2 traps are disabled by default */ + + SET_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382); } int bgp_cli_snmp_traps_config_write(struct vty *vty) @@ -86,6 +104,10 @@ int bgp_cli_snmp_traps_config_write(struct vty *vty) vty_out(vty, "bgp snmp traps bgp4-mibv2\n"); write++; } + if (!CHECK_FLAG(bm->options, BGP_OPT_TRAPS_RFC4382)) { + vty_out(vty, "no bgp snmp traps rfc4382\n"); + write++; + } return write; } diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c index 124e7a388b..b717793a45 100644 --- a/bgpd/bgp_updgrp.c +++ b/bgpd/bgp_updgrp.c @@ -343,7 +343,12 @@ static unsigned int updgrp_hash_key_make(const void *p) key = 0; - key = jhash_1word(peer->sort, key); /* EBGP or IBGP */ + /* `remote-as auto` technically uses identical peer->sort. + * After OPEN message is parsed, this is updated accordingly, but + * we need to call the peer_sort() here also to properly create + * separate subgroups. + */ + key = jhash_1word(peer_sort((struct peer *)peer), key); key = jhash_1word(peer->sub_sort, key); /* OAD */ key = jhash_1word((peer->flags & PEER_UPDGRP_FLAGS), key); key = jhash_1word((flags & PEER_UPDGRP_AF_FLAGS), key); diff --git a/bgpd/bgp_vty.h b/bgpd/bgp_vty.h index addd71757d..f88f5c8125 100644 --- a/bgpd/bgp_vty.h +++ b/bgpd/bgp_vty.h @@ -60,8 +60,6 @@ struct bgp; #define VTY_BGP_GR_ROUTER_DETECT(_bgp, _peer, _peer_list) \ do { \ - if (_peer->bgp->t_startup) \ - bgp_peer_gr_flags_update(_peer); \ for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ if (CHECK_FLAG(peer_loop->flags, \ PEER_FLAG_GRACEFUL_RESTART)) \ @@ -84,30 +82,27 @@ struct bgp; } \ } while (0) -#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA( \ - _bgp, _peer_list, _ret) \ - do { \ - struct peer *peer_loop; \ - bool gr_router_detected = false; \ - struct listnode *node = {0}; \ - struct listnode *nnode = {0}; \ - for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ - if (peer_loop->bgp->t_startup) \ - bgp_peer_gr_flags_update(peer_loop); \ - if (CHECK_FLAG(peer_loop->flags, \ - PEER_FLAG_GRACEFUL_RESTART)) \ - gr_router_detected = true; \ - } \ - if (gr_router_detected \ - && _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, false)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } else if (!gr_router_detected \ - && _bgp->present_zebra_gr_state \ - == ZEBRA_GR_ENABLE) { \ - if (bgp_zebra_send_capabilities(_bgp, true)) \ - _ret = BGP_ERR_INVALID_VALUE; \ - } \ +#define VTY_BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(_bgp, \ + _peer_list, _ret) \ + do { \ + struct peer *peer_loop; \ + bool gr_router_detected = false; \ + struct listnode *node = { 0 }; \ + struct listnode *nnode = { 0 }; \ + for (ALL_LIST_ELEMENTS(_peer_list, node, nnode, peer_loop)) { \ + if (CHECK_FLAG(peer_loop->flags, \ + PEER_FLAG_GRACEFUL_RESTART)) \ + gr_router_detected = true; \ + } \ + if (gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_DISABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, false)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } else if (!gr_router_detected && \ + _bgp->present_zebra_gr_state == ZEBRA_GR_ENABLE) { \ + if (bgp_zebra_send_capabilities(_bgp, true)) \ + _ret = BGP_ERR_INVALID_VALUE; \ + } \ } while (0) @@ -166,8 +161,9 @@ extern int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv, int argc, struct bgp **bgp, bool use_json); extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi, - safi_t safi, const char *neighbor, int as_type, - as_t as, uint16_t show_flags); + safi_t safi, const char *neighbor, + enum peer_asn_type as_type, as_t as, + uint16_t show_flags); extern bool peergroup_flag_check(struct peer *peer, uint64_t flag); extern bool peergroup_af_flag_check(struct peer *peer, afi_t afi, safi_t safi, uint64_t flag); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index c3b93adc26..797e3becc3 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -195,7 +195,7 @@ static int bgp_ifp_destroy(struct interface *ifp) bgp = ifp->vrf->info; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf del VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf del VRF %s IF %s", ifp->vrf->name, ifp->name); if (bgp) { @@ -220,8 +220,7 @@ static int bgp_ifp_up(struct interface *ifp) bgp_mac_add_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf->vrf_id, - ifp->name); + zlog_debug("Rx Intf up VRF %s IF %s", ifp->vrf->name, ifp->name); if (!bgp) return 0; @@ -235,7 +234,7 @@ static int bgp_ifp_up(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_up(ifp); - if (bgp_get_default() && if_is_loopback(ifp)) { + if (bgp_get_default() && if_is_vrf(ifp)) { vpn_leak_zebra_vrf_label_update(bgp, AFI_IP); vpn_leak_zebra_vrf_label_update(bgp, AFI_IP6); vpn_leak_zebra_vrf_sid_update(bgp, AFI_IP); @@ -259,7 +258,7 @@ static int bgp_ifp_down(struct interface *ifp) bgp_mac_del_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf down VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf down VRF %s IF %s", ifp->vrf->name, ifp->name); if (!bgp) @@ -290,7 +289,7 @@ static int bgp_ifp_down(struct interface *ifp) hook_call(bgp_vrf_status_changed, bgp, ifp); bgp_nht_ifp_down(ifp); - if (bgp_get_default() && if_is_loopback(ifp)) { + if (bgp_get_default() && if_is_vrf(ifp)) { vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP); vpn_leak_zebra_vrf_label_withdraw(bgp, AFI_IP6); vpn_leak_zebra_vrf_sid_withdraw(bgp, AFI_IP); @@ -319,8 +318,8 @@ static int bgp_interface_address_add(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf address add VRF %u IF %s addr %pFX", vrf_id, - ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf address add VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (!bgp) return 0; @@ -398,8 +397,8 @@ static int bgp_interface_address_delete(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf address del VRF %u IF %s addr %pFX", vrf_id, - ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf address del VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (bgp && if_is_operative(ifc->ifp)) { bgp_connected_delete(bgp, ifc); @@ -450,8 +449,8 @@ static int bgp_interface_nbr_address_add(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf neighbor add VRF %u IF %s addr %pFX", - vrf_id, ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf neighbor add VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (if_is_operative(ifc->ifp)) { bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -473,8 +472,8 @@ static int bgp_interface_nbr_address_delete(ZAPI_CALLBACK_ARGS) return 0; if (bgp_debug_zebra(ifc->address)) - zlog_debug("Rx Intf neighbor del VRF %u IF %s addr %pFX", - vrf_id, ifc->ifp->name, ifc->address); + zlog_debug("Rx Intf neighbor del VRF %s IF %s addr %pFX", + ifc->ifp->vrf->name, ifc->ifp->name, ifc->address); if (if_is_operative(ifc->ifp)) { bgp = bgp_lookup_by_vrf_id(vrf_id); @@ -556,13 +555,14 @@ static int zebra_read_route(ZAPI_CALLBACK_ARGS) if (add) { inet_ntop(api.prefix.family, &nexthop, buf, sizeof(buf)); - zlog_debug( - "Rx route ADD VRF %u %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI, - vrf_id, zebra_route_string(api.type), - api.instance, &api.prefix, buf, nhtype, ifindex, - api.metric, api.distance, api.tag); + zlog_debug("Rx route ADD %s %s[%d] %pFX nexthop %s (type %d if %u) metric %u distance %u tag %" ROUTE_TAG_PRI, + bgp->name_pretty, + zebra_route_string(api.type), api.instance, + &api.prefix, buf, nhtype, ifindex, + api.metric, api.distance, api.tag); } else { - zlog_debug("Rx route DEL VRF %u %s[%d] %pFX", vrf_id, + zlog_debug("Rx route DEL %s %s[%d] %pFX", + bgp->name_pretty, zebra_route_string(api.type), api.instance, &api.prefix); } @@ -1526,7 +1526,6 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, struct peer *peer; uint32_t metric; route_tag_t tag; - bool is_add; uint32_t nhg_id = 0; struct bgp_table *table = bgp_dest_table(dest); const struct prefix *p = bgp_dest_get_prefix(dest); @@ -1580,9 +1579,7 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, table->afi, table->safi, &nhg_id, &metric, &tag, &allow_recursion); - is_add = (valid_nh_count || nhg_id) ? true : false; - - if (is_add && CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { + if (CHECK_FLAG(bm->flags, BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA)) { struct bgp_zebra_opaque bzo = {}; const char *reason = bgp_path_selection_reason2str(dest->reason); @@ -1638,18 +1635,17 @@ bgp_zebra_announce_actual(struct bgp_dest *dest, struct bgp_path_info *info, } if (bgp_debug_zebra(p)) { - zlog_debug( - "Tx route %s VRF %u %pFX metric %u tag %" ROUTE_TAG_PRI - " count %d nhg %d", - is_add ? "add" : "delete", bgp->vrf_id, &api.prefix, - api.metric, api.tag, api.nexthop_num, nhg_id); + zlog_debug("Tx route add %s (table id %u) %pFX metric %u tag %" ROUTE_TAG_PRI + " count %d nhg %d", + bgp->name_pretty, api.tableid, &api.prefix, + api.metric, api.tag, api.nexthop_num, nhg_id); bgp_debug_zebra_nh(&api); zlog_debug("%s: %pFX: announcing to zebra (recursion %sset)", __func__, p, (allow_recursion ? "" : "NOT ")); } - return zclient_route_send(is_add ? ZEBRA_ROUTE_ADD : ZEBRA_ROUTE_DELETE, - zclient, &api); + + return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api); } @@ -1731,8 +1727,8 @@ enum zclient_send_status bgp_zebra_withdraw_actual(struct bgp_dest *dest, } if (bgp_debug_zebra(p)) - zlog_debug("Tx route delete VRF %u %pFX", bgp->vrf_id, - &api.prefix); + zlog_debug("Tx route delete %s (table id %u) %pFX", + bgp->name_pretty, api.tableid, &api.prefix); return zclient_route_send(ZEBRA_ROUTE_DELETE, zclient, &api); } @@ -1778,8 +1774,9 @@ static void bgp_handle_route_announcements_to_zebra(struct event *e) } if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("BGP %s route %pBD(%s) with dest %p and flags 0x%x to zebra", - install ? "announcing" : "withdrawing", dest, + zlog_debug("BGP %s%s route %pBD(%s) with dest %p and flags 0x%x to zebra", + install ? "announcing" : "withdrawing", + is_evpn ? " evpn" : " ", dest, table->bgp->name_pretty, dest, dest->flags); if (install) { @@ -2069,8 +2066,8 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type, return CMD_SUCCESS; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute add VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), + zlog_debug("Tx redistribute add %s afi %d %s %d", + bgp->name_pretty, afi, zebra_route_string(type), instance); /* Send distribute add message to zebra. */ @@ -2090,8 +2087,8 @@ int bgp_redistribute_resend(struct bgp *bgp, afi_t afi, int type, return -1; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute del/add VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), + zlog_debug("Tx redistribute del/add %s afi %d %s %d", + bgp->name_pretty, afi, zebra_route_string(type), instance); /* Send distribute add message to zebra. */ @@ -2185,9 +2182,9 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type, if (bgp_install_info_to_zebra(bgp)) { /* Send distribute delete message to zebra. */ if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Tx redistribute del VRF %u afi %d %s %d", - bgp->vrf_id, afi, zebra_route_string(type), - instance); + zlog_debug("Tx redistribute del %s afi %d %s %d", + bgp->name_pretty, afi, + zebra_route_string(type), instance); zebra_redistribute_send(ZEBRA_REDISTRIBUTE_DELETE, zclient, afi, type, instance, bgp->vrf_id); } @@ -2290,7 +2287,7 @@ void bgp_zebra_instance_register(struct bgp *bgp) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Registering VRF %u", bgp->vrf_id); + zlog_debug("Registering %s", bgp->name_pretty); /* Register for router-id, interfaces, redistributed routes. */ zclient_send_reg_requests(zclient, bgp->vrf_id); @@ -2312,7 +2309,7 @@ void bgp_zebra_instance_deregister(struct bgp *bgp) return; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Deregistering VRF %u", bgp->vrf_id); + zlog_debug("Deregistering %s", bgp->name_pretty); /* For EVPN instance, unregister learning about VNIs, if appropriate. */ if (bgp->advertise_all_vni) @@ -3325,7 +3322,7 @@ static int bgp_ifp_create(struct interface *ifp) struct bgp *bgp; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf add VRF %u IF %s", ifp->vrf->vrf_id, + zlog_debug("Rx Intf add VRF %s IF %s", ifp->vrf->name, ifp->name); bgp = ifp->vrf->info; @@ -3963,6 +3960,11 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) return BGP_GR_FAILURE; } + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("%s(%d): Sending GR capability %s to zebra", + bgp->name_pretty, bgp->vrf_id, + disable ? "disabled" : "enabled"); + /* Check if capability is already sent. If the flag force is set * send the capability since this can be initial bgp configuration */ @@ -3978,8 +3980,8 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) if (zclient_capabilities_send(ZEBRA_CLIENT_CAPABILITIES, zclient, &api) == ZCLIENT_SEND_FAILURE) { - zlog_err("%s: %s error sending capability", __func__, - bgp->name_pretty); + zlog_err("%s(%d): Error sending GR capability to zebra", + bgp->name_pretty, bgp->vrf_id); ret = BGP_GR_FAILURE; } else { if (disable) @@ -3987,9 +3989,6 @@ int bgp_zebra_send_capabilities(struct bgp *bgp, bool disable) else bgp->present_zebra_gr_state = ZEBRA_GR_ENABLE; - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("%s: %s send capabilty success", __func__, - bgp->name_pretty); ret = BGP_GR_SUCCESS; } return ret; diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 894226adac..a88de651f5 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -149,7 +149,7 @@ void bgp_session_reset(struct peer *peer) * during walk of peer list, we would end up accessing the freed next * node. This function moves the next node along. */ -static void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) +void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode) { struct listnode *n; struct peer *npeer; @@ -306,11 +306,11 @@ static int bgp_router_id_set(struct bgp *bgp, const struct in_addr *id, for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { IPV4_ADDR_COPY(&peer->local_id, id); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_RID_CHANGE; + peer->last_reset = PEER_DOWN_RID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } /* EVPN uses router id in RD, update them */ @@ -440,11 +440,12 @@ void bm_wait_for_fib_set(bool set) */ for (ALL_LIST_ELEMENTS_RO(bm->bgp, next, bgp)) { for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + if (!BGP_IS_VALID_STATE_FOR_NOTIF( peer->connection->status)) continue; - peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -496,10 +497,11 @@ void bgp_suppress_fib_pending_set(struct bgp *bgp, bool set) * let's just start over */ for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) { + peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; + if (!BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) continue; - peer->last_reset = PEER_DOWN_SUPPRESS_FIB_PENDING; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -523,11 +525,11 @@ void bgp_cluster_id_set(struct bgp *bgp, struct in_addr *cluster_id) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CLID_CHANGE; + peer->last_reset = PEER_DOWN_CLID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } } @@ -547,11 +549,11 @@ void bgp_cluster_id_unset(struct bgp *bgp) if (peer->sort != BGP_PEER_IBGP) continue; - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_CLID_CHANGE; + peer->last_reset = PEER_DOWN_CLID_CHANGE; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } } @@ -676,14 +678,12 @@ void bgp_confederation_id_unset(struct bgp *bgp) /* We're looking for peers who's AS is not local */ if (peer_sort(peer) != BGP_PEER_IBGP) { peer->local_as = bgp->as; + peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; if (BGP_IS_VALID_STATE_FOR_NOTIF( - peer->connection->status)) { - peer->last_reset = PEER_DOWN_CONFED_ID_CHANGE; + peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } - else bgp_session_reset_safe(peer, &nnode); } @@ -1074,10 +1074,10 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) /* Peer-group */ if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (peer->as_type == AS_INTERNAL) + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) return BGP_PEER_IBGP; - else if (peer->as_type == AS_EXTERNAL) + if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) return BGP_PEER_EBGP; else if (peer->as_type == AS_SPECIFIED && peer->as) { @@ -1132,17 +1132,20 @@ static inline enum bgp_peer_sort peer_calc_sort(struct peer *peer) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; - } else if (peer->group->conf->as_type - == AS_INTERNAL) + } else if (CHECK_FLAG(peer->group->conf->as_type, + AS_INTERNAL)) return BGP_PEER_IBGP; else return BGP_PEER_EBGP; } /* no AS information anywhere, let caller know */ return BGP_PEER_UNSPECIFIED; - } else if (peer->as_type != AS_SPECIFIED) - return (peer->as_type == AS_INTERNAL ? BGP_PEER_IBGP - : BGP_PEER_EBGP); + } else if (peer->as_type != AS_SPECIFIED) { + if (CHECK_FLAG(peer->as_type, AS_INTERNAL)) + return BGP_PEER_IBGP; + else if (CHECK_FLAG(peer->as_type, AS_EXTERNAL)) + return BGP_PEER_EBGP; + } return (local_as == 0 ? BGP_PEER_INTERNAL : local_as == peer->as ? BGP_PEER_IBGP @@ -1391,9 +1394,31 @@ int bgp_global_gr_init(struct bgp *bgp) memcpy(bgp->GLOBAL_GR_FSM, local_GLOBAL_GR_FSM, sizeof(local_GLOBAL_GR_FSM)); - bgp->global_gr_present_state = GLOBAL_HELPER; + /* Inherit any BGP-wide configuration. */ + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_RESTARTER)) + bgp->global_gr_present_state = GLOBAL_GR; + else if (CHECK_FLAG(bm->flags, BM_FLAG_GR_DISABLED)) + bgp->global_gr_present_state = GLOBAL_DISABLE; + else + bgp->global_gr_present_state = GLOBAL_HELPER; + + if (bm->restart_time != BGP_DEFAULT_RESTART_TIME) + bgp->restart_time = bm->restart_time; + if (bm->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) + bgp->stalepath_time = bm->stalepath_time; + if (bm->select_defer_time != BGP_DEFAULT_SELECT_DEFERRAL_TIME) + bgp->select_defer_time = bm->select_defer_time; + if (bm->rib_stale_time != BGP_DEFAULT_RIB_STALE_TIME) + bgp->rib_stale_time = bm->rib_stale_time; + if (CHECK_FLAG(bm->flags, BM_FLAG_GR_PRESERVE_FWD)) + SET_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD); + bgp->present_zebra_gr_state = ZEBRA_GR_DISABLE; + if (BGP_DEBUG(graceful_restart, GRACEFUL_RESTART)) + zlog_debug("%s: Global GR state is %s", bgp->name_pretty, + print_global_gr_mode(bgp->global_gr_present_state)); + return BGP_GR_SUCCESS; } @@ -1453,9 +1478,7 @@ int bgp_peer_gr_init(struct peer *peer) { PEER_HELPER, bgp_peer_gr_action }, { PEER_GLOBAL_INHERIT, NULL } } }; - memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, - sizeof(local_Peer_GR_FSM)); - peer->peer_gr_present_state = PEER_GLOBAL_INHERIT; + memcpy(&peer->PEER_GR_FSM, local_Peer_GR_FSM, sizeof(local_Peer_GR_FSM)); bgp_peer_move_to_gr_mode(peer, PEER_GLOBAL_INHERIT); return BGP_GR_SUCCESS; @@ -1929,7 +1952,7 @@ void bgp_recalculate_all_bestpaths(struct bgp *bgp) */ struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, + enum peer_asn_type as_type, struct peer_group *group, bool config_node, const char *as_str) { int active; @@ -2061,29 +2084,29 @@ bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) } /* Change peer's AS number. */ -void peer_as_change(struct peer *peer, as_t as, int as_specified, +void peer_as_change(struct peer *peer, as_t as, enum peer_asn_type as_type, const char *as_str) { enum bgp_peer_sort origtype, newtype; /* Stop peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; + peer->last_reset = PEER_DOWN_REMOTE_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); } origtype = peer_sort_lookup(peer); peer->as = as; - if (as_specified == AS_SPECIFIED && as_str) { + if (as_type == AS_SPECIFIED && as_str) { if (peer->as_pretty) XFREE(MTYPE_BGP_NAME, peer->as_pretty); peer->as_pretty = XSTRDUP(MTYPE_BGP_NAME, as_str); } else if (peer->as_type == AS_UNSPECIFIED && peer->as_pretty) XFREE(MTYPE_BGP_NAME, peer->as_pretty); - peer->as_type = as_specified; + peer->as_type = as_type; if (bgp_config_check(peer->bgp, BGP_CONFIG_CONFEDERATION) && !bgp_confederation_peers_check(peer->bgp, as) @@ -2140,7 +2163,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified, /* If peer does not exist, create new one. If peer already exists, set AS number to the peer. */ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, - as_t *as, int as_type, const char *as_str) + as_t *as, enum peer_asn_type as_type, const char *as_str) { struct peer *peer; as_t local_as; @@ -2181,10 +2204,10 @@ int peer_remote_as(struct bgp *bgp, union sockunion *su, const char *conf_if, } } else { /* internal/external used, compare as-types */ - if (((peer_sort_type == BGP_PEER_IBGP) - && (as_type != AS_INTERNAL)) - || ((peer_sort_type == BGP_PEER_EBGP) - && (as_type != AS_EXTERNAL))) { + if (((peer_sort_type == BGP_PEER_IBGP) && + !CHECK_FLAG(as_type, AS_INTERNAL)) || + ((peer_sort_type == BGP_PEER_EBGP) && + !CHECK_FLAG(as_type, AS_EXTERNAL))) { *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } @@ -2260,7 +2283,7 @@ static void peer_group2peer_config_copy_af(struct peer_group *group, flags_tmp = conf->af_flags[afi][safi] & ~pflags_ovrd; flags_tmp ^= conf->af_flags_invert[afi][safi] ^ peer->af_flags_invert[afi][safi]; - flags_tmp &= ~pflags_ovrd; + UNSET_FLAG(flags_tmp, pflags_ovrd); UNSET_FLAG(peer->af_flags[afi][safi], ~pflags_ovrd); SET_FLAG(peer->af_flags[afi][safi], flags_tmp); @@ -2423,6 +2446,8 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) if (!active && peer_active(peer)) { bgp_timer_set(peer->connection); } else { + peer->last_reset = PEER_DOWN_AF_ACTIVATE; + if (peer_established(peer->connection)) { if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 1; @@ -2435,18 +2460,15 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) false); } } else { - peer->last_reset = PEER_DOWN_AF_ACTIVATE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } if (peer->connection->status == OpenSent || - peer->connection->status == OpenConfirm) { - peer->last_reset = PEER_DOWN_AF_ACTIVATE; + peer->connection->status == OpenConfirm) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } /* * If we are turning on a AFI/SAFI locally and we've * started bringing a peer up, we need to tell @@ -2458,11 +2480,9 @@ static int peer_activate_af(struct peer *peer, afi_t afi, safi_t safi) */ other = peer->doppelganger; if (other && (other->connection->status == OpenSent || - other->connection->status == OpenConfirm)) { - other->last_reset = PEER_DOWN_AF_ACTIVATE; + other->connection->status == OpenConfirm)) bgp_notify_send(other->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } } return 0; @@ -2500,10 +2520,10 @@ int peer_activate(struct peer *peer, afi_t afi, safi_t safi) group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { - ret |= peer_activate_af(tmp_peer, afi, safi); + SET_FLAG(ret, peer_activate_af(tmp_peer, afi, safi)); } } else { - ret |= peer_activate_af(peer, afi, safi); + SET_FLAG(ret, peer_activate_af(peer, afi, safi)); } /* If this is the first peer to be activated for this @@ -2556,6 +2576,8 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, } if (peer_established(peer->connection)) { + peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; + if (CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV)) { peer->afc_adv[afi][safi] = 0; peer->afc_nego[afi][safi] = 0; @@ -2567,13 +2589,11 @@ static bool non_peergroup_deactivate_af(struct peer *peer, afi_t afi, bgp_clear_route(peer, afi, safi); peer->pcount[afi][safi] = 0; } else { - peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } } else { - peer->last_reset = PEER_DOWN_NEIGHBOR_DELETE; bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } @@ -2602,10 +2622,11 @@ int peer_deactivate(struct peer *peer, afi_t afi, safi_t safi) group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, tmp_peer)) { - ret |= non_peergroup_deactivate_af(tmp_peer, afi, safi); + SET_FLAG(ret, non_peergroup_deactivate_af(tmp_peer, afi, + safi)); } } else { - ret |= non_peergroup_deactivate_af(peer, afi, safi); + SET_FLAG(ret, non_peergroup_deactivate_af(peer, afi, safi)); } bgp = peer->bgp; @@ -2907,9 +2928,9 @@ static void peer_group2peer_config_copy(struct peer_group *group, peer->gtsm_hops = conf->gtsm_hops; /* peer flags apply */ - flags_tmp = conf->flags & ~peer->flags_override; + flags_tmp = CHECK_FLAG(conf->flags, ~peer->flags_override); flags_tmp ^= conf->flags_invert ^ peer->flags_invert; - flags_tmp &= ~peer->flags_override; + UNSET_FLAG(flags_tmp, peer->flags_override); UNSET_FLAG(peer->flags, ~peer->flags_override); SET_FLAG(peer->flags, flags_tmp); @@ -3005,7 +3026,7 @@ static void peer_group2peer_config_copy(struct peer_group *group, /* Peer group's remote AS configuration. */ int peer_group_remote_as(struct bgp *bgp, const char *group_name, as_t *as, - int as_type, const char *as_str) + enum peer_asn_type as_type, const char *as_str) { struct peer_group *group; struct peer *peer; @@ -3322,13 +3343,13 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, SET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_RMAP_BIND; + peer->last_reset = PEER_DOWN_RMAP_BIND; + + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else { + else bgp_session_reset(peer); - } } /* Create a new peer. */ @@ -4523,6 +4544,12 @@ bool peer_active(struct peer *peer) { if (BGP_CONNECTION_SU_UNSPEC(peer->connection)) return false; + + if (peer->bfd_config) { + if (bfd_session_is_down(peer->bfd_config->session)) + return false; + } + if (peer->afc[AFI_IP][SAFI_UNICAST] || peer->afc[AFI_IP][SAFI_MULTICAST] || peer->afc[AFI_IP][SAFI_LABELED_UNICAST] || peer->afc[AFI_IP][SAFI_MPLS_VPN] || peer->afc[AFI_IP][SAFI_ENCAP] @@ -4729,7 +4756,7 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, if (match->flag == 0) break; - if (match->flag & flag) { + if (CHECK_FLAG(match->flag, flag)) { found = 1; if (match->type == peer_change_reset_in) @@ -4760,6 +4787,13 @@ static int peer_flag_action_set(const struct peer_flag_action *action_list, static void peer_flag_modify_action(struct peer *peer, uint64_t flag) { + if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) + peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; + else if (flag == PEER_FLAG_PASSIVE) + peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; + else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) + peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; + if (flag == PEER_FLAG_SHUTDOWN) { if (CHECK_FLAG(peer->flags, flag)) { if (CHECK_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT)) @@ -4808,13 +4842,6 @@ static void peer_flag_modify_action(struct peer *peer, uint64_t flag) BGP_EVENT_ADD(peer->connection, BGP_Stop); } } else if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - if (flag == PEER_FLAG_DYNAMIC_CAPABILITY) - peer->last_reset = PEER_DOWN_CAPABILITY_CHANGE; - else if (flag == PEER_FLAG_PASSIVE) - peer->last_reset = PEER_DOWN_PASSIVE_CHANGE; - else if (flag == PEER_FLAG_DISABLE_CONNECTED_CHECK) - peer->last_reset = PEER_DOWN_MULTIHOP_CHANGE; - bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else @@ -5056,15 +5083,17 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, ptype = peer_sort(peer); /* Special check for reflector client. */ - if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_REFLECTOR_CLIENT) && + ptype != BGP_PEER_IBGP) return BGP_ERR_NOT_INTERNAL_PEER; /* Special check for remove-private-AS. */ - if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_REMOVE_PRIVATE_AS) && + ptype == BGP_PEER_IBGP) return BGP_ERR_REMOVE_PRIVATE_AS; /* as-override is not allowed for IBGP peers */ - if (flag & PEER_FLAG_AS_OVERRIDE && ptype == BGP_PEER_IBGP) + if (CHECK_FLAG(flag, PEER_FLAG_AS_OVERRIDE) && ptype == BGP_PEER_IBGP) return BGP_ERR_AS_OVERRIDE; /* Handle flag updates where desired state matches current state. */ @@ -5115,7 +5144,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, * If the peer is a route server client let's not * muck with the nexthop on the way out the door */ - if (flag & PEER_FLAG_RSERVER_CLIENT) { + if (CHECK_FLAG(flag, PEER_FLAG_RSERVER_CLIENT)) { if (set) SET_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_UNCHANGED); @@ -5532,12 +5561,12 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5569,13 +5598,13 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) member->update_if = XSTRDUP(MTYPE_PEER_UPDATE_SOURCE, ifname); sockunion_free(member->update_source); member->update_source = NULL; + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5603,12 +5632,12 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5639,13 +5668,13 @@ void peer_update_source_addr_set(struct peer *peer, const union sockunion *su) SET_FLAG(member->flags, PEER_FLAG_UPDATE_SOURCE); member->update_source = sockunion_dup(su); XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -5691,12 +5720,12 @@ void peer_update_source_unset(struct peer *peer) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(peer); /* Apply new source configuration to BFD session. */ @@ -5726,13 +5755,13 @@ void peer_update_source_unset(struct peer *peer) sockunion_free(member->update_source); member->update_source = NULL; XFREE(MTYPE_PEER_UPDATE_SOURCE, member->update_if); + member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; /* Send notification or reset peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_UPDATE_SOURCE_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); /* Apply new source configuration to BFD session. */ @@ -6698,12 +6727,12 @@ int peer_local_as_unset(struct peer *peer) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) { - peer->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else BGP_EVENT_ADD(peer->connection, BGP_Stop); /* Skip peer-group mechanics for regular peers. */ @@ -6725,13 +6754,13 @@ int peer_local_as_unset(struct peer *peer) UNSET_FLAG(member->flags, PEER_FLAG_LOCAL_AS_REPLACE_AS); member->change_local_as = 0; XFREE(MTYPE_BGP_NAME, member->change_local_as_pretty); + member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; /* Send notification or stop peer depending on state. */ - if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) { - member->last_reset = PEER_DOWN_LOCAL_AS_CHANGE; + if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_CONFIG_CHANGE); - } else + else bgp_session_reset(member); } @@ -6758,6 +6787,7 @@ int peer_password_set(struct peer *peer, const char *password) /* Check if handling a regular peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { + peer->last_reset = PEER_DOWN_PASSWORD_CHANGE; /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->connection->status)) bgp_notify_send(peer->connection, BGP_NOTIFY_CEASE, @@ -6795,6 +6825,7 @@ int peer_password_set(struct peer *peer, const char *password) XFREE(MTYPE_PEER_PASSWORD, member->password); member->password = XSTRDUP(MTYPE_PEER_PASSWORD, password); + member->last_reset = PEER_DOWN_PASSWORD_CHANGE; /* Send notification or reset peer depending on state. */ if (BGP_IS_VALID_STATE_FOR_NOTIF(member->connection->status)) bgp_notify_send(member->connection, BGP_NOTIFY_CEASE, @@ -8401,8 +8432,8 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->start_time = monotime(NULL); bm->t_rmap_update = NULL; bm->rmap_update_timer = RMAP_DEFAULT_UPDATE_TIMER; - bm->v_update_delay = BGP_UPDATE_DELAY_DEF; - bm->v_establish_wait = BGP_UPDATE_DELAY_DEF; + bm->v_update_delay = BGP_UPDATE_DELAY_DEFAULT; + bm->v_establish_wait = BGP_UPDATE_DELAY_DEFAULT; bm->terminating = false; bm->socket_buffer = buffer_size; bm->wait_for_fib = false; @@ -8412,6 +8443,10 @@ void bgp_master_init(struct event_loop *master, const int buffer_size, bm->t_bgp_sync_label_manager = NULL; bm->t_bgp_start_label_manager = NULL; bm->t_bgp_zebra_route = NULL; + bm->restart_time = BGP_DEFAULT_RESTART_TIME; + bm->stalepath_time = BGP_DEFAULT_STALEPATH_TIME; + bm->select_defer_time = BGP_DEFAULT_SELECT_DEFERRAL_TIME; + bm->rib_stale_time = BGP_DEFAULT_RIB_STALE_TIME; bgp_mac_init(); /* init the rd id space. diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 1f8cc53349..7f1b82d9c7 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -56,10 +56,12 @@ struct bgp_pbr_config; * behavior * in the system. */ -enum { AS_UNSPECIFIED = 0, - AS_SPECIFIED, - AS_INTERNAL, - AS_EXTERNAL, +enum peer_asn_type { + AS_UNSPECIFIED = 1, + AS_SPECIFIED = 2, + AS_INTERNAL = 4, + AS_EXTERNAL = 8, + AS_AUTO = 16, }; /* Zebra Gracaful Restart states */ @@ -129,6 +131,7 @@ struct bgp_master { #define BGP_OPT_NO_ZEBRA (1 << 2) #define BGP_OPT_TRAPS_RFC4273 (1 << 3) #define BGP_OPT_TRAPS_BGP4MIBV2 (1 << 4) +#define BGP_OPT_TRAPS_RFC4382 (1 << 5) uint64_t updgrp_idspace; uint64_t subgrp_idspace; @@ -163,6 +166,23 @@ struct bgp_master { uint32_t flags; #define BM_FLAG_GRACEFUL_SHUTDOWN (1 << 0) #define BM_FLAG_SEND_EXTRA_DATA_TO_ZEBRA (1 << 1) +#define BM_FLAG_MAINTENANCE_MODE (1 << 2) +#define BM_FLAG_GR_RESTARTER (1 << 3) +#define BM_FLAG_GR_DISABLED (1 << 4) +#define BM_FLAG_GR_PRESERVE_FWD (1 << 5) +#define BM_FLAG_GRACEFUL_RESTART (1 << 6) +#define BM_FLAG_GR_COMPLETE (1 << 7) + +#define BM_FLAG_GR_CONFIGURED (BM_FLAG_GR_RESTARTER | BM_FLAG_GR_DISABLED) + + /* BGP-wide graceful restart config params */ + uint32_t restart_time; + uint32_t stalepath_time; + uint32_t select_defer_time; + uint32_t rib_stale_time; + + time_t startup_time; + time_t gr_completion_time; bool terminating; /* global flag that sigint terminate seen */ @@ -293,9 +313,9 @@ struct graceful_restart_info { /* Best route select */ struct event *t_route_select; /* AFI, SAFI enabled */ - bool af_enabled[AFI_MAX][SAFI_MAX]; + bool af_enabled; /* Route update completed */ - bool route_sync[AFI_MAX][SAFI_MAX]; + bool route_sync; }; enum global_mode { @@ -470,9 +490,7 @@ struct bgp { uint32_t restarted_peers; uint32_t implicit_eors; uint32_t explicit_eors; -#define BGP_UPDATE_DELAY_DEF 0 -#define BGP_UPDATE_DELAY_MIN 0 -#define BGP_UPDATE_DELAY_MAX 3600 +#define BGP_UPDATE_DELAY_DEFAULT 0 /* Reference bandwidth for BGP link-bandwidth. Used when * the LB value has to be computed based on some other @@ -547,6 +565,9 @@ struct bgp { */ enum zebra_gr_mode present_zebra_gr_state; + /* Is deferred path selection still not complete? */ + bool gr_route_sync_pending; + /* BGP Per AF flags */ uint16_t af_flags[AFI_MAX][SAFI_MAX]; #define BGP_CONFIG_DAMPENING (1 << 0) @@ -1226,7 +1247,7 @@ struct peer { struct peer_af *peer_af_array[BGP_AF_MAX]; /* Peer's remote AS number. */ - int as_type; + enum peer_asn_type as_type; as_t as; /* for vty as format */ char *as_pretty; @@ -1797,6 +1818,7 @@ struct peer { #define PEER_DOWN_SOCKET_ERROR 34U /* Some socket error happened */ #define PEER_DOWN_RTT_SHUTDOWN 35U /* Automatically shutdown due to RTT */ #define PEER_DOWN_SUPPRESS_FIB_PENDING 36U /* Suppress fib pending changed */ +#define PEER_DOWN_PASSWORD_CHANGE 37U /* neighbor password command */ /* * Remember to update peer_down_str in bgp_fsm.c when you add * a new value to the last_reset reason @@ -2261,8 +2283,9 @@ extern bool peer_afc_advertised(struct peer *peer); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); extern struct peer *peer_create(union sockunion *su, const char *conf_if, struct bgp *bgp, as_t local_as, as_t remote_as, - int as_type, struct peer_group *group, - bool config_node, const char *as_str); + enum peer_asn_type as_type, + struct peer_group *group, bool config_node, + const char *as_str); extern struct peer *peer_create_accept(struct bgp *); extern void peer_xfer_config(struct peer *dst, struct peer *src); extern char *peer_uptime(time_t uptime2, char *buf, size_t len, bool use_json, @@ -2335,13 +2358,13 @@ extern void bgp_listen_limit_unset(struct bgp *bgp); extern bool bgp_update_delay_active(struct bgp *); extern bool bgp_update_delay_configured(struct bgp *); extern bool bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi); -extern void peer_as_change(struct peer *peer, as_t as, int as_type, - const char *as_str); +extern void peer_as_change(struct peer *peer, as_t as, + enum peer_asn_type as_type, const char *as_str); extern int peer_remote_as(struct bgp *bgp, union sockunion *su, - const char *conf_if, as_t *as, int as_type, - const char *as_str); + const char *conf_if, as_t *as, + enum peer_asn_type as_type, const char *as_str); extern int peer_group_remote_as(struct bgp *bgp, const char *peer_str, as_t *as, - int as_type, const char *as_str); + enum peer_asn_type as_type, const char *as_str); extern int peer_delete(struct peer *peer); extern void peer_notify_unconfig(struct peer *peer); extern int peer_group_delete(struct peer_group *); @@ -2742,6 +2765,59 @@ static inline bool bgp_in_graceful_shutdown(struct bgp *bgp) !!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_SHUTDOWN)); } +static inline bool bgp_in_graceful_restart(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is not complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + !CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline bool bgp_is_graceful_restart_complete(void) +{ + /* True if BGP has (re)started gracefully (based on flags + * noted at startup) and GR is marked as complete. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) && + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)); +} + +static inline void bgp_update_gr_completion(void) +{ + struct listnode *node, *nnode; + struct bgp *bgp; + + /* + * Check and mark GR complete. This is done when deferred + * path selection has been completed for all instances and + * route-advertisement/EOR and route-sync with zebra has + * been invoked. + */ + if (!CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bm->flags, BM_FLAG_GR_COMPLETE)) + return; + + for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) { + if (bgp->gr_route_sync_pending) + return; + } + + SET_FLAG(bm->flags, BM_FLAG_GR_COMPLETE); + bm->gr_completion_time = monotime(NULL); +} + +static inline bool bgp_gr_is_forwarding_preserved(struct bgp *bgp) +{ + /* + * Is forwarding state preserved? Based either on config + * or if BGP restarted gracefully. + * TBD: Additional AFI/SAFI based checks etc. + */ + return (CHECK_FLAG(bm->flags, BM_FLAG_GRACEFUL_RESTART) || + CHECK_FLAG(bgp->flags, BGP_FLAG_GR_PRESERVE_FWD)); +} + /* For benefit of rfapi */ extern struct peer *peer_new(struct bgp *bgp); @@ -2781,6 +2857,8 @@ extern bool bgp_path_attribute_treat_as_withdraw(struct peer *peer, char *buf, extern void srv6_function_free(struct bgp_srv6_function *func); +extern void bgp_session_reset_safe(struct peer *peer, struct listnode **nnode); + #ifdef _FRR_ATTRIBUTE_PRINTFRR /* clang-format off */ #pragma FRR printfrr_ext "%pBP" (struct peer *) diff --git a/debian/control b/debian/control index 12b80a77f3..4a02a36b71 100644 --- a/debian/control +++ b/debian/control @@ -33,7 +33,11 @@ Build-Depends: bison, python3-sphinx:native, texinfo (>= 4.7), lua5.3 , - liblua5.3-dev + liblua5.3-dev , + libgrpc-dev (>=1.16.1) , + libgrpc++-dev (>=1.16.1) , + protobuf-compiler (>=3.6.1) , + protobuf-compiler-grpc (>=1.16.1) Standards-Version: 4.5.0.3 Homepage: https://www.frrouting.org/ Vcs-Browser: https://github.com/FRRouting/frr/tree/debian/master @@ -136,3 +140,13 @@ Description: FRRouting suite - Python tools . Without this package installed, "reload" (as a systemd or init script invocation) will not work for the FRR daemons. + +Package: frr-grpc +Architecture: linux-any +Depends: frr (= ${binary:Version}), + ${misc:Depends}, + ${shlibs:Depends} +Description: FRRouting suite - GRPC interface + This provides the GRPC interface to the daemons. +Build-Profiles: + diff --git a/debian/copyright b/debian/copyright index edd73020bd..e1a944b338 100644 --- a/debian/copyright +++ b/debian/copyright @@ -4,6 +4,13 @@ Upstream-Contact: maintainers@frrouting.org, security@frrouting.org Source: https://www.frrouting.org/ Files: * +Comment: Note: GPL Versions of FRR binaries + If GRPC module is installed then please be aware that the + combination of the GRPC (licensed under Apache License) and + FRR (Licensed under GPLv2+) will force the resulting grpc + modules and related binaries to GPLv3 + Impacted binary files: frr/libfrrgrpc_pb.* frr/modules/grpc.so + FRR built or used without GRPC is not impacted Copyright: 1996-2003 by the original Zebra authors: Kunihiro Ishiguro Toshiaki Takada @@ -377,6 +384,24 @@ License: LGPL-2.1+ License version 2.1 can be found in the file `/usr/share/common-licenses/LGPL-2.1'. +License: GPL-3 + This package is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + . + This package is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + . + You should have received a copy of the GNU General Public License + along with this package; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + . + On Debian systems, the complete text of the GNU General + Public License can be found in `/usr/share/common-licenses/GPL-3'. + License: BSD-0-clause Redistribution and use in source and binary forms, with or without modification, are permitted. diff --git a/debian/frr-grpc.install b/debian/frr-grpc.install new file mode 100644 index 0000000000..d006439e6f --- /dev/null +++ b/debian/frr-grpc.install @@ -0,0 +1,2 @@ +usr/lib/*/frr/libfrrgrpc_pb.* +usr/lib/*/frr/modules/grpc.so diff --git a/debian/rules b/debian/rules index 0f84145718..ec8f92f755 100755 --- a/debian/rules +++ b/debian/rules @@ -33,6 +33,12 @@ else CONF_PIM6=--disable-pim6d endif +ifeq ($(filter pkg.frr.grpc,$(DEB_BUILD_PROFILES)),) + CONF_GRPC=--disable-grpc +else + CONF_GRPC=--enable-grpc +endif + export PYTHON=python3 %: @@ -51,6 +57,7 @@ override_dh_auto_configure: $(CONF_RPKI) \ $(CONF_LUA) \ $(CONF_PIM6) \ + $(CONF_GRPC) \ --with-libpam \ --enable-doc \ --enable-doc-html \ diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 495c604ae0..76dd1e4f28 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -18,6 +18,7 @@ import pygments from sphinx.highlighting import lexers from sphinx.util import logging + logger = logging.getLogger(__name__) # If extensions (or modules to document with autodoc) are in another directory, @@ -53,18 +54,18 @@ master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +release = "?.?-?" # ----------------------------------------------------------------------------- @@ -95,7 +96,7 @@ # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): @@ -287,7 +288,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR Developer's Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR Developer's Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +316,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR Developer's Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR Developer's Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +331,7 @@ ( master_doc, "frr", - u"FRR Developer's Manual", + "FRR Developer's Manual", author, "FRR", "One line description of project.", @@ -358,27 +359,29 @@ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() -frrfmt_re = re.compile(r'^\s*%(?P[^\s]+)\s+\((?P.*)\)\s*$') +frrfmt_re = re.compile(r"^\s*%(?P[^\s]+)\s+\((?P.*)\)\s*$") + def parse_frrfmt(env, text, node): from sphinx import addnodes m = frrfmt_re.match(text) if not m: - logger.warning('could not parse frrfmt:: %r' % (text), location=node) + logger.warning("could not parse frrfmt:: %r" % (text), location=node) node += addnodes.desc_name(text, text) return text - spec, types = m.group('spec'), m.group('types') + spec, types = m.group("spec"), m.group("types") - node += addnodes.desc_sig_operator('%', '%') - node += addnodes.desc_name(spec + ' ', spec + ' ') + node += addnodes.desc_sig_operator("%", "%") + node += addnodes.desc_name(spec + " ", spec + " ") plist = addnodes.desc_parameterlist() - for typ in types.split(','): + for typ in types.split(","): typ = typ.strip() plist += addnodes.desc_parameter(typ, typ) node += plist - return '%' + spec + return "%" + spec + # custom extensions here def setup(app): diff --git a/doc/developer/ospf-ls-retrans.rst b/doc/developer/ospf-ls-retrans.rst new file mode 100644 index 0000000000..230d7a1c5d --- /dev/null +++ b/doc/developer/ospf-ls-retrans.rst @@ -0,0 +1,69 @@ +OSPF Neighor Retransmission List +================================ + +Overview +-------- + +OSPF neighbor link-state retransmission lists are implemented using +both a sparse Link State Database (LSDB) and a doubly-linked list. +Rather than previous per-neighbor periodic timer, a per-neighbor +timer is set to the expiration time of the next scheduled LSA +retransmission. + +Sparse Link State Database (LSDB) +--------------------------------- + +When an explicit or implied acknowledgment is recieved from a +neighbor in 2-way state or higher, the acknowledge LSA must be +removed from the neighbor's link state retransmission list. In order +to do this efficiently, a sparse LSDB is utilized. LSDB entries also +include a pointer to the corresponding list entry so that it may be +efficiently removed from the doubly-linked list. + +The sparse LSDB is implemented using the OSPF functions is +ospf_lsdb.[c,h]. OSPF LSDBs are implemented as an array of route +tables (lib/table.[c,h]). What is unique of the LS Retransmission +list LSDB is that each entry also has a pointer into the doubly-linked +list to facilitate fast deletions. + +Doubly-Linked List +------------------ + +In addition to the sparse LSDB, LSAs on a neighbor LS retransmission +list are also maintained in a linked-list order chronologically +with the LSA scheduled for the next retransmission at the head of +the list. + +The doubly-link list is implemented using the dlist macros in +lib/typesafe.h. + +LSA LS Retransmission List Addition +------------------------------------ + +When an LSA is added to a neighbor retransmission list, it is +added to both the sparse LSDB and the doubly-linked list with a pointer +in the LSDB route-table node to the list entry. The LSA is added to +the tail of the list with the expiration time set to the current time +with the retransmission interval added. If the neighbor retransmission +timer is not set, it is set to expire at the time of the newly added +LSA. + +LSA LS Retransmission List Deletion +----------------------------------- + +When an LSA is deleted from a neighbor retransmission list, it is +deleted from eboth the sparse LSDB and the doubly-linked list with the +pointer the LSDB route-table node used to efficiently delete the entry +from the list. If the LSA at the head of the list was removed, then +the neighbor retransmission timer is reset to the expiration of the +LSA at the head of the list or canceled if the list is empty. + +Neighbor LS Retransmission List Expiration +------------------------------------------ + +When the neighbor retransmission timer expires, the LSA at the top of +list and any in a configured window (e.g., 50 milliseconds) are +retransmitted. The LSAs that have been retransmitted are removed from +the list and readded to the tail of the list with a new expiration time +which is retransmit-interval seconds in the future. + diff --git a/doc/developer/ospf.rst b/doc/developer/ospf.rst index 837a0bd185..da4802533c 100644 --- a/doc/developer/ospf.rst +++ b/doc/developer/ospf.rst @@ -8,6 +8,7 @@ OSPFD :maxdepth: 2 ospf-api + ospf-ls-retrans ospf-sr cspf diff --git a/doc/developer/packaging-debian.rst b/doc/developer/packaging-debian.rst index c2c3b7e7e1..4109057ee5 100644 --- a/doc/developer/packaging-debian.rst +++ b/doc/developer/packaging-debian.rst @@ -68,6 +68,8 @@ buster.) +----------------+-------------------+-----------------------------------------+ | pkg.frr.pim6d | pkg.frr.nopim6d | builds pim6d (default enabled) | +----------------+-------------------+-----------------------------------------+ + | pkg.frr.grpc | pkg.frr.nogrpc | builds with grpc support (default: no) | + +----------------+-------------------+-----------------------------------------+ * the ``-uc -us`` options to disable signing the packages with your GPG key diff --git a/doc/developer/packaging-redhat.rst b/doc/developer/packaging-redhat.rst index d88f449926..8037873461 100644 --- a/doc/developer/packaging-redhat.rst +++ b/doc/developer/packaging-redhat.rst @@ -67,24 +67,27 @@ Tested on CentOS 6, CentOS 7, CentOS 8 and Fedora 24. ############### FRRouting (FRR) configure options ################# # with-feature options - %{!?with_pam: %global with_pam 0 } - %{!?with_ospfclient: %global with_ospfclient 1 } - %{!?with_ospfapi: %global with_ospfapi 1 } - %{!?with_irdp: %global with_irdp 1 } - %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_babeld: %global with_babeld 1 } + %{!?with_bfdd: %global with_bfdd 1 } + %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_cumulus: %global with_cumulus 0 } + %{!?with_eigrpd: %global with_eigrpd 1 } + %{!?with_fpm: %global with_fpm 1 } + %{!?with_mgmtd_test_be_client: %global with_mgmtd_test_be_client 0 } %{!?with_ldpd: %global with_ldpd 1 } - %{!?with_nhrpd: %global with_nhrpd 1 } - %{!?with_eigrp: %global with_eigrpd 1 } - %{!?with_shared: %global with_shared 1 } %{!?with_multipath: %global with_multipath 256 } - %{!?frr_user: %global frr_user frr } - %{!?vty_group: %global vty_group frrvty } - %{!?with_fpm: %global with_fpm 0 } - %{!?with_watchfrr: %global with_watchfrr 1 } - %{!?with_bgp_vnc: %global with_bgp_vnc 0 } + %{!?with_nhrpd: %global with_nhrpd 1 } + %{!?with_ospfapi: %global with_ospfapi 1 } + %{!?with_ospfclient: %global with_ospfclient 1 } + %{!?with_pam: %global with_pam 0 } + %{!?with_pbrd: %global with_pbrd 1 } %{!?with_pimd: %global with_pimd 1 } %{!?with_pim6d: %global with_pim6d 1 } - %{!?with_rpki: %global with_rpki 0 } + %{!?with_vrrpd: %global with_vrrpd 1 } + %{!?with_rtadv: %global with_rtadv 1 } + %{!?with_watchfrr: %global with_watchfrr 1 } + %{!?with_pathd: %global with_pathd 1 } + %{!?with_grpc: %global with_grpc 0 } 8. Build the RPM:: diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index e1702c47c7..52c0361a02 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -411,6 +411,14 @@ for ``master`` branch: and create ``frr`` user and ``frrvty`` group as shown above. +Newer versions of Address Sanitizers require a sysctl to be changed +to allow for the tests to be successfully run. This is also true +for Undefined behavior Sanitizers as well as Memory Sanitizer. + +.. code:: shell + + sysctl vm.mmap_rnd_bits=28 + Debugging Topotest Failures ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -750,6 +758,46 @@ IDE/editor if supported (e.g., the emacs ``cov-mode`` package) NOTE: the *.gcda files in ``/tmp/topotests/gcda`` are cumulative so if you do not remove them they will aggregate data across multiple topotest runs. +How to reproduce failed Tests +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Generally tests fail but recreating the test failure reliably is not necessarily +easy, or it happens once every 10 runs locally. Here are some generic strategies +that are employed to allow for the test to be reproduced reliably + +.. code:: console + + cd + ln -s test_the_test_name.py test_a.py + ln -s test_the_test_name.py test_b.py + +This allows you to run multiple copies of the same test with one full test run. +Additionally if you need to modify the test you don't need to recopy everything +to make it work. By adding multiple copies of the same occassionally failing test +you raise the odds of it failing again. Additionally you have easily accessible +good and bad runs to compare. + +.. code:: console + + sudo -E python3 -m pytest -n --dist=loadfile + +Choose a n value that is greater than the number of cpu's avalaible on the system. +This changes the timing and may or may not make it more likely that the test fails. +Be aware, though, that this changes memory requirements as well as may make other +tests fail more often as well. You should choose values that do not cause the system +to go into swap usage. + +.. code:: console + + stress -n + +By filling up cpu's with programs that do nothing you also change the timing again and +may cause the problem to happen more often. + +There is no magic bullet here. You as a developer might have to experiment with different +values and different combinations of the above to cause the problem to happen more often. +These are just the tools that we know of at this point in time. + .. _topotests_docker: @@ -1292,6 +1340,15 @@ Example: router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF) +or using unified config (specifying which daemons to run is optional): + +.. code:: py + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)), [ + TopoRouter.RD_ZEBRA + TopoRouter.RD_MGMTD, + TopoRouter.RD_BGP]) - The topology definition or build function diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index f720f6279e..a6bdec1e5b 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -1306,6 +1306,16 @@ MemorySanitizer to ``configure``. +UndefinedSanitizer + Similar to AddressSanitizer, this tool provides runtime instrumentation for + detecting use of undefined behavior in C. Testing your own code with this + tool before submission is encouraged. You can enable it by passing:: + + --enable-undefined-sanitizer + + to ``configure``. If you run FRR with this you will probably also have + to set ``sudo sysctl vm.mmap_rnd_bits=28`` + All of the above tools are available in the Clang/LLVM toolchain since 3.4. AddressSanitizer and ThreadSanitizer are available in recent versions of GCC, but are no longer actively maintained. MemorySanitizer is not available in GCC. @@ -1315,6 +1325,14 @@ but are no longer actively maintained. MemorySanitizer is not available in GCC. The different Sanitizers are mostly incompatible with each other. Please refer to GCC/LLVM documentation for details. +.. note:: + + The different sanitizers also require setting + + sysctl vm.mmap_rnd_bits=28 + + in order to work properly. + frr-format plugin This is a GCC plugin provided with FRR that does extended type checks for ``%pFX``-style printfrr extensions. To use this plugin, diff --git a/doc/manpages/bfd-options.rst b/doc/manpages/bfd-options.rst index e335ed120b..2bad5f1521 100644 --- a/doc/manpages/bfd-options.rst +++ b/doc/manpages/bfd-options.rst @@ -1,10 +1,33 @@ -BFD SOCKET ----------- +BFD +--- -The following option controls the BFD daemon control socket location. +The following options controls the BFD daemon auxiliary sockets. -.. option:: --bfdctl bfd-control-socket +.. option:: --dplaneaddr :
[<:port>] - Opens the BFD daemon control socket located at the pointed location. + Configure the distributed BFD data plane listening socket bind address. - (default: |INSTALL_PREFIX_STATE|/bfdd.sock) + One would expect the data plane to run in the same machine as FRR, so + the suggested configuration would be: + + ``--dplaneaddr unix:/var/run/frr/bfdd_dplane.sock`` + + Or using IPv4: + + ``--dplaneaddr ipv4:127.0.0.1`` + + Or using IPv6: + + ``--dplaneaddr ipv6:[::1]`` + + It is also possible to specify a port (for IPv4/IPv6 only): + + ``--dplaneaddr ipv6:[::1]:50701`` + + (if ommited the default port is ``50700``). + + It is also possible to operate in client mode (instead of listening for + connections). To connect to a data plane server append the letter 'c' to + the protocol, example: + + ``--dplaneaddr ipv4c:127.0.0.1`` diff --git a/doc/manpages/conf.py b/doc/manpages/conf.py index 73dea094ae..995885b220 100644 --- a/doc/manpages/conf.py +++ b/doc/manpages/conf.py @@ -91,7 +91,7 @@ # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): diff --git a/doc/user/overview.rst b/doc/user/about.rst similarity index 94% rename from doc/user/overview.rst rename to doc/user/about.rst index 2ef88acd7a..ba80a324d3 100644 --- a/doc/user/overview.rst +++ b/doc/user/about.rst @@ -1,47 +1,8 @@ .. _overview: -******** -Overview -******** - -`FRR`_ is a fully featured, high performance, free software IP routing suite. - -FRR implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and -more (see :ref:`feature-matrix`), as well as many of their extensions. - -FRR is a high performance suite written primarily in C. It can easily handle -full Internet routing tables and is suitable for use on hardware ranging from -cheap SBCs to commercial grade routers. It is actively used in production by -hundreds of companies, universities, research labs and governments. - -FRR is distributed under GPLv2, with development modeled after the Linux -kernel. Anyone may contribute features, bug fixes, tools, documentation -updates, or anything else. - -FRR is a fork of `Quagga `_. - -.. _how-to-get-frr: - -How to get FRR -============== - -The official FRR website is located at |PACKAGE_URL| and contains further -information, as well as links to additional resources. - -Several distributions provide packages for FRR. Check your distribution's -repositories to find out if a suitable version is available. - -Up-to-date Debian & Redhat packages are available at https://deb.frrouting.org/ -& https://rpm.frrouting.org/ respectively. - -For instructions on installing from source, refer to the -`developer documentation `_. - - -.. _about-frr: - +********* About FRR -========= +********* FRR provides IP routing services. Its role in a networking stack is to exchange routing information with other routers, make routing and policy decisions, and @@ -55,11 +16,8 @@ light L2 functionality as well, but this is mostly left to the platform. This makes it suitable for deployments ranging from small home networks with static routes to Internet exchanges running full Internet tables. -FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. -Feature support varies by platform; see the :ref:`feature-matrix`. - System Requirements -------------------- +=================== System resources needed by FRR are highly dependent on workload. Routing software performance is particularly susceptible to external factors such as: @@ -86,8 +44,8 @@ information with peers about how to forward packets. Forwarding plane performance largely depends on choice of NIC / ASIC. -System Architecture -------------------- +Architecture +============ .. index:: pair: architecture; FRR @@ -146,9 +104,8 @@ routing stack. .. _supported-platforms: -Supported Platforms -------------------- - +Platform Support +================ Currently FRR supports GNU/Linux and BSD. Porting FRR to other platforms is not too difficult as platform dependent code should be mostly limited to the @@ -366,6 +323,8 @@ BGP :t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009.` - :rfc:`5668` :t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009.` +- :rfc:`5701` + :t:`IPv6 Address Specific BGP Extended Community Attribute. Y. Rekhter. 2009.` - :rfc:`6286` :t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan. June 2011.` - :rfc:`6472` diff --git a/doc/user/basics.rst b/doc/user/basics.rst new file mode 100644 index 0000000000..4504e9893c --- /dev/null +++ b/doc/user/basics.rst @@ -0,0 +1,23 @@ +.. _basics: + +###### +Basics +###### + +.. toctree:: + :maxdepth: 2 + + basic + extlog + vtysh + grpc + filter + routemap + affinitymap + ipv6 + kernel + snmp + scripting + nexthop_groups + + diff --git a/doc/user/bfd.rst b/doc/user/bfd.rst index 3ca104a3a9..5c5584e28f 100644 --- a/doc/user/bfd.rst +++ b/doc/user/bfd.rst @@ -1,12 +1,19 @@ .. _bfd: -********************************** -Bidirectional Forwarding Detection -********************************** +*** +BFD +*** -:abbr:`BFD (Bidirectional Forwarding Detection)` stands for -Bidirectional Forwarding Detection and it is described and extended by -the following RFCs: +:abbr:`BFD (Bidirectional Forwarding Detection)` is: + + a protocol intended to detect faults in the bidirectional path between two + forwarding engines, including interfaces, data link(s), and to the extent + possible the forwarding engines themselves, with potentially very low + latency. + + -- :rfc:`5880` + +It is described and extended by the following RFCs: * :rfc:`5880` * :rfc:`5881` @@ -38,19 +45,6 @@ may also be specified (:ref:`common-invocation-options`). .. program:: bfdd -.. option:: --bfdctl - - Set the BFD daemon control socket location. If using a non-default - socket location:: - - /usr/lib/frr/bfdd --bfdctl /tmp/bfdd.sock - - - The default UNIX socket location is |INSTALL_PREFIX_STATE|/bfdd.sock - - This option overrides the location addition that the -N option provides - to the bfdd.sock - .. option:: --dplaneaddr :
[<:port>] Configure the distributed BFD data plane listening socket bind address. diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 150a915e3a..a569a9af28 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -92,6 +92,12 @@ be specified (:ref:`common-invocation-options`). the operator has turned off communication to zebra and is running bgpd as a complete standalone process. +.. option:: -K, --graceful_restart + + Bgpd will use this option to denote either a planned FRR graceful + restart or a bgpd-only graceful restart, and this will drive the BGP + GR restarting router procedures. + LABEL MANAGER ------------- @@ -1080,6 +1086,52 @@ Default global mode is helper and default peer per mode is inherit from global. If per peer mode is configured, the GR mode of this particular peer will override the global mode. +.. _bgp-GR-config-mode-cmd: + +BGP GR Config Mode Commands +^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. clicmd:: bgp graceful-restart + + This command will enable BGP graceful restart functionality for all BGP instances. + +.. clicmd:: bgp graceful-restart-disable + + This command will disable both the functionality graceful restart and helper + mode for all BGP instances + +.. clicmd:: bgp graceful-restart select-defer-time (0-3600) + + This is command, will set deferral time to value specified. + +.. clicmd:: bgp graceful-restart rib-stale-time (1-3600) + + This is command, will set the time for which stale routes are kept in RIB. + +.. clicmd:: bgp graceful-restart restart-time (0-4095) + + Set the time to wait to delete stale routes before a BGP open message + is received. + + Using with Long-lived Graceful Restart capability, this is recommended + setting this timer to 0 and control stale routes with + ``bgp long-lived-graceful-restart stale-time``. + + Default value is 120. + +.. clicmd:: bgp graceful-restart stalepath-time (1-4095) + + This is command, will set the max time (in seconds) to hold onto + restarting peer's stale paths. + + It also controls Enhanced Route-Refresh timer. + + If this command is configured and the router does not receive a Route-Refresh EoRR + message, the router removes the stale routes from the BGP table after the timer + expires. The stale path timer is started when the router receives a Route-Refresh + BoRR message + + .. _bgp-GR-global-mode-cmd: BGP GR Global Mode Commands @@ -1509,6 +1561,10 @@ Defining Peers peers ASN is the same as mine as specified under the :clicmd:`router bgp ASN` command the connection will be denied. +.. clicmd:: neighbor PEER remote-as auto + + The neighbor's ASN is detected automatically from the OPEN message. + .. clicmd:: neighbor PEER oad Mark a peer belonging to the One Administrative Domain. @@ -1647,7 +1703,7 @@ Configuring Peers IPv4 session addresses, see the ``neighbor PEER update-source`` command below. -.. clicmd:: neighbor PEER interface remote-as +.. clicmd:: neighbor PEER interface remote-as Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The session will be established via IPv6 link locals. Use ``internal`` for iBGP diff --git a/doc/user/conf.py b/doc/user/conf.py index 728f9c9364..18f048bc08 100644 --- a/doc/user/conf.py +++ b/doc/user/conf.py @@ -18,6 +18,8 @@ import pygments import sphinx from sphinx.highlighting import lexers +from sphinx.domains.std import GenericObject +from docutils.parsers.rst import directives # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the @@ -52,18 +54,18 @@ master_doc = "index" # General information about the project. -project = u"FRR" -copyright = u"2017, FRR" -author = u"FRR authors" +project = "FRR" +copyright = "2017, FRR" +author = "FRR authors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # The short X.Y version. -version = u"?.?" +version = "?.?" # The full version, including alpha/beta/rc tags. -release = u"?.?-?" +release = "?.?-?" # ----------------------------------------------------------------------------- @@ -94,7 +96,7 @@ # extract version information, installation location, other stuff we need to # use when building final documents -val = re.compile('^S\["([^"]+)"\]="(.*)"$') +val = re.compile(r'^S\["([^"]+)"\]="(.*)"$') try: with open("../../config.status", "r") as cfgstatus: for ln in cfgstatus.readlines(): @@ -287,7 +289,7 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, "FRR.tex", u"FRR User Manual", u"FRR", "manual"), + (master_doc, "FRR.tex", "FRR User Manual", "FRR", "manual"), ] # The name of an image file (relative to this directory) to place at the top of @@ -315,7 +317,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [(master_doc, "frr", u"FRR User Manual", [author], 1)] +man_pages = [(master_doc, "frr", "FRR User Manual", [author], 1)] # If true, show URL addresses after external links. # man_show_urls = False @@ -330,7 +332,7 @@ ( master_doc, "frr", - u"FRR User Manual", + "FRR User Manual", author, "FRR", "One line description of project.", @@ -358,6 +360,7 @@ with open("../extra/frrlexer.py", "rb") as lex: frrlexerpy = lex.read() + # Parse version string into int array def vparse(s): a = [] @@ -372,11 +375,54 @@ def vparse(s): return a[:3] -# custom extensions here +class ClicmdDirective(GenericObject): + """ + Directive for documenting CLI commands. + + The xref string, if no option is provided, will be the verbatim command + string. If the :daemon: option is provided, then it's + "() )". + + Options: + :daemon: - specify the daemon this command belongs to. Useful for + disambiguating multiple definitions of the same command. + """ + + has_content = True + required_arguments = 1 + optional_arguments = 0 + option_spec = { + **GenericObject.option_spec, + "daemon": directives.unchanged, + } + + def handle_signature(self, sig, signode): + name = super().handle_signature(sig, signode) + daemon = self.options["daemon"] if "daemon" in self.options else "" + prefix = f"({daemon}) " if daemon else "" + return prefix + name + + def run(self): + daemon = self.options["daemon"] if "daemon" in self.options else "" + if daemon: + self.indextemplate = f"pair: ({daemon}) %s; configuration command" + else: + self.indextemplate = f"pair: %s; configuration command" + + nodes = super().run() + + return nodes + + def setup(app): - # object type for FRR CLI commands, can be extended to document parent CLI - # node later on - app.add_object_type("clicmd", "clicmd", indextemplate="pair: %s; configuration command") + # Override the directive that was just created for us + if int(sphinx.__version__.split(".")[0]) >= 2: + app.add_object_type("clicmd", "clicmd", objname="CLI command") + app.add_directive_to_domain("std", "clicmd", ClicmdDirective, override=True) + else: + app.add_object_type( + "clicmd", "clicmd", indextemplate="pair: %s; configuration command" + ) # I dont care how stupid this is if "add_js_file" in dir(app): @@ -389,7 +435,6 @@ def setup(app): else: app.add_stylesheet("overrides.css") - # load Pygments lexer for FRR config syntax # # NB: in Pygments 2.2+ this can be done with `load_lexer_from_file`, but we diff --git a/doc/user/index.rst b/doc/user/index.rst index 4789677a9a..d3b632a8de 100644 --- a/doc/user/index.rst +++ b/doc/user/index.rst @@ -1,80 +1,31 @@ FRRouting User Guide ==================== -############ -Introduction -############ +FRR is a fully featured, high performance, free software IP routing suite. It +implements all standard routing protocols such as BGP, RIP, OSPF, IS-IS and +more (see :ref:`feature-matrix`), as well as many of their extensions. It can +handle full Internet routing tables and is suitable for use on hardware ranging +from cheap SBCs to commercial grade routers, and is actively used in production +by hundreds of companies, universities, research labs and governments. -.. _introduction: -.. toctree:: - :maxdepth: 2 - - overview - installation - setup - -###### -Basics -###### +FRR runs on all modern \*NIX operating systems, including Linux and the BSDs. +Feature support varies by platform; see the :ref:`feature-matrix`. -.. _basics: -.. toctree:: - :maxdepth: 2 +FRR is distributed under GPLv2, with development modeled after the Linux +kernel. Anyone may contribute features, bug fixes, tools, documentation +updates, or anything else. - basic - extlog - vtysh - grpc - filter - routemap - affinitymap - ipv6 - kernel - snmp - scripting - nexthop_groups -.. modules +FRR is a fork of `Quagga `_. -######### -Protocols -######### - -.. _protocols: .. toctree:: :maxdepth: 2 - zebra - bfd - bgp - babeld - fabricd - ldpd - eigrpd - evpn - isisd - nhrpd - ospfd - ospf6d - pathd - pim - pimv6 - pbr - ripd - ripngd - sharp - static - vnc - vrrp - bmp - watchfrr - mgmtd - -######## -Appendix -######## + introduction + basics + protocols -.. _appendix: .. toctree:: + :caption: Appendix :maxdepth: 2 bugs diff --git a/doc/user/installation.rst b/doc/user/installation.rst index e49f10491e..4d2017c0f8 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -3,22 +3,25 @@ single: Installing FRR single: Building FRR -.. _installation: - Installation ============ -This section covers the basics of building, installing and setting up FRR. +This section covers the basics of building, installing and setting up +FRR. +The official FRR website is located at |PACKAGE_URL| and contains further +information, as well as links to additional resources. From Packages ------------- -The project publishes packages for Red Hat, Centos, Debian and Ubuntu on the -`GitHub releases `_. page. External -contributors offer packages for many other platforms including \*BSD, Alpine, -Gentoo, Docker, and others. There is currently no documentation on how to use -those but we hope to add it soon. +Up-to-date Debian & Redhat packages are available at +https://deb.frrouting.org/ & https://rpm.frrouting.org/ respectively. + +Several distributions also provide packages for FRR. Check your +distribution's repositories to find out if a suitable version is +available. + From Snapcraft -------------- @@ -29,12 +32,12 @@ universal Snap images, available at https://snapcraft.io/frr. From Source ----------- -Building FRR from source is the best way to ensure you have the latest features -and bug fixes. Details for each supported platform, including dependency -package listings, permissions, and other gotchas, are in the `developer's -documentation -`_. This -section provides a brief overview on the process. +Building FRR from source is the best way to ensure you have the latest +features and bug fixes. Details for each supported platform, including +dependency package listings, permissions, and other gotchas, are in the +`developer's documentation +`_. +This section provides a brief overview on the process. Getting the Source diff --git a/doc/user/introduction.rst b/doc/user/introduction.rst new file mode 100644 index 0000000000..89866b9c29 --- /dev/null +++ b/doc/user/introduction.rst @@ -0,0 +1,13 @@ +.. _introduction: + +############ +Introduction +############ + +.. toctree:: + :maxdepth: 2 + + about + installation + setup + diff --git a/doc/user/isisd.rst b/doc/user/isisd.rst index 7412611869..3a0f277bf0 100644 --- a/doc/user/isisd.rst +++ b/doc/user/isisd.rst @@ -325,7 +325,7 @@ Showing ISIS information Show topology IS-IS paths to Intermediate Systems, globally, in area (level-1) or domain (level-2). -.. clicmd:: show isis [vrf ] route [level-1|level-2] [prefix-sid|backup] [algorithm [(128-255)]] +.. clicmd:: show isis [vrf ] route [level-1|level-2] [prefix-sid] [backup] [algorithm [(128-255)]] Show the ISIS routing table, as determined by the most recent SPF calculation. diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst index cbed734e42..7a000a49c4 100644 --- a/doc/user/ldpd.rst +++ b/doc/user/ldpd.rst @@ -148,7 +148,7 @@ LDP Configuration configured password. PASSWORD is a clear text password wit its digest sent through the network. -.. clicmd:: neighbor A.B.C.D holdtime HOLDTIME +.. clicmd:: neighbor A.B.C.D session holdtime HOLDTIME The following command located under MPLS router node configures the holdtime value in seconds of the LDP neighbor ID. Configuring it triggers a keepalive diff --git a/doc/user/nhrpd.rst b/doc/user/nhrpd.rst index 54527a0c9a..648d56d9c1 100644 --- a/doc/user/nhrpd.rst +++ b/doc/user/nhrpd.rst @@ -84,6 +84,12 @@ Configuring NHRP registration requests are sent. By default registrations are sent every one third of the holdtime. +.. clicmd:: ip nhrp authentication PASSWORD + + Enables Cisco style authentication on NHRP packets. This embeds the + plaintext password to the outgoing NHRP packets. + Maximum length of the password is 8 characters. + .. clicmd:: ip nhrp map A.B.C.D|X:X::X:X A.B.C.D|local Map an IP address of a station to the station's NBMA address. diff --git a/doc/user/ospfd.rst b/doc/user/ospfd.rst index 70c15e73de..b80adba7f0 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -738,7 +738,17 @@ Interfaces retransmitting Database Description and Link State Request packets. The default value is 5 seconds. -.. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] +.. clicmd:: ip ospf retransmit-window (20-1000) + + + Set number of milliseconds in the window for neighbor LSA retransmission. + When a neighbor Link State (LS) retransmission timer expires, LSAs scheduled + to be retransmitted within the number of milliseconds configured are + retransmitted to the neighbor. Any expiring after the window will be + retransmitted the next time the neighbor LS retransmission timer expires. + The default is 50 milliseconds. + + .. clicmd:: ip ospf transmit-delay (1-65535) [A.B.C.D] Set number of seconds for InfTransDelay value. LSAs' age should be diff --git a/doc/user/pim.rst b/doc/user/pim.rst index b19bb9d1b3..1740828f26 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -55,16 +55,23 @@ Certain signals have special meanings to *pimd*. *pimd* invocation options. Common options that can be specified (:ref:`common-invocation-options`). -.. clicmd:: ip pim rp A.B.C.D A.B.C.D/M +PIM Routers +----------- + +.. clicmd:: router pim [vrf NAME] + + Configure global PIM protocol + +.. clicmd:: rp A.B.C.D A.B.C.D/M In order to use pim, it is necessary to configure a RP for join messages to be sent to. Currently the only methodology to do this is via static rp commands. All routers in the pim network must agree on these values. The first ip address is the RP's address and the second value is the matching prefix of group ranges covered. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim rp keep-alive-timer (1-65535) +.. clicmd:: rp keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds at RP. The normal keepalive period for the KAT(S,G) defaults to 210 seconds. @@ -74,41 +81,41 @@ Certain signals have special meanings to *pimd*. max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is - vrf aware, to configure for a vrf, enter the vrf submode. + vrf aware, to configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim register-accept-list PLIST +.. clicmd:: register-accept-list PLIST When pim receives a register packet the source of the packet will be compared to the prefix-list specified, PLIST, and if a permit is received normal processing continues. If a deny is returned for the source address of the register packet a register stop message is sent to the source. -.. clicmd:: ip pim spt-switchover infinity-and-beyond [prefix-list PLIST] +.. clicmd:: spt-switchover infinity-and-beyond [prefix-list PLIST] On the last hop router if it is desired to not switch over to the SPT tree configure this command. Optional parameter prefix-list can be use to control which groups to switch or not switch. If a group is PERMIT as per the PLIST, then the SPT switchover does not happen for it and if it is DENY, then the SPT switchover happens. - This command is vrf aware, to configure for a vrf, - enter the vrf submode. + This command is vrf aware, to configure for a vrf, specify the vrf in the + router pim block. -.. clicmd:: ip pim ecmp +.. clicmd:: ecmp If pim has the a choice of ECMP nexthops for a particular RPF, pim will cause S,G flows to be spread out amongst the nexthops. If this command is not specified then the first nexthop found will be used. This command is vrf - aware, to configure for a vrf, enter the vrf submode. + aware, to configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim ecmp rebalance +.. clicmd:: ecmp rebalance If pim is using ECMP and an interface goes down, cause pim to rebalance all S,G flows across the remaining nexthops. If this command is not configured pim only modifies those S,G flows that were using the interface that went - down. This command is vrf aware, to configure for a vrf, enter the vrf - submode. + down. This command is vrf aware, to configure for a vrf, specify the vrf in + the router pim block. -.. clicmd:: ip pim join-prune-interval (1-65535) +.. clicmd:: join-prune-interval (1-65535) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, @@ -116,39 +123,45 @@ Certain signals have special meanings to *pimd*. a value smaller than 60 seconds be aware that this can and will affect convergence at scale. -.. clicmd:: ip pim keep-alive-timer (1-65535) +.. clicmd:: keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim packets (1-255) +.. clicmd:: packets (1-255) When processing packets from a neighbor process the number of packets incoming at one time before moving on to the next task. The default value is 3 packets. This command is only useful at scale when you can possibly have a large number of pim control packets flowing. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim register-suppress-time (1-65535) +.. clicmd:: register-suppress-time (1-65535) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a - vrf, enter the vrf submode. + vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim send-v6-secondary +.. clicmd:: send-v6-secondary When sending pim hello packets tell pim to send any v6 secondary addresses on the interface. This information is used to allow pim to use v6 nexthops in it's decision for RPF lookup. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim block. -.. clicmd:: ip pim ssm prefix-list WORD +.. clicmd:: ssm prefix-list WORD Specify a range of group addresses via a prefix-list that forces pim to - never do SM over. This command is vrf aware, to configure for a vrf, enter - the vrf submode. + never do SM over. This command is vrf aware, to configure for a vrf, specify + the vrf in the router pim block. + +Global Multicast +---------------- + +These commands are valid at the top-level of the configuration (or also per +vrf where indicated), instead of under the 'router pim' submode. .. clicmd:: ip multicast rpf-lookup-mode WORD @@ -333,12 +346,16 @@ MSDP can be setup in different ways: .. note:: - MSDP default peer and SA filtering is not implemented. + MSDP default peer is not implemented. +Commands available for MSDP +--------------------------- -Commands available for MSDP: +.. note:: -.. clicmd:: ip msdp timers (1-65535) (1-65535) [(1-65535)] + MSDP configuration is available under 'router pim'. + +.. clicmd:: msdp timers (1-65535) (1-65535) [(1-65535)] Configure global MSDP timers. @@ -354,19 +371,39 @@ Commands available for MSDP: configures the interval between connection attempts. The default value is 30 seconds. -.. clicmd:: ip msdp mesh-group WORD member A.B.C.D +.. clicmd:: msdp mesh-group WORD member A.B.C.D Create or update a mesh group to include the specified MSDP peer. -.. clicmd:: ip msdp mesh-group WORD source A.B.C.D +.. clicmd:: msdp mesh-group WORD source A.B.C.D Create or update a mesh group to set the source address used to connect to peers. -.. clicmd:: ip msdp peer A.B.C.D source A.B.C.D +.. clicmd:: msdp peer A.B.C.D source A.B.C.D Create a regular MSDP session with peer using the specified source address. +.. clicmd:: msdp peer A.B.C.D sa-filter ACL_NAME + + Configure incoming or outgoing SA filtering rule. + + .. note:: + + The filtering will only take effect starting from the command + application. + +.. clicmd:: msdp peer A.B.C.D password WORD + + Use MD5 authentication to connect with the remote peer. + + .. note:: + + The authentication will only take effect when starting a new + connection. + + To apply it immediately call `clear ip msdp peer A.B.C.D`. + .. _show-pim-information: @@ -385,15 +422,9 @@ cause great confusion. .. clicmd:: show ip igmp [vrf NAME] join [json] - Display IGMP static join information for a specific vrf. - -.. index:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] -.. clicmd:: show ip igmp [vrf NAME$vrf_name] groups [INTERFACE$ifname [GROUP$grp_str]] [detail] [json$json] - - Display IGMP static join information for all the vrfs present. + Display IGMP static join information. -.. index:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] -.. clicmd:: show ip igmp vrf all groups [GROUP$grp_str] [detail$detail] [json$json] +.. clicmd:: show ip igmp [vrf NAME] groups [INTERFACE [GROUP]] [detail] [json] Display IGMP groups information. @@ -576,11 +607,11 @@ cause great confusion. Display current bsr, its uptime and last received bsm age. -.. clicmd:: show ip pim bsrp-info +.. clicmd:: show ip pim bsrp-info [vrf NAME] [json] Display group-to-rp mappings received from E-BSR. -.. clicmd:: show ip pim bsm-database +.. clicmd:: show ip pim bsm-database [vrf NAME] [json] Display all fragments of stored bootstrap message in user readable format. @@ -696,6 +727,13 @@ Clear commands reset various variables. removes the next hop tracking for the bsr and resets the upstreams for the dynamically learnt RPs. +.. clicmd:: clear ip msdp peer A.B.C.D + + Reset MSDP peer connection. + + Use this command to set/unset MD5 authentication. + + PIM EVPN configuration ====================== To use PIM in the underlay for overlay BUM forwarding associate a multicast @@ -734,8 +772,9 @@ Sample configuration ! You may want to enable ssmpingd for troubleshooting ! See http://www.venaas.no/multicast/ssmping/ ! - ip ssmpingd 1.1.1.1 - ip ssmpingd 2.2.2.2 + router pim + ssmpingd 1.1.1.1 + ssmpingd 2.2.2.2 ! HINTS: ! - Enable "ip pim ssm" on the interface directly attached to the @@ -750,4 +789,3 @@ Sample configuration interface eth0 ip pim ssm ip igmp - diff --git a/doc/user/pimv6.rst b/doc/user/pimv6.rst index b8567e4863..edf7a82015 100644 --- a/doc/user/pimv6.rst +++ b/doc/user/pimv6.rst @@ -47,21 +47,28 @@ Certain signals have special meanings to *pim6d*. *pim6d* invocation options. Common options that can be specified (:ref:`common-invocation-options`). -.. clicmd:: ipv6 pim rp X:X::X:X Y:Y::Y:Y/M +PIMv6 Router +------------ + +.. clicmd:: router pim6 [vrf NAME] + + Configure the global PIMv6 protocol + +.. clicmd:: rp X:X::X:X Y:Y::Y:Y/M In order to use pimv6, it is necessary to configure a RP for join messages to be sent to. Currently the only methodology to do this is via static rp commands. All routers in the pimv6 network must agree on these values. The first ipv6 address is the RP's address and the second value is the matching prefix of group ranges covered. This command is vrf aware, to configure for - a vrf, enter the vrf submode. + a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim rp X:X::X:X prefix-list WORD +.. clicmd:: rp X:X::X:X prefix-list WORD This CLI helps in configuring RP address for a range of groups specified by the prefix-list. -.. clicmd:: ipv6 pim rp keep-alive-timer (1-65535) +.. clicmd:: rp keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds at RP. The normal keepalive period for the KAT(S,G) defaults to 210 seconds. @@ -71,19 +78,19 @@ Certain signals have special meanings to *pim6d*. max(Keepalive_Period, RP_Keepalive_Period) when a Register-Stop is sent. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is - vrf aware, to configure for a vrf, enter the vrf submode. + vrf aware, to configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim spt-switchover infinity-and-beyond [prefix-list PLIST] +.. clicmd:: spt-switchover infinity-and-beyond [prefix-list PLIST] On the last hop router if it is desired to not switch over to the SPT tree configure this command. Optional parameter prefix-list can be use to control which groups to switch or not switch. If a group is PERMIT as per the PLIST, then the SPT switchover does not happen for it and if it is DENY, then the SPT switchover happens. - This command is vrf aware, to configure for a vrf, - enter the vrf submode. + This command is vrf aware, to configure for a vrf, specify the vrf in the + router pim6 block. -.. clicmd:: ipv6 pim join-prune-interval (1-65535) +.. clicmd:: join-prune-interval (1-65535) Modify the join/prune interval that pim uses to the new value. Time is specified in seconds. This command is vrf aware, to configure for a vrf, @@ -91,28 +98,28 @@ Certain signals have special meanings to *pim6d*. a value smaller than 60 seconds be aware that this can and will affect convergence at scale. -.. clicmd:: ipv6 pim keep-alive-timer (1-65535) +.. clicmd:: keep-alive-timer (1-65535) Modify the time out value for a S,G flow from 1-65535 seconds. If choosing a value below 31 seconds be aware that some hardware platforms cannot see data flowing in better than 30 second chunks. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim packets (1-255) +.. clicmd:: packets (1-255) When processing packets from a neighbor process the number of packets incoming at one time before moving on to the next task. The default value is 3 packets. This command is only useful at scale when you can possibly have a large number of pim control packets flowing. This command is vrf aware, to - configure for a vrf, enter the vrf submode. + configure for a vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 pim register-suppress-time (1-65535) +.. clicmd:: register-suppress-time (1-65535) Modify the time that pim will register suppress a FHR will send register notifications to the kernel. This command is vrf aware, to configure for a - vrf, enter the vrf submode. + vrf, specify the vrf in the router pim6 block. -.. clicmd:: ipv6 ssmpingd [X:X::X:X] +.. clicmd:: ssmpingd [X:X::X:X] Enable ipv6 ssmpingd configuration. A network level management tool to check whether one can receive multicast packets via SSM from host. @@ -388,11 +395,11 @@ General multicast routing state Display current bsr, its uptime and last received bsm age. -.. clicmd:: show ipv6 pim bsrp-info +.. clicmd:: show ipv6 pim bsrp-info [vrf NAME] [json] Display group-to-rp mappings received from E-BSR. -.. clicmd:: show ipv6 pim bsm-database +.. clicmd:: show ipv6 pim bsm-database [vrf NAME] [json] Display all fragments of stored bootstrap message in user readable format. @@ -417,7 +424,7 @@ Clear commands reset various variables. .. clicmd:: clear ipv6 pim [vrf NAME] interface traffic - When this command is issued, resets the information about the + When this command is issued, resets the information about the number of PIM protocol packets sent/received on an interface. .. clicmd:: clear ipv6 pim oil @@ -494,7 +501,7 @@ the config was written out. .. clicmd:: debug mld trace [detail] - This traces mld code and how it is running. + This traces mld code and how it is running. .. clicmd:: debug pimv6 bsm diff --git a/doc/user/protocols.rst b/doc/user/protocols.rst new file mode 100644 index 0000000000..e571cd66fc --- /dev/null +++ b/doc/user/protocols.rst @@ -0,0 +1,35 @@ +.. _protocols: + +######### +Protocols +######### + +.. toctree:: + :maxdepth: 2 + + zebra + bfd + bgp + babeld + fabricd + ldpd + eigrpd + evpn + isisd + nhrpd + ospfd + ospf6d + pathd + pim + pimv6 + pbr + ripd + ripngd + sharp + static + vnc + vrrp + bmp + watchfrr + mgmtd + diff --git a/doc/user/snmptrap.rst b/doc/user/snmptrap.rst index df534e28bd..52b1904665 100644 --- a/doc/user/snmptrap.rst +++ b/doc/user/snmptrap.rst @@ -215,3 +215,9 @@ possibility to select the MIB he wants to receive traps from: By default, only rfc4273 traps are enabled and sent. .. [Draft-IETF-idr-bgp4-mibv2-11] + +The :rfc:`4382` also defines traps to inform when an L3VPN network changes +the operational status of its VRF interface. The user can choose to suppress +those traps or not. + +.. clicmd:: bgp snmp traps rfc4382 diff --git a/doc/user/subdir.am b/doc/user/subdir.am index 4879f7f7ef..395ce305fe 100644 --- a/doc/user/subdir.am +++ b/doc/user/subdir.am @@ -29,7 +29,7 @@ user_RSTFILES = \ doc/user/ospf6d.rst \ doc/user/ospfd.rst \ doc/user/ospf_fundamentals.rst \ - doc/user/overview.rst \ + doc/user/about.rst \ doc/user/packet-dumps.rst \ doc/user/pathd.rst \ doc/user/pim.rst \ diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 37644dc88a..900d2fd343 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -1021,6 +1021,35 @@ and this section also helps that case. ! ... +.. clicmd:: format NAME + + Specify the SID allocation schema for the SIDs allocated from this locator. Currently, + FRR supports supports the following allocation schemas: + + - `usid-f3216` + - `uncompressed` + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# locators + router(config-srv6-locators)# locator loc1 + router(config-srv6-locator)# prefix fc00:0:1::/48 + router(config-srv6-locator)# format usid-f3216 + + router(config-srv6-locator)# show run + ... + segment-routing + srv6 + locators + locator loc1 + prefix fc00:0:1::/48 + format usid-f3216 + ! + ... + .. clicmd:: encapsulation Configure parameters for SRv6 encapsulation. @@ -1029,6 +1058,61 @@ and this section also helps that case. Configure the source address of the outer encapsulating IPv6 header. +.. clicmd:: formats + + Configure SRv6 SID formats. + +.. clicmd:: format NAME + + Configure SRv6 SID format. + +.. clicmd:: compressed usid + + Enable SRv6 uSID compression and configure SRv6 uSID compression parameters. + +.. clicmd:: local-id-block start START + + Configure the start value for the Local ID Block (LIB). + +.. clicmd:: local-id-block explicit start START end END + + Configure the start/end values for the Explicit LIB (ELIB). + +.. clicmd:: wide-local-id-block start START end END + + Configure the start/end values for the Wide LIB (W-LIB). + +.. clicmd:: wide-local-id-block explicit start START + + Configure the start value for the Explicit Wide LIB (EW-LIB). + +:: + + router# configure terminal + router(config)# segment-routinig + router(config-sr)# srv6 + router(config-srv6)# formats + router(config-srv6-formats)# format usid-f3216 + router(config-srv6-format)# compressed usid + router(config-srv6-format-usid)# local-id-block start 0xD000 + router(config-srv6-format-usid)# local-id-block explicit start 0xF000 end 0xFDFF + router(config-srv6-format-usid)# wide-local-id-block start 0xFFF4 end 0xFFF5 + router(config-srv6-format-usid)# wide-local-id-block explicit start 0xFFF4 + + router(config-srv6-locator)# show run + ... + segment-routing + srv6 + formats + format usid-f3216 + compressed usid + local-id-block start 0xD000 + local-id-block explicit start 0xF000 end 0xFDFF + wide-local-id-block start 0xFFF4 end 0xFFF5 + wide-local-id-block explicit start 0xFFF4 + ! + ... + .. _multicast-rib-commands: Multicast RIB Commands diff --git a/docker/alpine/Dockerfile b/docker/alpine/Dockerfile index 1cff06feee..3f811455b3 100644 --- a/docker/alpine/Dockerfile +++ b/docker/alpine/Dockerfile @@ -1,7 +1,7 @@ # syntax=docker/dockerfile:1 # Create a basic stage set up to build APKs -FROM alpine:3.19 as alpine-builder +FROM alpine:3.20 as alpine-builder RUN apk add \ --update-cache \ abuild \ @@ -24,7 +24,7 @@ RUN cd /src/libyang \ && abuild -r -P /pkgs/apk # This stage builds a dist tarball from the source -FROM alpine:3.19 as source-builder +FROM alpine:3.20 as source-builder RUN mkdir -p /src/alpine /pkgs/apk COPY alpine/APKBUILD.in /src/alpine COPY --from=alpine-apk-builder-libyang /pkgs/apk/src /pkgs/apk @@ -57,7 +57,7 @@ RUN cd /dist \ && abuild -r -P /pkgs/apk # This stage installs frr from the apk -FROM alpine:3.19 +FROM alpine:3.20 RUN mkdir -p /pkgs/apk COPY --from=alpine-apk-builder /pkgs/apk/ /pkgs/apk/ RUN apk add \ diff --git a/docker/alpine/libyang/APKBUILD b/docker/alpine/libyang/APKBUILD index 6973fd62d8..d8cd4d918a 100755 --- a/docker/alpine/libyang/APKBUILD +++ b/docker/alpine/libyang/APKBUILD @@ -11,6 +11,7 @@ makedepends="bison cmake cmocka-dev flex pcre2-dev" checkdepends="expect grep shunit2" subpackages="$pkgname-dev $pkgname-doc" source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkgver.tar.gz" +options="!check" # secfixes: # 1.0.215-r1: @@ -21,6 +22,7 @@ source="$pkgname-$pkgver.tar.gz::https://github.com/CESNET/libyang/archive/v$pkg # - CVE-2021-28906 build() { + export ABUILD_APK_INDEX_OPTS="--allow-untrusted" if [ "$CBUILD" != "$CHOST" ]; then CMAKE_CROSSOPTS="-DCMAKE_SYSTEM_NAME=Linux -DCMAKE_HOST_SYSTEM_NAME=Linux" fi diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index c04f8155ba..078280acf5 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -293,7 +293,7 @@ const char *isis_adj_name(const struct isis_adjacency *adj) struct isis_dynhn *dyn; dyn = dynhn_find_by_id(adj->circuit->isis, adj->sysid); - if (dyn) + if (adj->circuit->area->dynhostname && dyn) return dyn->hostname; snprintfrr(buf, sizeof(buf), "%pSY", adj->sysid); @@ -358,12 +358,15 @@ void isis_adj_state_change(struct isis_adjacency **padj, * purposes */ adj->last_flap = time(NULL); adj->flaps++; - } else if (old_state == ISIS_ADJ_UP) { - circuit->adj_state_changes++; + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->adj_state_changes++; - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { listnode_delete( @@ -409,10 +412,13 @@ void isis_adj_state_change(struct isis_adjacency **padj, master, send_l2_csnp, circuit, 0, &circuit->t_send_csnp[1]); } - } else if (old_state == ISIS_ADJ_UP) { - circuit->upadjcount[level - 1]--; - if (circuit->upadjcount[level - 1] == 0) - isis_tx_queue_clean(circuit->tx_queue); + } else { + if (old_state == ISIS_ADJ_UP) { + circuit->upadjcount[level - 1]--; + if (circuit->upadjcount[level - 1] == 0) + isis_tx_queue_clean( + circuit->tx_queue); + } if (new_state == ISIS_ADJ_DOWN) { if (adj->circuit->u.p2p.neighbor == adj) diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 7819b20e8f..fa1ce3007f 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -198,8 +198,8 @@ void isis_circuit_del(struct isis_circuit *circuit) ldp_sync_info_free(&circuit->ldp_sync_info); circuit_mt_finish(circuit); - isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL1); - isis_lfa_excluded_ifaces_clear(circuit, ISIS_LEVEL2); + isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL1); + isis_lfa_excluded_ifaces_delete(circuit, ISIS_LEVEL2); list_delete(&circuit->ip_addrs); list_delete(&circuit->ipv6_link); diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 32231a079f..5574bbc50f 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -83,6 +83,7 @@ static void circuit_commence_level(struct isis_circuit *circuit, int level) send_hello_sched(circuit, level, TRIGGERED_IIH_DELAY); circuit->u.bc.lan_neighs[level - 1] = list_new(); + circuit->u.bc.adjdb[level - 1] = list_new(); } } @@ -108,6 +109,10 @@ static void circuit_resign_level(struct isis_circuit *circuit, int level) circuit->u.bc.is_dr[idx] = 0; if (circuit->u.bc.lan_neighs[idx] != NULL) list_delete(&circuit->u.bc.lan_neighs[idx]); + if (circuit->u.bc.adjdb[idx]) { + circuit->u.bc.adjdb[idx]->del = isis_delete_adj; + list_delete(&circuit->u.bc.adjdb[idx]); + } } return; diff --git a/isisd/isis_lfa.c b/isisd/isis_lfa.c index dc8f0b96c0..887f27eec5 100644 --- a/isisd/isis_lfa.c +++ b/isisd/isis_lfa.c @@ -238,10 +238,10 @@ void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level) * * @param nodes List of SPF nodes */ -void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level) +void isis_lfa_excluded_ifaces_delete(struct isis_circuit *circuit, int level) { - hash_clean(circuit->lfa_excluded_ifaces[level - 1], - lfa_excl_interface_hash_free); + hash_clean_and_free(&circuit->lfa_excluded_ifaces[level - 1], + lfa_excl_interface_hash_free); } /** diff --git a/isisd/isis_lfa.h b/isisd/isis_lfa.h index 0ba1c1cef5..58ff115b02 100644 --- a/isisd/isis_lfa.h +++ b/isisd/isis_lfa.h @@ -133,7 +133,7 @@ struct lfa_tiebreaker *isis_lfa_tiebreaker_add(struct isis_area *area, void isis_lfa_tiebreaker_delete(struct isis_area *area, int level, struct lfa_tiebreaker *tie_b); void isis_lfa_excluded_ifaces_init(struct isis_circuit *circuit, int level); -void isis_lfa_excluded_ifaces_clear(struct isis_circuit *circuit, int level); +void isis_lfa_excluded_ifaces_delete(struct isis_circuit *circuit, int level); void isis_lfa_excluded_iface_add(struct isis_circuit *circuit, int level, const char *ifname); void isis_lfa_excluded_iface_delete(struct isis_circuit *circuit, int level, diff --git a/isisd/isis_lsp.c b/isisd/isis_lsp.c index c98cee06a5..391d42fba1 100644 --- a/isisd/isis_lsp.c +++ b/isisd/isis_lsp.c @@ -482,13 +482,19 @@ static void lsp_update_data(struct isis_lsp *lsp, struct isis_lsp_hdr *hdr, lsp->tlvs = tlvs; - if (area->dynhostname && lsp->tlvs->hostname - && lsp->hdr.rem_lifetime) { - isis_dynhn_insert( - area->isis, lsp->hdr.lsp_id, lsp->tlvs->hostname, - (lsp->hdr.lsp_bits & LSPBIT_IST) == IS_LEVEL_1_AND_2 - ? IS_LEVEL_2 - : IS_LEVEL_1); + if (area->dynhostname && lsp->hdr.rem_lifetime) { + if (lsp->tlvs->hostname) { + isis_dynhn_insert(area->isis, lsp->hdr.lsp_id, + lsp->tlvs->hostname, + (lsp->hdr.lsp_bits & LSPBIT_IST) == + IS_LEVEL_1_AND_2 + ? IS_LEVEL_2 + : IS_LEVEL_1); + } else { + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id) && + !LSP_FRAGMENT(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, lsp->hdr.lsp_id); + } } return; @@ -1222,17 +1228,11 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) } /* Add SRv6 Locator TLV. */ - if (area->srv6db.config.enabled && - !list_isempty(area->srv6db.srv6_locator_chunks)) { + if (area->srv6db.config.enabled && area->srv6db.srv6_locator) { struct isis_srv6_locator locator = {}; - struct srv6_locator_chunk *chunk; - - /* TODO: support more than one locator */ - chunk = (struct srv6_locator_chunk *)listgetdata( - listhead(area->srv6db.srv6_locator_chunks)); locator.metric = 0; - locator.prefix = chunk->prefix; + locator.prefix = area->srv6db.srv6_locator->prefix; locator.flags = 0; locator.algorithm = 0; @@ -1252,7 +1252,8 @@ static void lsp_build(struct isis_lsp *lsp, struct isis_area *area) isis_tlvs_add_ipv6_reach(lsp->tlvs, isis_area_ipv6_topology(area), - &chunk->prefix, 0, false, NULL); + &area->srv6db.srv6_locator->prefix, 0, + false, NULL); } /* IPv4 address and TE router ID TLVs. @@ -2225,6 +2226,10 @@ void lsp_tick(struct event *thread) &area->lspdb[level], next); + if (!LSP_PSEUDO_ID(lsp->hdr.lsp_id)) + isis_dynhn_remove(area->isis, + lsp->hdr.lsp_id); + lspdb_del(&area->lspdb[level], lsp); lsp_destroy(lsp); lsp = NULL; @@ -2335,6 +2340,56 @@ static int lsp_handle_adj_state_change(struct isis_adjacency *adj) return 0; } +/* + * Iterate over all SRv6 locator TLVs + */ +int isis_lsp_iterate_srv6_locator(struct isis_lsp *lsp, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg) +{ + bool pseudo_lsp = LSP_PSEUDO_ID(lsp->hdr.lsp_id); + struct isis_lsp *frag; + struct listnode *node; + + if (lsp->hdr.seqno == 0 || lsp->hdr.rem_lifetime == 0) + return LSP_ITER_CONTINUE; + + /* Parse LSP */ + if (lsp->tlvs) { + if (!pseudo_lsp) { + struct isis_item_list *srv6_locator_reachs; + struct isis_srv6_locator_tlv *r; + + srv6_locator_reachs = + isis_lookup_mt_items(&lsp->tlvs->srv6_locator, + mtid); + + for (r = srv6_locator_reachs + ? (struct isis_srv6_locator_tlv *) + srv6_locator_reachs->head + : NULL; + r; r = r->next) { + if ((*cb)((struct prefix *)&r->prefix, + r->metric, false /* ignore */, + r->subtlvs, arg) == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + } + } + + /* Parse LSP fragments if it is not a fragment itself */ + if (!LSP_FRAGMENT(lsp->hdr.lsp_id)) + for (ALL_LIST_ELEMENTS_RO(lsp->lspu.frags, node, frag)) { + if (!frag->tlvs) + continue; + + if (isis_lsp_iterate_srv6_locator(frag, mtid, cb, + arg) == LSP_ITER_STOP) + return LSP_ITER_STOP; + } + + return LSP_ITER_CONTINUE; +} + /* * Iterate over all IP reachability TLVs in a LSP (all fragments) of the given * address-family and MT-ID. diff --git a/isisd/isis_lsp.h b/isisd/isis_lsp.h index 3839a9504c..15db88b02f 100644 --- a/isisd/isis_lsp.h +++ b/isisd/isis_lsp.h @@ -143,6 +143,8 @@ int isis_lsp_iterate_ip_reach(struct isis_lsp *lsp, int family, uint16_t mtid, lsp_ip_reach_iter_cb cb, void *arg); int isis_lsp_iterate_is_reach(struct isis_lsp *lsp, uint16_t mtid, lsp_is_reach_iter_cb cb, void *arg); +int isis_lsp_iterate_srv6_locator(struct isis_lsp *lsp, uint16_t mtid, + lsp_ip_reach_iter_cb cb, void *arg); #define lsp_flood(lsp, circuit) \ _lsp_flood((lsp), (circuit), __func__, __FILE__, __LINE__) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 8dd3a97aa1..b7ed8f7605 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -103,6 +103,12 @@ static __attribute__((__noreturn__)) void terminate(int i) isis_sr_term(); isis_srv6_term(); isis_zebra_stop(); + + isis_master_terminate(); + route_map_finish(); + vrf_terminate(); + + frr_fini(); exit(i); } diff --git a/isisd/isis_misc.c b/isisd/isis_misc.c index e4ef6c8dfa..833d514341 100644 --- a/isisd/isis_misc.c +++ b/isisd/isis_misc.c @@ -370,18 +370,20 @@ const char *print_sys_hostname(const uint8_t *sysid) struct isis_dynhn *dyn; struct isis *isis = NULL; struct listnode *node; + struct isis_area *area = NULL; if (!sysid) return "nullsysid"; /* For our system ID return our host name */ - isis = isis_lookup_by_sysid(sysid); - if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) + area = isis_area_lookup_by_sysid(sysid); + if (area && area->dynhostname && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) return cmd_hostname_get(); for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { + area = isis_area_lookup_by_sysid(isis->sysid); dyn = dynhn_find_by_id(isis, sysid); - if (dyn) + if (area && area->dynhostname && dyn) return dyn->hostname; } diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 763b8b73d2..2b47d5cbeb 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -252,11 +252,12 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) return NB_ERR_INCONSISTENCY; listnode_delete(area->area_addrs, addrp); - XFREE(MTYPE_ISIS_AREA_ADDR, addrp); /* * Last area address - reset the SystemID for this router */ - if (listcount(area->area_addrs) == 0) { + if (!memcmp(addrp->area_addr + addrp->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN) && + listcount(area->area_addrs) == 0) { for (ALL_LIST_ELEMENTS_RO(area->circuit_list, cnode, circuit)) for (lvl = IS_LEVEL_1; lvl <= IS_LEVEL_2; ++lvl) { if (circuit->u.bc.is_dr[lvl - 1]) @@ -268,6 +269,8 @@ int isis_instance_area_address_destroy(struct nb_cb_destroy_args *args) zlog_debug("Router has no SystemID"); } + XFREE(MTYPE_ISIS_AREA_ADDR, addrp); + return NB_OK; } @@ -2835,7 +2838,9 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) { struct isis_area *area; struct flex_algo *fa; - bool advertise; + bool advertise, update_te; + struct isis_circuit *circuit; + struct listnode *node; uint32_t algorithm; uint32_t priority = FLEX_ALGO_PRIO_DEFAULT; struct isis_flex_algo_alloc_arg arg; @@ -2848,6 +2853,7 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) area = nb_running_get_entry(args->dnode, NULL, true); arg.algorithm = algorithm; arg.area = area; + update_te = list_isempty(area->flex_algos->flex_algos); fa = flex_algo_alloc(area->flex_algos, algorithm, &arg); fa->priority = priority; fa->advertise_definition = advertise; @@ -2859,6 +2865,12 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) admin_group_allow_explicit_zero( &fa->admin_group_include_all); } + if (update_te) { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, + circuit)) + isis_link_params_update_asla(circuit, + circuit->interface); + } lsp_regenerate_schedule(area, area->is_type, 0); break; case NB_EV_VALIDATE: @@ -2872,6 +2884,9 @@ int isis_instance_flex_algo_create(struct nb_cb_create_args *args) int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args) { + struct isis_circuit *circuit; + struct listnode *node, *nnode; + struct flex_algo *fa; struct isis_area *area; uint32_t algorithm; @@ -2880,7 +2895,17 @@ int isis_instance_flex_algo_destroy(struct nb_cb_destroy_args *args) switch (args->event) { case NB_EV_APPLY: - flex_algo_delete(area->flex_algos, algorithm); + for (ALL_LIST_ELEMENTS(area->flex_algos->flex_algos, node, + nnode, fa)) { + if (fa->algorithm == algorithm) + flex_algo_free(area->flex_algos, fa); + } + if (list_isempty(area->flex_algos->flex_algos)) { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, + circuit)) + isis_link_params_update_asla(circuit, + circuit->interface); + } lsp_regenerate_schedule(area, area->is_type, 0); break; case NB_EV_VALIDATE: @@ -3518,10 +3543,10 @@ int isis_instance_segment_routing_srv6_locator_modify( sr_debug("Configured SRv6 locator %s for IS-IS area %s", loc_name, area->area_tag); - sr_debug("Trying to get a chunk from locator %s for IS-IS area %s", - loc_name, area->area_tag); + sr_debug("Trying to get locator %s for IS-IS area %s", loc_name, + area->area_tag); - if (isis_zebra_srv6_manager_get_locator_chunk(loc_name) < 0) + if (isis_zebra_srv6_manager_get_locator(loc_name) < 0) return NB_ERR; return NB_OK; diff --git a/isisd/isis_snmp.c b/isisd/isis_snmp.c index f9e3780e29..83a06b6998 100644 --- a/isisd/isis_snmp.c +++ b/isisd/isis_snmp.c @@ -2826,6 +2826,13 @@ static int isis_snmp_init(struct event_loop *tm) return 0; } +static int isis_snmp_terminate(void) +{ + smux_terminate(); + + return 0; +} + /* * ISIS notification functions: we have one function per notification */ @@ -3448,6 +3455,7 @@ static int isis_snmp_module_init(void) hook_register(isis_circuit_del_hook, isis_circuit_snmp_id_free); hook_register(frr_late_init, isis_snmp_init); + hook_register(frr_fini, isis_snmp_terminate); return 0; } diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 1197f8c372..86302076f8 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -2230,21 +2230,35 @@ int _isis_spf_schedule(struct isis_area *area, int level, } static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, - uint8_t *root_sysid) + uint8_t *root_sysid, struct json_object **json) { struct listnode *node; struct isis_vertex *vertex; char buff[VID2STR_BUFFER]; + char vertex_name[VID2STR_BUFFER]; + char vertex_typestr[VID2STR_BUFFER]; + char vertex_interface[VID2STR_BUFFER]; + char vertex_parent[VID2STR_BUFFER + 11]; + char vertex_nexthop[VID2STR_BUFFER]; + char vertex_metricstr[20]; + struct ttable *tt; + char *table; - vty_out(vty, - "Vertex Type Metric Next-Hop Interface Parent\n"); + /* Prepare table. */ + tt = ttable_new(&ttable_styles[TTSTYLE_BLANK]); + ttable_add_row(tt, "Vertex|Type|Metric|Next-Hop|Interface|Parent"); + tt->style.cell.rpad = 2; + tt->style.corner = '+'; + ttable_restyle(tt); + ttable_rowseps(tt, 0, BOTTOM, true, '-'); for (ALL_QUEUE_ELEMENTS_RO(queue, node, vertex)) { if (VTYPE_IS(vertex->type) && memcmp(vertex->N.id, root_sysid, ISIS_SYS_ID_LEN) == 0) { - vty_out(vty, "%-20s %-12s %-6s", - print_sys_hostname(root_sysid), "", ""); - vty_out(vty, "%-30s\n", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + print_sys_hostname(root_sysid), "", "", + "", "", ""); continue; } @@ -2254,9 +2268,12 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, struct isis_vertex_adj *vadj; struct isis_vertex *pvertex; - vty_out(vty, "%-20s %-12s %-6u ", - vid2string(vertex, buff, sizeof(buff)), - vtype2string(vertex->type), vertex->d_N); + snprintf(vertex_name, sizeof(vertex_name), "%s", + vid2string(vertex, buff, sizeof(buff))); + snprintf(vertex_typestr, sizeof(vertex_typestr), "%s", + vtype2string(vertex->type)); + snprintf(vertex_metricstr, sizeof(vertex_metricstr), "%u", + vertex->d_N); for (unsigned int i = 0; i < MAX(vertex->Adj_N ? listcount(vertex->Adj_N) : 0, vertex->parents ? listcount(vertex->parents) : 0); @@ -2276,36 +2293,60 @@ static void isis_print_paths(struct vty *vty, struct isis_vertex_queue *queue, } if (rows) { - vty_out(vty, "\n"); - vty_out(vty, "%-20s %-12s %-6s ", "", "", ""); + /* display here */ + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", + vertex_name, vertex_typestr, + vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); + + /* store the first 3 elements */ + vertex_name[0] = '\0'; + vertex_typestr[0] = '\0'; + vertex_metricstr[0] = '\0'; } if (vadj) { struct isis_spf_adj *sadj = vadj->sadj; - vty_out(vty, "%-20s %-9s ", - print_sys_hostname(sadj->id), - sadj->adj ? sadj->adj->circuit - ->interface->name - : "-"); + snprintf(vertex_nexthop, sizeof(vertex_nexthop), + "%s", print_sys_hostname(sadj->id)); + snprintf(vertex_interface, + sizeof(vertex_interface), "%s", + sadj->adj ? sadj->adj->circuit + ->interface->name + : "-"); } if (pvertex) { - if (!vadj) - vty_out(vty, "%-20s %-9s ", "", ""); - - vty_out(vty, "%s(%d)", - vid2string(pvertex, buff, sizeof(buff)), - pvertex->type); + if (!vadj) { + vertex_nexthop[0] = '\0'; + vertex_interface[0] = '\0'; + } + snprintf(vertex_parent, sizeof(vertex_parent), + "%s(%d)", + vid2string(pvertex, buff, sizeof(buff)), + pvertex->type); } ++rows; } - vty_out(vty, "\n"); + ttable_add_row(tt, "%s|%s|%s|%s|%s|%s", vertex_name, + vertex_typestr, vertex_metricstr, vertex_nexthop, + vertex_interface, vertex_parent); } + if (json == NULL) { + table = ttable_dump(tt, "\n"); + vty_out(vty, "%s\n", table); + XFREE(MTYPE_TMP, table); + } else + *json = ttable_json_with_json_text( + tt, "ssdsss", + "vertex|type|metric|nextHop|interface|parent"); + ttable_del(tt); } -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json) { const char *tree_id_text = NULL; @@ -2327,14 +2368,18 @@ void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree) return; } - vty_out(vty, "IS-IS paths to level-%d routers %s\n", spftree->level, - tree_id_text); - isis_print_paths(vty, &spftree->paths, spftree->sysid); - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "IS-IS paths to level-%d routers %s\n", + spftree->level, tree_id_text); + + isis_print_paths(vty, &spftree->paths, spftree->sysid, json); + if (!json) + vty_out(vty, "\n"); } static void show_isis_topology_common(struct vty *vty, int levels, - struct isis *isis, uint8_t algo) + struct isis *isis, uint8_t algo, + json_object **json) { #ifndef FABRICD struct isis_flex_algo_data *fa_data; @@ -2343,10 +2388,15 @@ static void show_isis_topology_common(struct vty *vty, int levels, struct isis_spftree *spftree; struct listnode *node; struct isis_area *area; + json_object *json_level = NULL, *jstr = NULL, *json_val; + char key[18]; if (!isis->area_list || isis->area_list->count == 0) return; + if (json) + *json = json_object_new_object(); + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { #ifndef FABRICD /* @@ -2364,21 +2414,37 @@ static void show_isis_topology_common(struct vty *vty, int levels, fa_data = NULL; #endif /* ifndef FABRICD */ - vty_out(vty, - "Area %s:", area->area_tag ? area->area_tag : "null"); + if (json) { + jstr = json_object_new_string( + area->area_tag ? area->area_tag : "null"); + json_object_object_add(*json, "area", jstr); + json_object_int_add(*json, "algorithm", algo); + } else { + vty_out(vty, "Area %s:", + area->area_tag ? area->area_tag : "null"); #ifndef FABRICD - if (algo != SR_ALGORITHM_SPF) - vty_out(vty, " Algorithm %hhu\n", algo); - else + if (algo != SR_ALGORITHM_SPF) + vty_out(vty, " Algorithm %hhu\n", algo); + else #endif /* ifndef FABRICD */ - vty_out(vty, "\n"); + vty_out(vty, "\n"); + } for (int level = ISIS_LEVEL1; level <= ISIS_LEVELS; level++) { if ((level & levels) == 0) continue; + if (json) { + json_level = json_object_new_object(); + jstr = json_object_new_string( + area->area_tag ? area->area_tag + : "null"); + json_object_object_add(json_level, "area", jstr); + } + if (area->ip_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV4] @@ -2388,9 +2454,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + } } if (area->ipv6_circuits > 0) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = fa_data->spftree[SPFTREE_IPV6] @@ -2399,9 +2472,16 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + } } if (isis_area_ipv6_dstsrc_enabled(area)) { + json_val = NULL; #ifndef FABRICD if (fa_data) spftree = @@ -2411,18 +2491,36 @@ static void show_isis_topology_common(struct vty *vty, int levels, #endif /* ifndef FABRICD */ spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + } + } + if (json) { + snprintf(key, sizeof(key), "level-%d", level); + json_object_object_add(*json, key, json_level); } } if (fabricd_spftree(area)) { + json_val = NULL; + vty_out(vty, "IS-IS paths to level-2 routers with hop-by-hop metric\n"); - isis_print_paths(vty, &fabricd_spftree(area)->paths, isis->sysid); - vty_out(vty, "\n"); + isis_print_paths(vty, &fabricd_spftree(area)->paths, + isis->sysid, json ? &json_val : NULL); + if (json && json_val) + json_object_object_add(json_level, + "fabricd-paths", + json_val); + else + vty_out(vty, "\n"); } - - vty_out(vty, "\n"); + if (!json) + vty_out(vty, "\n"); } } @@ -2433,6 +2531,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, " []" " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ + " [json$uj]" , SHOW_STR PROTO_HELP VRF_CMD_HELP_STR "All VRFs\n" @@ -2443,6 +2542,7 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, "Show Flex-algo routes\n" "Algorithm number\n" #endif /* ifndef FABRICD */ + JSON_STR ) { int levels = ISIS_LEVELS; @@ -2453,6 +2553,8 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, bool all_algorithm = false; int idx_vrf = 0; uint16_t algorithm = SR_ALGORITHM_SPF; + bool uj = use_json(argc, argv); + json_object *json = NULL, *json_vrf = NULL; #ifndef FABRICD int idx = 0; @@ -2476,21 +2578,33 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, } ISIS_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + if (uj) + json = json_object_new_array(); + if (all_vrf) { for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) { if (all_algorithm) { for (algorithm = SR_ALGORITHM_FLEX_MIN; algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) - show_isis_topology_common( - vty, levels, isis, - (uint8_t)algorithm); + show_isis_topology_common(vty, levels, + isis, + (uint8_t)algorithm, + uj ? &json_vrf + : NULL); } else { show_isis_topology_common(vty, levels, isis, - (uint8_t)algorithm); + (uint8_t)algorithm, + uj ? &json_vrf : NULL); + } + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int( + isis->vrf_id)); + json_object_array_add(json, json_vrf); } } - return CMD_SUCCESS; + goto out; } isis = isis_lookup_by_vrfname(vrf_name); if (isis == NULL) @@ -2499,10 +2613,24 @@ DEFUN(show_isis_topology, show_isis_topology_cmd, for (algorithm = SR_ALGORITHM_FLEX_MIN; algorithm <= SR_ALGORITHM_FLEX_MAX; algorithm++) { show_isis_topology_common(vty, levels, isis, - (uint8_t)algorithm); + (uint8_t)algorithm, + uj ? &json_vrf : NULL); } } else - show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm); + show_isis_topology_common(vty, levels, isis, (uint8_t)algorithm, + uj ? &json_vrf : NULL); + if (uj) { + json_object_object_add(json_vrf, "vrf_id", + json_object_new_int(isis->vrf_id)); + json_object_array_add(json, json_vrf); + } +out: + if (uj) { + vty_out(vty, "%s\n", + json_object_to_json_string_ext(json, + JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } return CMD_SUCCESS; } @@ -2890,7 +3018,11 @@ void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, vty_out(vty, "%s\n", table); XFREE(MTYPE_TMP, table); } else if (json) { - *json = ttable_json(tt, prefix_sid ? "sdssdsdd" : "sdsss"); + *json = ttable_json_with_json_text( + tt, prefix_sid ? "sdssdsdd" : "sdsss", + prefix_sid + ? "prefix|metric|interface|nextHop|segmentIdentifier|labelOperation|Algorithm" + : "prefix|metric|interface|nextHop|label(s)"); } ttable_del(tt); } @@ -2974,8 +3106,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV4] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv4-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -2996,8 +3134,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_IPV6] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, @@ -3019,8 +3163,14 @@ static void show_isis_route_common(struct vty *vty, int levels, spftree = area->spftree[SPFTREE_DSTSRC] [level - 1]; - if (!json) - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, + json ? &json_val : NULL); + if (json && json_val) { + json_object_object_add(json_level, + "ipv6-dstsrc-paths", + json_val); + json_val = NULL; + } isis_print_routes(vty, spftree, json ? &json_val : NULL, prefix_sid, backup); @@ -3077,7 +3227,7 @@ DEFUN(show_isis_route, show_isis_route_cmd, #ifndef FABRICD " []" #endif /* ifndef FABRICD */ - " []" + " [prefix-sid] [backup]" #ifndef FABRICD " [algorithm [(128-255)]]" #endif /* ifndef FABRICD */ diff --git a/isisd/isis_spf.h b/isisd/isis_spf.h index 7e9754d9bf..ee2d29abe3 100644 --- a/isisd/isis_spf.h +++ b/isisd/isis_spf.h @@ -61,7 +61,8 @@ struct isis_lsp *isis_root_system_lsp(struct lspdb_head *lspdb, __FILE__, __LINE__) int _isis_spf_schedule(struct isis_area *area, int level, const char *func, const char *file, int line); -void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree); +void isis_print_spftree(struct vty *vty, struct isis_spftree *spftree, + struct json_object **json); void isis_print_routes(struct vty *vty, struct isis_spftree *spftree, json_object **json, bool prefix_sid, bool backup); void isis_spf_init(void); diff --git a/isisd/isis_srv6.c b/isisd/isis_srv6.c index 44fd599cbb..b5974b1a62 100644 --- a/isisd/isis_srv6.c +++ b/isisd/isis_srv6.c @@ -102,6 +102,7 @@ bool isis_srv6_locator_unset(struct isis_area *area) struct srv6_locator_chunk *chunk; struct isis_srv6_sid *sid; struct srv6_adjacency *sra; + struct srv6_sid_ctx ctx = {}; if (strncmp(area->srv6db.config.srv6_locator_name, "", sizeof(area->srv6db.config.srv6_locator_name)) == 0) { @@ -120,13 +121,31 @@ bool isis_srv6_locator_unset(struct isis_area *area) * Zebra */ isis_zebra_srv6_sid_uninstall(area, sid); + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + isis_zebra_release_srv6_sid(&ctx); + listnode_delete(area->srv6db.srv6_sids, sid); isis_srv6_sid_free(sid); } /* Uninstall all local Adjacency-SIDs. */ - for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_endx_sids, node, nnode, sra)) { + /* + * Inform the SID Manager that IS-IS will no longer use the SID, so + * that the SID Manager can remove the SID context ownership from IS-IS + * and release/free the SID context if it is not yes by other protocols. + */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = sra->nexthop; + isis_zebra_release_srv6_sid(&ctx); + srv6_endx_sid_del(sra); + } /* Inform Zebra that we are releasing the SRv6 locator */ ret = isis_zebra_srv6_manager_release_locator_chunk( @@ -146,6 +165,10 @@ bool isis_srv6_locator_unset(struct isis_area *area) srv6_locator_chunk_free(&chunk); } + /* Clear locator */ + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Clear locator name */ memset(area->srv6db.config.srv6_locator_name, 0, sizeof(area->srv6db.config.srv6_locator_name)); @@ -197,150 +220,36 @@ void isis_srv6_interface_set(struct isis_area *area, const char *ifname) } } -/** - * Encode SID function in the SRv6 SID. - * - * @param sid - * @param func - * @param offset - * @param len - */ -static void encode_sid_func(struct in6_addr *sid, uint32_t func, uint8_t offset, - uint8_t len) -{ - for (uint8_t idx = 0; idx < len; idx++) { - uint8_t tidx = offset + idx; - sid->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); - if (func >> (len - 1 - idx) & 0x1) - sid->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); - } -} - -static bool sid_exist(struct isis_area *area, const struct in6_addr *sid) -{ - struct listnode *node; - struct isis_srv6_sid *s; - struct srv6_adjacency *sra; - - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_sids, node, s)) - if (sid_same(&s->sid, sid)) - return true; - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_endx_sids, node, sra)) - if (sid_same(&sra->sid, sid)) - return true; - return false; -} - -/** - * Request a SID from the SRv6 locator. - * - * @param area IS-IS area - * @param chunk SRv6 locator chunk - * @param sid_func The FUNCTION part of the SID to be allocated (a negative - * number will allocate the first available SID) - * - * @return First available SID on success or in6addr_any if the SRv6 - * locator chunk is full - */ -static struct in6_addr -srv6_locator_request_sid(struct isis_area *area, - struct srv6_locator_chunk *chunk, int sid_func) -{ - struct in6_addr sid; - uint8_t offset = 0; - uint8_t func_len = 0; - uint32_t func_max; - bool allocated = false; - - if (!area || !chunk) - return in6addr_any; - - sr_debug("ISIS-SRv6 (%s): requested new SID from locator %s", - area->area_tag, chunk->locator_name); - - /* Let's build the SID, step by step. A SID has the following structure - (defined in RFC 8986): LOCATOR:FUNCTION:ARGUMENT.*/ - - /* First, we encode the LOCATOR in the L most significant bits. */ - sid = chunk->prefix.prefix; - - /* The next part of the SID is the FUNCTION. Let's compute the length - * and the offset of the FUNCTION in the SID */ - func_len = chunk->function_bits_length; - offset = chunk->block_bits_length + chunk->node_bits_length; - - /* Then, encode the FUNCTION */ - if (sid_func >= 0) { - /* SID FUNCTION has been specified. We need to allocate a SID - * with the requested FUNCTION. */ - encode_sid_func(&sid, sid_func, offset, func_len); - if (sid_exist(area, &sid)) { - zlog_warn( - "ISIS-SRv6 (%s): the requested SID %pI6 is already used", - area->area_tag, &sid); - return sid; - } - allocated = true; - } else { - /* SID FUNCTION not specified. We need to choose a FUNCTION that - * is not already used. So let's iterate through all possible - * functions and get the first available one. */ - func_max = (1 << func_len) - 1; - for (uint32_t func = 1; func < func_max; func++) { - encode_sid_func(&sid, func, offset, func_len); - if (sid_exist(area, &sid)) - continue; - allocated = true; - break; - } - } - - if (!allocated) { - /* We ran out of available SIDs */ - zlog_warn("ISIS-SRv6 (%s): no SIDs available in locator %s", - area->area_tag, chunk->locator_name); - return in6addr_any; - } - - sr_debug("ISIS-SRv6 (%s): allocating new SID %pI6", area->area_tag, - &sid); - - return sid; -} - /** * Allocate an SRv6 SID from an SRv6 locator. * * @param area IS-IS area - * @param chunk SRv6 locator chunk + * @param locator SRv6 locator * @param behavior SRv6 Endpoint Behavior bound to the SID + * @param sid_value SRv6 SID value * * @result the allocated SID on success, NULL otherwise */ struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, - int sid_func) + struct in6_addr *sid_value) { struct isis_srv6_sid *sid = NULL; - if (!area || !chunk) + if (!area || !locator || !sid_value) return NULL; sid = XCALLOC(MTYPE_ISIS_SRV6_SID, sizeof(struct isis_srv6_sid)); - sid->sid = srv6_locator_request_sid(area, chunk, sid_func); - if (IPV6_ADDR_SAME(&sid->sid, &in6addr_any)) { - isis_srv6_sid_free(sid); - return NULL; - } + sid->sid = *sid_value; sid->behavior = behavior; - sid->structure.loc_block_len = chunk->block_bits_length; - sid->structure.loc_node_len = chunk->node_bits_length; - sid->structure.func_len = chunk->function_bits_length; - sid->structure.arg_len = chunk->argument_bits_length; - sid->locator = chunk; + sid->structure.loc_block_len = locator->block_bits_length; + sid->structure.loc_node_len = locator->node_bits_length; + sid->structure.func_len = locator->function_bits_length; + sid->structure.arg_len = locator->argument_bits_length; + sid->locator = locator; sid->area = area; return sid; @@ -376,9 +285,10 @@ void isis_area_delete_backup_srv6_endx_sids(struct isis_area *area, int level) * @param adj IS-IS Adjacency * @param backup True to initialize backup Adjacency SID * @param nexthops List of backup nexthops (for backup End.X SIDs only) + * @param sid_value SID value associated to be associated with the adjacency */ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, - struct list *nexthops) + struct list *nexthops, struct in6_addr *sid_value) { struct isis_circuit *circuit = adj->circuit; struct isis_area *area = circuit->area; @@ -387,11 +297,10 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, struct isis_srv6_lan_endx_sid_subtlv *ladj_sid; struct in6_addr nexthop; uint8_t flags = 0; - struct srv6_locator_chunk *chunk; + struct srv6_locator *locator; uint32_t behavior; - if (!area || !area->srv6db.srv6_locator_chunks || - list_isempty(area->srv6db.srv6_locator_chunks)) + if (!area || !area->srv6db.srv6_locator) return; sr_debug("ISIS-SRv6 (%s): Add %s End.X SID", area->area_tag, @@ -401,10 +310,7 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (!circuit->ipv6_router || !adj->ll_ipv6_count) return; - chunk = (struct srv6_locator_chunk *)listgetdata( - listhead(area->srv6db.srv6_locator_chunks)); - if (!chunk) - return; + locator = area->srv6db.srv6_locator; nexthop = adj->ll_ipv6_addrs[0]; @@ -415,25 +321,21 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, if (circuit->ext == NULL) circuit->ext = isis_alloc_ext_subtlvs(); - behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) + behavior = (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) ? SRV6_ENDPOINT_BEHAVIOR_END_X_NEXT_CSID : SRV6_ENDPOINT_BEHAVIOR_END_X; sra = XCALLOC(MTYPE_ISIS_SRV6_INFO, sizeof(*sra)); sra->type = backup ? ISIS_SRV6_ADJ_BACKUP : ISIS_SRV6_ADJ_NORMAL; sra->behavior = behavior; - sra->locator = chunk; - sra->structure.loc_block_len = chunk->block_bits_length; - sra->structure.loc_node_len = chunk->node_bits_length; - sra->structure.func_len = chunk->function_bits_length; - sra->structure.arg_len = chunk->argument_bits_length; + sra->locator = locator; + sra->structure.loc_block_len = locator->block_bits_length; + sra->structure.loc_node_len = locator->node_bits_length; + sra->structure.func_len = locator->function_bits_length; + sra->structure.arg_len = locator->argument_bits_length; sra->nexthop = nexthop; - sra->sid = srv6_locator_request_sid(area, chunk, -1); - if (IPV6_ADDR_SAME(&sra->sid, &in6addr_any)) { - XFREE(MTYPE_ISIS_SRV6_INFO, sra); - return; - } + sra->sid = *sid_value; switch (circuit->circ_type) { /* SRv6 LAN End.X SID for Broadcast interface section #8.2 */ @@ -505,9 +407,9 @@ void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, * * @param adj IS-IS Adjacency */ -void srv6_endx_sid_add(struct isis_adjacency *adj) +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value) { - srv6_endx_sid_add_single(adj, false, NULL); + srv6_endx_sid_add_single(adj, false, NULL, sid_value); } /** @@ -610,7 +512,7 @@ static int srv6_adj_ip_enabled(struct isis_adjacency *adj, int family, family != AF_INET6) return 0; - srv6_endx_sid_add(adj); + isis_zebra_request_srv6_sid_endx(adj); return 0; } @@ -832,6 +734,9 @@ void isis_srv6_area_term(struct isis_area *area) srv6_locator_chunk_free(&chunk); list_delete(&srv6db->srv6_locator_chunks); + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Free SRv6 SIDs list */ list_delete(&srv6db->srv6_sids); list_delete(&srv6db->srv6_endx_sids); diff --git a/isisd/isis_srv6.h b/isisd/isis_srv6.h index 7f16712ae3..bde14965f6 100644 --- a/isisd/isis_srv6.h +++ b/isisd/isis_srv6.h @@ -44,7 +44,7 @@ struct isis_srv6_sid { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Backpointer to IS-IS area */ struct isis_area *area; @@ -89,7 +89,7 @@ struct srv6_adjacency { struct isis_srv6_sid_structure structure; /* Parent SRv6 locator */ - struct srv6_locator_chunk *locator; + struct srv6_locator *locator; /* Adjacency-SID nexthop information */ struct in6_addr nexthop; @@ -109,6 +109,8 @@ struct srv6_adjacency { /* Per-area IS-IS SRv6 Data Base (SRv6 DB) */ struct isis_srv6_db { + /* List of SRv6 Locator */ + struct srv6_locator *srv6_locator; /* List of SRv6 Locator chunks */ struct list *srv6_locator_chunks; @@ -149,9 +151,9 @@ bool isis_srv6_locator_unset(struct isis_area *area); void isis_srv6_interface_set(struct isis_area *area, const char *ifname); struct isis_srv6_sid * -isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator_chunk *chunk, +isis_srv6_sid_alloc(struct isis_area *area, struct srv6_locator *locator, enum srv6_endpoint_behavior_codepoint behavior, - int sid_func); + struct in6_addr *sid_value); extern void isis_srv6_sid_free(struct isis_srv6_sid *sid); extern void isis_srv6_area_init(struct isis_area *area); @@ -169,8 +171,8 @@ void isis_srv6_locator2tlv(const struct isis_srv6_locator *loc, struct isis_srv6_locator_tlv *loc_tlv); void srv6_endx_sid_add_single(struct isis_adjacency *adj, bool backup, - struct list *nexthops); -void srv6_endx_sid_add(struct isis_adjacency *adj); + struct list *nexthops, struct in6_addr *sid_value); +void srv6_endx_sid_add(struct isis_adjacency *adj, struct in6_addr *sid_value); void srv6_endx_sid_del(struct srv6_adjacency *sra); struct srv6_adjacency *isis_srv6_endx_sid_find(struct isis_adjacency *adj, enum srv6_adj_type type); diff --git a/isisd/isis_te.c b/isisd/isis_te.c index 3683f74558..b6321dbac3 100644 --- a/isisd/isis_te.c +++ b/isisd/isis_te.c @@ -164,8 +164,8 @@ void isis_mpls_te_term(struct isis_area *area) XFREE(MTYPE_ISIS_MPLS_TE, area->mta); } -static void isis_link_params_update_asla(struct isis_circuit *circuit, - struct interface *ifp) +void isis_link_params_update_asla(struct isis_circuit *circuit, + struct interface *ifp) { struct isis_asla_subtlvs *asla; struct listnode *node, *nnode; @@ -1258,8 +1258,11 @@ static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric, if (!args || !prefix) return LSP_ITER_CONTINUE; - te_debug(" |- Process Extended %s Reachability %pFX", - prefix->family == AF_INET ? "IP" : "IPv6", prefix); + if (args->srv6_locator) + te_debug(" |- Process SRv6 Locator %pFX", prefix); + else + te_debug(" |- Process Extended %s Reachability %pFX", + prefix->family == AF_INET ? "IP" : "IPv6", prefix); vertex = args->vertex; @@ -1386,6 +1389,38 @@ static int lsp_to_subnet_cb(const struct prefix *prefix, uint32_t metric, } } + /* Update SRv6 SID and locator if any */ + if (subtlvs && subtlvs->srv6_end_sids.count != 0) { + struct isis_srv6_end_sid_subtlv *psid; + struct ls_srv6_sid sr = {}; + + psid = (struct isis_srv6_end_sid_subtlv *) + subtlvs->srv6_end_sids.head; + sr.behavior = psid->behavior; + sr.flags = psid->flags; + memcpy(&sr.sid, &psid->sid, sizeof(struct in6_addr)); + + if (!CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6) || + memcmp(&ls_pref->srv6, &sr, sizeof(struct ls_srv6_sid))) { + memcpy(&ls_pref->srv6, &sr, sizeof(struct ls_srv6_sid)); + SET_FLAG(ls_pref->flags, LS_PREF_SRV6); + if (subnet->status != NEW) + subnet->status = UPDATE; + } else { + if (subnet->status == ORPHAN) + subnet->status = SYNC; + } + } else { + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + UNSET_FLAG(ls_pref->flags, LS_PREF_SRV6); + if (subnet->status != NEW) + subnet->status = UPDATE; + } else { + if (subnet->status == ORPHAN) + subnet->status = SYNC; + } + } + /* Update status and Export Link State Edge if needed */ if (subnet->status != SYNC) { if (args->export) @@ -1454,12 +1489,18 @@ static void isis_te_parse_lsp(struct mpls_te_area *mta, struct isis_lsp *lsp) &args); /* Process all Extended IP (v4 & v6) in LSP (all fragments) */ + args.srv6_locator = false; isis_lsp_iterate_ip_reach(lsp, AF_INET, ISIS_MT_IPV4_UNICAST, lsp_to_subnet_cb, &args); isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV6_UNICAST, lsp_to_subnet_cb, &args); isis_lsp_iterate_ip_reach(lsp, AF_INET6, ISIS_MT_IPV4_UNICAST, lsp_to_subnet_cb, &args); + args.srv6_locator = true; + isis_lsp_iterate_srv6_locator(lsp, ISIS_MT_STANDARD, lsp_to_subnet_cb, + &args); + isis_lsp_iterate_srv6_locator(lsp, ISIS_MT_IPV6_UNICAST, + lsp_to_subnet_cb, &args); /* Clean remaining Orphan Edges or Subnets */ if (IS_EXPORT_TE(mta)) diff --git a/isisd/isis_te.h b/isisd/isis_te.h index bf1dc2b9bb..697f03b612 100644 --- a/isisd/isis_te.h +++ b/isisd/isis_te.h @@ -103,6 +103,7 @@ struct isis_te_args { struct ls_ted *ted; struct ls_vertex *vertex; bool export; + bool srv6_locator; }; enum lsp_event { LSP_UNKNOWN, LSP_ADD, LSP_UPD, LSP_DEL, LSP_INC, LSP_TICK }; @@ -112,6 +113,8 @@ void isis_mpls_te_init(void); void isis_mpls_te_create(struct isis_area *area); void isis_mpls_te_disable(struct isis_area *area); void isis_mpls_te_term(struct isis_area *area); +void isis_link_params_update_asla(struct isis_circuit *circuit, + struct interface *ifp); void isis_link_params_update(struct isis_circuit *, struct interface *); int isis_mpls_te_update(struct interface *); void isis_te_lsp_event(struct isis_lsp *lsp, enum lsp_event event); diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 3bb8a48246..c7f45b2469 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -1010,7 +1010,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_adj_sid *adj; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *adj_sid_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1022,42 +1022,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", adj->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", + adj_sid_json = json_object_new_object(); + json_object_int_add(adj_sid_json, "sid", adj->sid); - json_object_int_add(flags_json, "weight", + json_object_int_add(adj_sid_json, "weight", adj->weight); - json_object_string_add( - flags_json, "flag-f", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + json_object_string_add(adj_sid_json, "flag-f", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-b", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-v", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-l", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-s", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add(adj_sid_json, "flag-p", + adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + adj_sid_json); } /* end old deprecated key format */ @@ -1067,35 +1062,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", adj->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", adj->sid); - json_object_int_add(flags_json, "weight", + adj_sid_json = json_object_new_object(); + json_object_int_add(adj_sid_json, "sid", + adj->sid); + json_object_int_add(adj_sid_json, "weight", adj->weight); - json_object_boolean_add(flags_json, "flagF", + json_object_boolean_add(adj_sid_json, "flagF", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? true : false); - json_object_boolean_add(flags_json, "flagB", + json_object_boolean_add(adj_sid_json, "flagB", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? true : false); - json_object_boolean_add(flags_json, "flagV", + json_object_boolean_add(adj_sid_json, "flagV", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? true : false); - json_object_boolean_add(flags_json, "flagL", + json_object_boolean_add(adj_sid_json, "flagL", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? true : false); - json_object_boolean_add(flags_json, "flagS", + json_object_boolean_add(adj_sid_json, "flagS", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? true : false); - json_object_boolean_add(flags_json, "flagP", + json_object_boolean_add(adj_sid_json, "flagP", adj->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG ? true : false); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + adj_sid_json); } } else for (adj = (struct isis_adj_sid *)exts->adj_sid.head; @@ -1128,7 +1125,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_LAN_ADJ_SID)) { struct isis_lan_adj_sid *lan; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *lan_adj_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1147,42 +1144,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, continue; snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", lan->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", + lan_adj_json = json_object_new_object(); + json_object_int_add(lan_adj_json, "sid", lan->sid); - json_object_int_add(flags_json, "weight", + json_object_int_add(lan_adj_json, "weight", lan->weight); - json_object_string_add( - flags_json, "flag-f", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-v", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-l", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + json_object_string_add(lan_adj_json, "flag-f", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-b", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-v", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-l", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-s", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG + ? "1" + : "0"); + json_object_string_add(lan_adj_json, "flag-p", + lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + lan_adj_json); } /* end old deprecated key format */ @@ -1197,35 +1189,37 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, continue; snprintfrr(cnt_buf, sizeof(cnt_buf), "%d", lan->sid); - flags_json = json_object_new_object(); - json_object_int_add(flags_json, "sid", lan->sid); - json_object_int_add(flags_json, "weight", + lan_adj_json = json_object_new_object(); + json_object_int_add(lan_adj_json, "sid", + lan->sid); + json_object_int_add(lan_adj_json, "weight", lan->weight); - json_object_boolean_add(flags_json, "flagF", + json_object_boolean_add(lan_adj_json, "flagF", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_FFLG ? true : false); - json_object_boolean_add(flags_json, "flagB", + json_object_boolean_add(lan_adj_json, "flagB", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_BFLG ? true : false); - json_object_boolean_add(flags_json, "flagV", + json_object_boolean_add(lan_adj_json, "flagV", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG ? true : false); - json_object_boolean_add(flags_json, "flagL", + json_object_boolean_add(lan_adj_json, "flagL", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_LFLG ? true : false); - json_object_boolean_add(flags_json, "flagS", + json_object_boolean_add(lan_adj_json, "flagS", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_SFLG ? true : false); - json_object_boolean_add(flags_json, "flagP", + json_object_boolean_add(lan_adj_json, "flagP", lan->flags & EXT_SUBTLV_LINK_ADJ_SID_PFLG ? true : false); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + lan_adj_json); } } else @@ -1268,7 +1262,7 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, struct isis_srv6_endx_sid_subtlv *adj; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, *srv6_endx_sid_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1282,76 +1276,85 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &adj->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &adj->sid); - json_object_string_add( - flags_json, "algorithm", - sr_algorithm_string(adj->algorithm)); - json_object_int_add(flags_json, "weight", - adj->weight); - json_object_string_add( - flags_json, "behavior", - seg6local_action2str(adj->behavior)); - json_object_string_add( - flags_json, "flag-b", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_array_add(arr_adj_json, flags_json); + srv6_endx_sid_json = json_object_new_object(); + json_object_string_addf(srv6_endx_sid_json, + "sid", "%pI6", + &adj->sid); + json_object_string_add(srv6_endx_sid_json, + "algorithm", + sr_algorithm_string( + adj->algorithm)); + json_object_int_add(srv6_endx_sid_json, + "weight", adj->weight); + json_object_string_add(srv6_endx_sid_json, + "behavior", + seg6local_action2str( + adj->behavior)); + json_object_string_add(srv6_endx_sid_json, + "flag-b", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add(srv6_endx_sid_json, + "flag-s", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add(srv6_endx_sid_json, + "flag-p", + adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + json_object_array_add(arr_adj_json, + srv6_endx_sid_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, NULL, - arr_adj_json, + srv6_endx_sid_json, indent + 4); } /* end old deprecated key format */ arr_adj_json = json_object_new_array(); - json_object_object_add(json, "srv6EndSID", arr_adj_json); + json_object_object_add(json, "srv6EndXSID", + arr_adj_json); for (adj = (struct isis_srv6_endx_sid_subtlv *) exts->srv6_endx_sid.head; adj; adj = adj->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &adj->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &adj->sid); - json_object_string_add(flags_json, "algorithm", + srv6_endx_sid_json = json_object_new_object(); + json_object_string_addf(srv6_endx_sid_json, + "sid", "%pI6", + &adj->sid); + json_object_string_add(srv6_endx_sid_json, + "algorithm", sr_algorithm_string( adj->algorithm)); - json_object_int_add(flags_json, "weight", - adj->weight); - json_object_string_add(flags_json, "behavior", + json_object_int_add(srv6_endx_sid_json, + "weight", adj->weight); + json_object_string_add(srv6_endx_sid_json, + "behavior", seg6local_action2str( adj->behavior)); json_object_boolean_add( - flags_json, "flagB", + srv6_endx_sid_json, "flagB", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); json_object_boolean_add( - flags_json, "flagS", + srv6_endx_sid_json, "flagS", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); json_object_boolean_add( - flags_json, "flagP", + srv6_endx_sid_json, "flagP", !!(adj->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_endx_sid_json); if (adj->subsubtlvs) isis_format_subsubtlvs(adj->subsubtlvs, NULL, - arr_adj_json, + srv6_endx_sid_json, indent + 4); } } else @@ -1384,7 +1387,8 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, if (IS_SUBTLV(exts, EXT_SRV6_LAN_ENDX_SID)) { struct isis_srv6_lan_endx_sid_subtlv *lan; if (json) { - struct json_object *arr_adj_json, *flags_json; + struct json_object *arr_adj_json, + *srv6_lan_endx_sid_json; #if CONFDATE > 20240916 CPP_NOTICE("remove deprecated key format with -") @@ -1398,42 +1402,47 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, lan; lan = lan->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &lan->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &lan->sid); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add( - flags_json, "algorithm", - sr_algorithm_string(lan->algorithm)); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add( - flags_json, "behavior", - seg6local_action2str(lan->behavior)); - json_object_string_add( - flags_json, "flag-b", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-s", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG - ? "1" - : "0"); - json_object_string_add( - flags_json, "flag-p", - lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG - ? "1" - : "0"); - json_object_string_addf(flags_json, + srv6_lan_endx_sid_json = + json_object_new_object(); + json_object_string_addf(srv6_lan_endx_sid_json, + "sid", "%pI6", + &lan->sid); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "algorithm", + sr_algorithm_string( + lan->algorithm)); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "behavior", + seg6local_action2str( + lan->behavior)); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-b", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG + ? "1" + : "0"); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-s", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG + ? "1" + : "0"); + json_object_string_add(srv6_lan_endx_sid_json, + "flag-p", + lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG + ? "1" + : "0"); + json_object_string_addf(srv6_lan_endx_sid_json, "neighbor-id", "%pSY", lan->neighbor_id); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_lan_endx_sid_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, NULL, - arr_adj_json, + srv6_lan_endx_sid_json, indent + 4); } /* end old deprecated key format */ @@ -1446,39 +1455,44 @@ static void format_item_ext_subtlvs(struct isis_ext_subtlvs *exts, lan; lan = lan->next) { snprintfrr(cnt_buf, sizeof(cnt_buf), "%pI6", &lan->sid); - flags_json = json_object_new_object(); - json_object_string_addf(flags_json, "sid", - "%pI6", &lan->sid); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add(flags_json, "algorithm", + srv6_lan_endx_sid_json = + json_object_new_object(); + json_object_string_addf(srv6_lan_endx_sid_json, + "sid", "%pI6", + &lan->sid); + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "algorithm", sr_algorithm_string( lan->algorithm)); - json_object_int_add(flags_json, "weight", - lan->weight); - json_object_string_add(flags_json, "behavior", + json_object_int_add(srv6_lan_endx_sid_json, + "weight", lan->weight); + json_object_string_add(srv6_lan_endx_sid_json, + "behavior", seg6local_action2str( lan->behavior)); json_object_boolean_add( - flags_json, "flagB", + srv6_lan_endx_sid_json, "flagB", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_BFLG)); json_object_boolean_add( - flags_json, "flagS", + srv6_lan_endx_sid_json, "flagS", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_SFLG)); json_object_boolean_add( - flags_json, "flagP", + srv6_lan_endx_sid_json, "flagP", !!(lan->flags & EXT_SUBTLV_LINK_SRV6_ENDX_SID_PFLG)); - json_object_string_addf(flags_json, - "neighbor-id", "%pSY", + json_object_string_addf(srv6_lan_endx_sid_json, + "neighborID", "%pSY", lan->neighbor_id); - json_object_array_add(arr_adj_json, flags_json); + json_object_array_add(arr_adj_json, + srv6_lan_endx_sid_json); if (lan->subsubtlvs) isis_format_subsubtlvs(lan->subsubtlvs, NULL, - arr_adj_json, + srv6_lan_endx_sid_json, indent + 4); } } else diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 2412ec5e84..caf7d3ddfb 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -644,6 +644,70 @@ int isis_zebra_request_label_range(uint32_t base, uint32_t chunk_size) return 0; } +/** + * Request an End.X SID for an IS-IS adjacency. + * + * @param adj IS-IS Adjacency + */ +void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj) +{ + struct isis_circuit *circuit = adj->circuit; + struct isis_area *area = circuit->area; + struct in6_addr nexthop; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + bool ret; + + if (!area || !area->srv6db.srv6_locator) + return; + + /* Determine nexthop IP address */ + if (!circuit->ipv6_router || !adj->ll_ipv6_count) + return; + + nexthop = adj->ll_ipv6_addrs[0]; + + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END_X; + ctx.nh6 = nexthop; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End.X SID for IS-IS area %s", + __func__, area->area_tag); + return; + } +} + +static void request_srv6_sids(struct isis_area *area) +{ + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct listnode *node; + struct isis_adjacency *adj; + bool ret; + + if (!area || !area->srv6db.config.enabled || !area->srv6db.srv6_locator) + return; + + sr_debug("Requesting SRv6 SIDs for IS-IS area %s", area->area_tag); + + /* Request new SRv6 End SID */ + ctx.behavior = ZEBRA_SEG6_LOCAL_ACTION_END; + ret = isis_zebra_request_srv6_sid(&ctx, &sid_value, + area->srv6db.config.srv6_locator_name); + if (!ret) { + zlog_err("%s: not allocated new End SID for IS-IS area %s", + __func__, area->area_tag); + return; + } + + /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { + if (adj->ll_ipv6_count > 0) + isis_zebra_request_srv6_sid_endx(adj); + } +} + /** * Release Label Range to the Label Manager. * @@ -1119,99 +1183,47 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra) } /** - * Callback to process an SRv6 locator chunk received from SRv6 Manager (zebra). + * Internal function to process an SRv6 locator * - * @result 0 on success, -1 otherwise + * @param locator The locator to be processed */ -static int isis_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +static int isis_zebra_process_srv6_locator_internal(struct srv6_locator *locator) { struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); - struct stream *s = NULL; - struct listnode *node; struct isis_area *area; - struct srv6_locator_chunk *c; - struct srv6_locator_chunk *chunk = srv6_locator_chunk_alloc(); - struct isis_srv6_sid *sid; - struct isis_adjacency *adj; - enum srv6_endpoint_behavior_codepoint behavior; - bool allocated = false; - - if (!isis) { - srv6_locator_chunk_free(&chunk); - return -1; - } + struct listnode *node; - /* Decode the received zebra message */ - s = zclient->ibuf; - if (zapi_srv6_locator_chunk_decode(s, chunk) < 0) { - srv6_locator_chunk_free(&chunk); + if (!isis || !locator) return -1; - } - sr_debug( - "Received SRv6 locator chunk from zebra: name %s, " - "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", - chunk->locator_name, &chunk->prefix, chunk->block_bits_length, - chunk->node_bits_length, chunk->function_bits_length, - chunk->argument_bits_length); + zlog_info("%s: Received SRv6 locator %s %pFX, loc-block-len=%u, loc-node-len=%u func-len=%u, arg-len=%u", + __func__, locator->name, &locator->prefix, + locator->block_bits_length, locator->node_bits_length, + locator->function_bits_length, locator->argument_bits_length); /* Walk through all areas of the ISIS instance */ for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - if (strncmp(area->srv6db.config.srv6_locator_name, - chunk->locator_name, - sizeof(area->srv6db.config.srv6_locator_name)) != 0) + /* + * Check if the IS-IS area is configured to use the received + * locator + */ + if (strncmp(area->srv6db.config.srv6_locator_name, locator->name, + sizeof(area->srv6db.config.srv6_locator_name)) != 0) { + zlog_err("%s: SRv6 Locator name unmatch %s:%s", + __func__, area->srv6db.config.srv6_locator_name, + locator->name); continue; - - for (ALL_LIST_ELEMENTS_RO(area->srv6db.srv6_locator_chunks, - node, c)) { - if (!prefix_cmp(&c->prefix, &chunk->prefix)) { - srv6_locator_chunk_free(&chunk); - return 0; - } - } - - sr_debug( - "SRv6 locator chunk (locator %s, prefix %pFX) assigned to IS-IS area %s", - chunk->locator_name, &chunk->prefix, area->area_tag); - - /* Add the SRv6 Locator chunk to the per-area chunks list */ - listnode_add(area->srv6db.srv6_locator_chunks, chunk); - - /* Decide which behavior to use,depending on the locator type - * (i.e. uSID vs classic locator) */ - behavior = (CHECK_FLAG(chunk->flags, SRV6_LOCATOR_USID)) - ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID - : SRV6_ENDPOINT_BEHAVIOR_END; - - /* Allocate new SRv6 End SID */ - sid = isis_srv6_sid_alloc(area, chunk, behavior, 0); - if (!sid) - return -1; - - /* Install the new SRv6 End SID in the forwarding plane through - * Zebra */ - isis_zebra_srv6_sid_install(area, sid); - - /* Store the SID */ - listnode_add(area->srv6db.srv6_sids, sid); - - /* Create SRv6 End.X SIDs from existing IS-IS Adjacencies */ - for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, node, adj)) { - if (adj->ll_ipv6_count > 0) - srv6_endx_sid_add(adj); } - /* Regenerate LSPs to advertise the new locator and the SID */ - lsp_regenerate_schedule(area, area->is_type, 0); + sr_debug("SRv6 locator (locator %s, prefix %pFX) set for IS-IS area %s", + locator->name, &locator->prefix, area->area_tag); - allocated = true; - break; - } + /* Store the locator in the IS-IS area */ + area->srv6db.srv6_locator = srv6_locator_alloc(locator->name); + srv6_locator_copy(area->srv6db.srv6_locator, locator); - if (!allocated) { - sr_debug("No IS-IS area configured for the locator %s", - chunk->locator_name); - srv6_locator_chunk_free(&chunk); + /* Request SIDs from the locator */ + request_srv6_sids(area); } return 0; @@ -1226,8 +1238,6 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) { struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); struct srv6_locator loc = {}; - struct listnode *node; - struct isis_area *area; if (!isis) return -1; @@ -1236,33 +1246,7 @@ static int isis_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) if (zapi_srv6_locator_decode(zclient->ibuf, &loc) < 0) return -1; - sr_debug( - "New SRv6 locator allocated in zebra: name %s, " - "prefix %pFX, block_len %u, node_len %u, func_len %u, arg_len %u", - loc.name, &loc.prefix, loc.block_bits_length, - loc.node_bits_length, loc.function_bits_length, - loc.argument_bits_length); - - /* Lookup on the IS-IS areas */ - for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - /* If SRv6 is enabled on this area and the configured locator - * corresponds to the new locator, then request a chunk from the - * locator */ - if (area->srv6db.config.enabled && - strncmp(area->srv6db.config.srv6_locator_name, loc.name, - sizeof(area->srv6db.config.srv6_locator_name)) == 0) { - sr_debug( - "Sending a request to get a chunk from the SRv6 locator %s (%pFX) " - "for IS-IS area %s", - loc.name, &loc.prefix, area->area_tag); - - if (isis_zebra_srv6_manager_get_locator_chunk( - loc.name) < 0) - return -1; - } - } - - return 0; + return isis_zebra_process_srv6_locator_internal(&loc); } /** @@ -1335,6 +1319,9 @@ static int isis_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) } } + srv6_locator_free(area->srv6db.srv6_locator); + area->srv6db.srv6_locator = NULL; + /* Regenerate LSPs to advertise that the locator no longer * exists */ lsp_regenerate_schedule(area, area->is_type, 0); @@ -1368,6 +1355,232 @@ int isis_zebra_srv6_manager_release_locator_chunk(const char *name) return srv6_manager_release_locator_chunk(zclient, name); } +/** + * Ask the SRv6 Manager (zebra) about a specific locator + * + * @param name Locator name + * @return 0 on success, -1 otherwise + */ +int isis_zebra_srv6_manager_get_locator(const char *name) +{ + if (!name) + return -1; + + /* + * Send the Get Locator request to the SRv6 Manager and return the + * result + */ + return srv6_manager_get_locator(zclient, name); +} + +/** + * Ask the SRv6 Manager (zebra) to allocate a SID. + * + * Optionally, it is possible to provide an IPv6 address (sid_value parameter). + * + * When sid_value is provided, the SRv6 Manager allocates the requested SID + * address, if the request can be satisfied (explicit allocation). + * + * When sid_value is not provided, the SRv6 Manager allocates any available SID + * from the provided locator (dynamic allocation). + * + * @param ctx Context to be associated with the request SID + * @param sid_value IPv6 address to be associated with the requested SID (optional) + * @param locator_name Name of the locator from which the SID must be allocated + */ +bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + int ret; + + if (!ctx || !locator_name) + return false; + + /* + * Send the Get SRv6 SID request to the SRv6 Manager and check the + * result + */ + ret = srv6_manager_get_sid(zclient, ctx, sid_value, locator_name, NULL); + if (ret < 0) { + zlog_warn("%s: error getting SRv6 SID!", __func__); + return false; + } + + return true; +} + +/** + * Ask the SRv6 Manager (zebra) to release a previously allocated SID. + * + * This function is used to tell the SRv6 Manager that IS-IS no longer intends + * to use the SID. + * + * @param ctx Context to be associated with the SID to be released + */ +void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx) +{ + int ret; + + if (!ctx) + return; + + /* + * Send the Release SRv6 SID request to the SRv6 Manager and check the + * result + */ + ret = srv6_manager_release_sid(zclient, ctx); + if (ret < 0) { + zlog_warn("%s: error releasing SRv6 SID!", __func__); + return; + } +} + +static int isis_zebra_srv6_sid_notify(ZAPI_CALLBACK_ARGS) +{ + struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT); + struct srv6_sid_ctx ctx; + struct in6_addr sid_addr; + enum zapi_srv6_sid_notify note; + uint32_t sid_func; + struct isis_area *area; + struct listnode *node, *nnode, *n; + char buf[256]; + struct srv6_locator *locator; + struct prefix_ipv6 tmp_prefix; + struct srv6_adjacency *sra; + enum srv6_endpoint_behavior_codepoint behavior; + struct isis_srv6_sid *sid; + struct isis_adjacency *adj; + + if (!isis) + return -1; + + /* Decode the received notification message */ + if (!zapi_srv6_sid_notify_decode(zclient->ibuf, &ctx, &sid_addr, + &sid_func, NULL, ¬e, NULL)) { + zlog_err("%s : error in msg decode", __func__); + return -1; + } + + sr_debug("%s: received SRv6 SID notify: ctx %s sid_value %pI6 sid_func %u note %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), &ctx), &sid_addr, + sid_func, zapi_srv6_sid_notify2str(note)); + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (!area->srv6db.config.enabled || !area->srv6db.srv6_locator) + continue; + + locator = area->srv6db.srv6_locator; + + /* Verify that the received SID belongs to the configured locator */ + if (note == ZAPI_SRV6_SID_ALLOCATED) { + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = sid_addr; + + if (!prefix_match((struct prefix *)&locator->prefix, + (struct prefix *)&tmp_prefix)) { + sr_debug("%s : ignoring SRv6 SID notify: locator (area %s) does not match", + __func__, area->area_tag); + continue; + } + } + + /* Handle notification */ + switch (note) { + case ZAPI_SRV6_SID_ALLOCATED: + sr_debug("SRv6 SID %pI6 %s ALLOCATED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + if (ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* Remove old End SIDs, if any */ + for (ALL_LIST_ELEMENTS(area->srv6db.srv6_sids, + node, nnode, sid)) { + isis_zebra_srv6_sid_uninstall(area, sid); + listnode_delete(area->srv6db.srv6_sids, + sid); + } + + /* Allocate new SRv6 End SID */ + behavior = + (CHECK_FLAG(locator->flags, + SRV6_LOCATOR_USID)) + ? SRV6_ENDPOINT_BEHAVIOR_END_NEXT_CSID + : SRV6_ENDPOINT_BEHAVIOR_END; + sid = isis_srv6_sid_alloc(area, + area->srv6db + .srv6_locator, + behavior, &sid_addr); + if (!sid) { + zlog_warn("%s: isis_srv6_sid_alloc failed", + __func__); + return -1; + } + + /* + * Install the new SRv6 End SID in the forwarding plane through + * Zebra + */ + isis_zebra_srv6_sid_install(area, sid); + + /* Store the SID */ + listnode_add(area->srv6db.srv6_sids, sid); + + } else if (ctx.behavior == + ZEBRA_SEG6_LOCAL_ACTION_END_X) { + for (ALL_LIST_ELEMENTS_RO(area->adjacency_list, + n, adj)) { + /* Check if the End.X SID is for this adjacecny */ + if (adj->ll_ipv6_count == 0 || + memcmp(&adj->ll_ipv6_addrs[0], + &ctx.nh6, + sizeof(struct in6_addr)) != 0) + continue; + + /* Remove old End.X SIDs, if any */ + for (ALL_LIST_ELEMENTS(adj->srv6_endx_sids, + node, nnode, sra)) + srv6_endx_sid_del(sra); + + /* Allocate new End.X SID for the adjacency */ + srv6_endx_sid_add_single(adj, false, + NULL, + &sid_addr); + } + } else { + zlog_warn("%s: unsupported behavior %u", + __func__, ctx.behavior); + return -1; + } + break; + case ZAPI_SRV6_SID_RELEASED: + sr_debug("SRv6 SID %pI6 %s: RELEASED", &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + break; + case ZAPI_SRV6_SID_FAIL_ALLOC: + sr_debug("SRv6 SID %pI6 %s: Failed to allocate", + &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + /* Error will be logged by zebra module */ + break; + case ZAPI_SRV6_SID_FAIL_RELEASE: + zlog_warn("%s: SRv6 SID %pI6 %s failure to release", + __func__, &sid_addr, + srv6_sid_ctx2str(buf, sizeof(buf), &ctx)); + + /* Error will be logged by zebra module */ + break; + } + + /* Regenerate LSPs to advertise the new locator and the SID */ + lsp_regenerate_schedule(area, area->is_type, 0); + } + + return 0; +} + static zclient_handler *const isis_handlers[] = { [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra, [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, @@ -1380,10 +1593,9 @@ static zclient_handler *const isis_handlers[] = { [ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify, - [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = - isis_zebra_process_srv6_locator_chunk, [ZEBRA_SRV6_LOCATOR_ADD] = isis_zebra_process_srv6_locator_add, [ZEBRA_SRV6_LOCATOR_DELETE] = isis_zebra_process_srv6_locator_delete, + [ZEBRA_SRV6_SID_NOTIFY] = isis_zebra_srv6_sid_notify, }; void isis_zebra_init(struct event_loop *master, int instance) @@ -1416,5 +1628,4 @@ void isis_zebra_stop(void) zclient_free(zclient_sync); zclient_stop(zclient); zclient_free(zclient); - frr_fini(); } diff --git a/isisd/isis_zebra.h b/isisd/isis_zebra.h index f1684b7c25..79da16efac 100644 --- a/isisd/isis_zebra.h +++ b/isisd/isis_zebra.h @@ -68,4 +68,11 @@ void isis_zebra_srv6_adj_sid_uninstall(struct srv6_adjacency *sra); extern int isis_zebra_srv6_manager_get_locator_chunk(const char *name); extern int isis_zebra_srv6_manager_release_locator_chunk(const char *name); +extern int isis_zebra_srv6_manager_get_locator(const char *name); +extern void isis_zebra_request_srv6_sid_endx(struct isis_adjacency *adj); +extern bool isis_zebra_request_srv6_sid(const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void isis_zebra_release_srv6_sid(const struct srv6_sid_ctx *ctx); + #endif /* _ZEBRA_ISIS_ZEBRA_H */ diff --git a/isisd/isisd.c b/isisd/isisd.c index 982df0839b..2863fd913f 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -176,6 +176,11 @@ void isis_master_init(struct event_loop *master) im->master = master; } +void isis_master_terminate(void) +{ + list_delete(&im->isis); +} + struct isis *isis_new(const char *vrf_name) { struct vrf *vrf; @@ -272,7 +277,7 @@ void isis_area_del_circuit(struct isis_area *area, struct isis_circuit *circuit) isis_csm_state_change(ISIS_DISABLE, circuit, area); } -static void delete_area_addr(void *arg) +void isis_area_address_delete(void *arg) { struct iso_address *addr = (struct iso_address *)arg; @@ -330,7 +335,7 @@ struct isis_area *isis_area_create(const char *area_tag, const char *vrf_name) area->circuit_list = list_new(); area->adjacency_list = list_new(); area->area_addrs = list_new(); - area->area_addrs->del = delete_area_addr; + area->area_addrs->del = isis_area_address_delete; if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) event_add_timer(master, lsp_tick, area, 1, &area->t_tick); @@ -471,6 +476,29 @@ struct isis_area *isis_area_lookup(const char *area_tag, vrf_id_t vrf_id) return NULL; } +struct isis_area *isis_area_lookup_by_sysid(const uint8_t *sysid) +{ + struct isis_area *area; + struct listnode *node; + struct isis *isis; + struct iso_address *addr = NULL; + + isis = isis_lookup_by_sysid(sysid); + if (isis == NULL) + return NULL; + + for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { + if (listcount(area->area_addrs) > 0) { + addr = listgetdata(listhead(area->area_addrs)); + if (!memcmp(addr->area_addr + addr->addr_len, sysid, + ISIS_SYS_ID_LEN)) + return area; + } + } + + return NULL; +} + int isis_area_get(struct vty *vty, const char *area_tag) { struct isis_area *area; @@ -496,6 +524,7 @@ void isis_area_destroy(struct isis_area *area) { struct listnode *node, *nnode; struct isis_circuit *circuit; + struct iso_address *addr; QOBJ_UNREG(area); @@ -545,6 +574,15 @@ void isis_area_destroy(struct isis_area *area) if (!CHECK_FLAG(im->options, F_ISIS_UNIT_TEST)) isis_redist_area_finish(area); + if (listcount(area->area_addrs) > 0) { + addr = listgetdata(listhead(area->area_addrs)); + if (!memcmp(addr->area_addr + addr->addr_len, area->isis->sysid, + ISIS_SYS_ID_LEN)) { + memset(area->isis->sysid, 0, ISIS_SYS_ID_LEN); + area->isis->sysid_set = 0; + } + } + list_delete(&area->area_addrs); for (int i = SPF_PREFIX_PRIO_CRITICAL; i <= SPF_PREFIX_PRIO_MEDIUM; diff --git a/isisd/isisd.h b/isisd/isisd.h index f5042e4ad5..1ae39f0ae9 100644 --- a/isisd/isisd.h +++ b/isisd/isisd.h @@ -268,6 +268,7 @@ DECLARE_HOOK(isis_area_overload_bit_update, (struct isis_area * area), (area)); void isis_terminate(void); void isis_master_init(struct event_loop *master); +void isis_master_terminate(void); void isis_vrf_link(struct isis *isis, struct vrf *vrf); void isis_vrf_unlink(struct isis *isis, struct vrf *vrf); struct isis *isis_lookup_by_vrfid(vrf_id_t vrf_id); @@ -285,10 +286,12 @@ void isis_area_add_circuit(struct isis_area *area, void isis_area_del_circuit(struct isis_area *area, struct isis_circuit *circuit); +void isis_area_address_delete(void *arg); struct isis_area *isis_area_create(const char *, const char *); struct isis_area *isis_area_lookup(const char *, vrf_id_t vrf_id); struct isis_area *isis_area_lookup_by_vrf(const char *area_tag, const char *vrf_name); +struct isis_area *isis_area_lookup_by_sysid(const uint8_t *sysid); int isis_area_get(struct vty *vty, const char *area_tag); void isis_area_destroy(struct isis_area *area); void isis_filter_update(struct access_list *access); diff --git a/lib/agentx.c b/lib/agentx.c index 19f2a6b7fc..2a3ff2355e 100644 --- a/lib/agentx.c +++ b/lib/agentx.c @@ -377,4 +377,16 @@ void smux_events_update(void) agentx_events_update(); } +static void smux_events_delete_thread(void *arg) +{ + XFREE(MTYPE_TMP, arg); +} + +void smux_terminate(void) +{ + if (events) { + events->del = smux_events_delete_thread; + list_delete(&events); + } +} #endif /* SNMP_AGENTX */ diff --git a/lib/bfd.c b/lib/bfd.c index 2222bb9547..4535fc1233 100644 --- a/lib/bfd.c +++ b/lib/bfd.c @@ -1334,3 +1334,9 @@ int bfd_nht_update(const struct prefix *match, const struct zapi_route *route) return 0; } + +bool bfd_session_is_down(const struct bfd_session_params *session) +{ + return session->bss.state == BSS_DOWN || + session->bss.state == BSS_ADMIN_DOWN; +} diff --git a/lib/bfd.h b/lib/bfd.h index bfa5287340..48929a9564 100644 --- a/lib/bfd.h +++ b/lib/bfd.h @@ -464,6 +464,8 @@ extern bool bfd_protocol_integration_shutting_down(void); extern int bfd_nht_update(const struct prefix *match, const struct zapi_route *route); +extern bool bfd_session_is_down(const struct bfd_session_params *session); + #ifdef __cplusplus } #endif diff --git a/lib/command.h b/lib/command.h index e4c575e8d7..cb105c656c 100644 --- a/lib/command.h +++ b/lib/command.h @@ -161,6 +161,9 @@ enum node_type { SRV6_LOCS_NODE, /* SRv6 locators node */ SRV6_LOC_NODE, /* SRv6 locator node */ SRV6_ENCAP_NODE, /* SRv6 encapsulation node */ + SRV6_SID_FORMATS_NODE, /* SRv6 SID formats config node */ + SRV6_SID_FORMAT_USID_F3216_NODE, /* SRv6 uSID f3216 format config node */ + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, /* SRv6 uncompressed f4024 format config node */ VTY_NODE, /* Vty node. */ FPM_NODE, /* Dataplane FPM node. */ LINK_PARAMS_NODE, /* Link-parameters node */ @@ -179,6 +182,8 @@ enum node_type { ISIS_SRV6_NODE_MSD_NODE, /* ISIS SRv6 Node MSDs node */ MGMTD_NODE, /* MGMTD node. */ RPKI_VRF_NODE, /* RPKI node for VRF */ + PIM_NODE, /* PIM protocol mode */ + PIM6_NODE, /* PIM protocol for IPv6 mode */ NODE_TYPE_MAX, /* maximum */ }; /* clang-format on */ @@ -247,9 +252,11 @@ struct cmd_node { /* Argc max counts. */ #define CMD_ARGC_MAX 256 +/* clang-format off */ + /* helper defines for end-user DEFUN* macros */ #define DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attrs, dnum) \ - static const struct cmd_element cmdname = { \ + const struct cmd_element cmdname = { \ .string = cmdstr, \ .func = funcname, \ .doc = helpstr, \ @@ -276,7 +283,7 @@ struct cmd_node { /* DEFPY variants */ #define DEFPY_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ funcdecl_##funcname #define DEFPY(funcname, cmdname, cmdstr, helpstr) \ @@ -303,7 +310,7 @@ struct cmd_node { #define DEFUN_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUN(funcname, cmdname, cmdstr, helpstr) \ @@ -340,7 +347,8 @@ struct cmd_node { /* DEFUN + DEFSH */ #define DEFUNSH_ATTR(daemon, funcname, cmdname, cmdstr, helpstr, attr) \ DEFUN_CMD_FUNC_DECL(funcname) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, daemon) \ + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, \ + daemon) \ DEFUN_CMD_FUNC_TEXT(funcname) #define DEFUNSH(daemon, funcname, cmdname, cmdstr, helpstr) \ @@ -352,7 +360,7 @@ struct cmd_node { /* ALIAS macro which define existing command's alias. */ #define ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, attr) \ - DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) + static DEFUN_CMD_ELEMENT(funcname, cmdname, cmdstr, helpstr, attr, 0) #define ALIAS(funcname, cmdname, cmdstr, helpstr) \ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, 0) @@ -371,6 +379,8 @@ struct cmd_node { #define ALIAS_YANG(funcname, cmdname, cmdstr, helpstr) \ ALIAS_ATTR(funcname, cmdname, cmdstr, helpstr, CMD_ATTR_YANG) +/* clang-format on */ + /* Some macroes */ /* diff --git a/lib/command_graph.c b/lib/command_graph.c index ff3c11db69..20ab6b321b 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -267,6 +267,9 @@ static bool cmd_nodes_equal(struct graph_node *ga, struct graph_node *gb) case NEG_ONLY_TKN: case WORD_TKN: case ASNUM_TKN: +#ifdef BUILDING_CLIPPY + case CMD_ELEMENT_TKN: +#endif return true; } diff --git a/lib/command_graph.h b/lib/command_graph.h index 25aa47db7b..313c97fe87 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -54,6 +54,9 @@ enum cmd_token_type { END_TKN, // last token in line NEG_ONLY_TKN, // filter token, match if "no ..." command +#ifdef BUILDING_CLIPPY + CMD_ELEMENT_TKN, // python bindings only +#endif SPECIAL_TKN = FORK_TKN, }; /* clang-format on */ diff --git a/lib/command_py.c b/lib/command_py.c index f8abcf8ef4..a77adcd7dc 100644 --- a/lib/command_py.c +++ b/lib/command_py.c @@ -29,6 +29,7 @@ struct wrap_graph; static PyObject *graph_to_pyobj(struct wrap_graph *graph, struct graph_node *gn); +static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i); /* * nodes are wrapped as follows: @@ -44,13 +45,6 @@ struct wrap_graph_node { bool allowrepeat; const char *type; - bool deprecated; - bool hidden; - const char *text; - const char *desc; - const char *varname; - long long min, max; - struct graph_node *node; struct wrap_graph *wgraph; size_t idx; @@ -68,6 +62,7 @@ struct wrap_graph { char *definition; struct graph *graph; + size_t n_nodewrappers; struct wrap_graph_node **nodewrappers; }; @@ -84,11 +79,75 @@ static PyObject *refuse_new(PyTypeObject *type, PyObject *args, PyObject *kwds) READONLY, (char *)#name " (" #type ")" \ } static PyMemberDef members_graph_node[] = { - member(allowrepeat, T_BOOL), member(type, T_STRING), - member(deprecated, T_BOOL), member(hidden, T_BOOL), - member(text, T_STRING), member(desc, T_STRING), - member(min, T_LONGLONG), member(max, T_LONGLONG), - member(varname, T_STRING), {}, + /* clang-format off */ + member(type, T_STRING), + member(idx, T_ULONG), + {}, + /* clang-format on */ +}; +#undef member + +static PyObject *graph_node_get_str(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + const char *val = *(const char **)offset; + + if (!val) + Py_RETURN_NONE; + return PyUnicode_FromString(val); +} + +static PyObject *graph_node_get_bool(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + bool val = *(bool *)offset; + + return PyBool_FromLong(val); +} + +static PyObject *graph_node_get_ll(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + long long val = *(long long *)offset; + + return PyLong_FromLongLong(val); +} + +static PyObject *graph_node_get_u8(PyObject *self, void *poffset) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + void *offset = (char *)wrap->node->data + (ptrdiff_t)poffset; + uint8_t val = *(uint8_t *)offset; + + return PyLong_FromUnsignedLong(val); +} + +/* clang-format off */ +#define member(name, variant) \ + { \ + (char *)#name, \ + graph_node_get_##variant, \ + NULL, \ + (char *)#name " (" #variant ")", \ + (void *)offsetof(struct cmd_token, name), \ + } +/* clang-format on */ + +static PyGetSetDef getset_graph_node[] = { + /* clang-format off */ + member(attr, u8), + member(allowrepeat, bool), + member(varname_src, u8), + member(text, str), + member(desc, str), + member(min, ll), + member(max, ll), + member(varname, str), + {}, + /* clang-format on */ }; #undef member @@ -101,12 +160,30 @@ static PyObject *graph_node_next(PyObject *self, PyObject *args) struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; PyObject *pylist; - if (wrap->node->data - && ((struct cmd_token *)wrap->node->data)->type == END_TKN) + if (wrap->node->data && + ((struct cmd_token *)wrap->node->data)->type == CMD_ELEMENT_TKN) return PyList_New(0); pylist = PyList_New(vector_active(wrap->node->to)); for (size_t i = 0; i < vector_active(wrap->node->to); i++) { struct graph_node *gn = vector_slot(wrap->node->to, i); + + PyList_SetItem(pylist, i, graph_to_pyobj(wrap->wgraph, gn)); + } + return pylist; +}; + +static PyObject *graph_node_prev(PyObject *self, PyObject *args) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + PyObject *pylist; + + if (wrap->node->data && + ((struct cmd_token *)wrap->node->data)->type == START_TKN) + return PyList_New(0); + pylist = PyList_New(vector_active(wrap->node->from)); + for (size_t i = 0; i < vector_active(wrap->node->from); i++) { + struct graph_node *gn = vector_slot(wrap->node->from, i); + PyList_SetItem(pylist, i, graph_to_pyobj(wrap->wgraph, gn)); } return pylist; @@ -118,30 +195,60 @@ static PyObject *graph_node_next(PyObject *self, PyObject *args) static PyObject *graph_node_join(PyObject *self, PyObject *args) { struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + struct cmd_token *tok; if (!wrap->node->data || ((struct cmd_token *)wrap->node->data)->type == END_TKN) Py_RETURN_NONE; - struct cmd_token *tok = wrap->node->data; + tok = wrap->node->data; if (tok->type != FORK_TKN) Py_RETURN_NONE; return graph_to_pyobj(wrap->wgraph, tok->forkjoin); }; +static PyObject *graph_node_fork(PyObject *self, PyObject *args) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)self; + struct cmd_token *tok; + + if (!wrap->node->data || + ((struct cmd_token *)wrap->node->data)->type == END_TKN) + Py_RETURN_NONE; + + tok = wrap->node->data; + if (tok->type != JOIN_TKN) + Py_RETURN_NONE; + + return graph_to_pyobj(wrap->wgraph, tok->forkjoin); +}; + static PyMethodDef methods_graph_node[] = { - {"next", graph_node_next, METH_NOARGS, "outbound graph edge list"}, - {"join", graph_node_join, METH_NOARGS, "outbound join node"}, - {}}; + { "next", graph_node_next, METH_NOARGS, "outbound graph edge list" }, + { "prev", graph_node_prev, METH_NOARGS, "inbound graph edge list" }, + { "join", graph_node_join, METH_NOARGS, "outbound join node" }, + { "fork", graph_node_fork, METH_NOARGS, "inbound fork node" }, + {} +}; static void graph_node_wrap_free(void *arg) { struct wrap_graph_node *wrap = arg; + + assert(wrap->idx < wrap->wgraph->n_nodewrappers); wrap->wgraph->nodewrappers[wrap->idx] = NULL; Py_DECREF(wrap->wgraph); } +static PyObject *repr_graph_node(PyObject *arg) +{ + struct wrap_graph_node *wrap = (struct wrap_graph_node *)arg; + + return PyUnicode_FromFormat("<_clippy.GraphNode %p [%zu] %s>", + wrap->node, wrap->idx, wrap->type); +} + static PyTypeObject typeobj_graph_node = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.GraphNode", .tp_basicsize = sizeof(struct wrap_graph_node), @@ -150,13 +257,14 @@ static PyTypeObject typeobj_graph_node = { .tp_new = refuse_new, .tp_free = graph_node_wrap_free, .tp_members = members_graph_node, + .tp_getset = getset_graph_node, .tp_methods = methods_graph_node, + .tp_repr = repr_graph_node, }; static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, struct graph_node *gn) { - struct wrap_graph_node *wrap; size_t i; for (i = 0; i < vector_active(wgraph->graph->nodes); i++) @@ -166,6 +274,24 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, PyErr_SetString(PyExc_ValueError, "cannot find node in graph"); return NULL; } + + return graph_to_pyobj_idx(wgraph, i); +} + +static PyObject *graph_to_pyobj_idx(struct wrap_graph *wgraph, size_t i) +{ + struct wrap_graph_node *wrap; + struct graph_node *gn = vector_slot(wgraph->graph->nodes, i); + + if (i >= wgraph->n_nodewrappers) { + wgraph->nodewrappers = + realloc(wgraph->nodewrappers, + (i + 1) * sizeof(wgraph->nodewrappers[0])); + memset(wgraph->nodewrappers + wgraph->n_nodewrappers, 0, + sizeof(wgraph->nodewrappers[0]) * + (i + 1 - wgraph->n_nodewrappers)); + wgraph->n_nodewrappers = i + 1; + } if (wgraph->nodewrappers[i]) { PyObject *obj = (PyObject *)wgraph->nodewrappers[i]; Py_INCREF(obj); @@ -209,19 +335,11 @@ static PyObject *graph_to_pyobj(struct wrap_graph *wgraph, item(START_TKN); item(END_TKN); item(NEG_ONLY_TKN); + item(CMD_ELEMENT_TKN); #undef item default: wrap->type = "???"; } - - wrap->deprecated = !!(tok->attr & CMD_ATTR_DEPRECATED); - wrap->hidden = !!(tok->attr & CMD_ATTR_HIDDEN); - wrap->text = tok->text; - wrap->desc = tok->desc; - wrap->varname = tok->varname; - wrap->min = tok->min; - wrap->max = tok->max; - wrap->allowrepeat = tok->allowrepeat; } return (PyObject *)wrap; @@ -246,9 +364,13 @@ static PyObject *graph_first(PyObject *self, PyObject *args) return graph_to_pyobj(gwrap, gn); }; +static PyObject *graph_merge(PyObject *self, PyObject *args); + static PyMethodDef methods_graph[] = { - {"first", graph_first, METH_NOARGS, "first graph node"}, - {}}; + { "first", graph_first, METH_NOARGS, "first graph node" }, + { "merge", graph_merge, METH_VARARGS, "merge graphs" }, + {} +}; static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds); @@ -262,6 +384,30 @@ static void graph_wrap_free(void *arg) free(wgraph->definition); } +static Py_ssize_t graph_length(PyObject *self) +{ + struct wrap_graph *gwrap = (struct wrap_graph *)self; + + return vector_active(gwrap->graph->nodes); +} + +static PyObject *graph_item(PyObject *self, Py_ssize_t idx) +{ + struct wrap_graph *gwrap = (struct wrap_graph *)self; + + if (idx >= vector_active(gwrap->graph->nodes)) + return PyErr_Format(PyExc_IndexError, + "index %zd past graph size %u", idx, + vector_active(gwrap->graph->nodes)); + + return graph_to_pyobj_idx(gwrap, idx); +} + +static PySequenceMethods seq_graph = { + .sq_length = graph_length, + .sq_item = graph_item, +}; + static PyTypeObject typeobj_graph = { PyVarObject_HEAD_INIT(NULL, 0).tp_name = "_clippy.Graph", .tp_basicsize = sizeof(struct wrap_graph), @@ -271,35 +417,62 @@ static PyTypeObject typeobj_graph = { .tp_free = graph_wrap_free, .tp_members = members_graph, .tp_methods = methods_graph, + .tp_as_sequence = &seq_graph, }; +static PyObject *graph_merge(PyObject *self, PyObject *args) +{ + PyObject *py_other; + struct wrap_graph *gwrap = (struct wrap_graph *)self; + struct wrap_graph *gother; + + if (!PyArg_ParseTuple(args, "O!", &typeobj_graph, &py_other)) + return NULL; + + gother = (struct wrap_graph *)py_other; + cmd_graph_merge(gwrap->graph, gother->graph, +1); + Py_RETURN_NONE; +} + /* top call / entrypoint for python code */ static PyObject *graph_parse(PyTypeObject *type, PyObject *args, PyObject *kwds) { - const char *def, *doc = NULL; + const char *def, *doc = NULL, *name = NULL; struct wrap_graph *gwrap; - static const char *kwnames[] = {"cmddef", "doc", NULL}; + static const char *const kwnames[] = { "cmddef", "doc", "name", NULL }; gwrap = (struct wrap_graph *)typeobj_graph.tp_alloc(&typeobj_graph, 0); if (!gwrap) return NULL; - if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|s", (char **)kwnames, - &def, &doc)) + if (!PyArg_ParseTupleAndKeywords(args, kwds, "z|ss", (char **)kwnames, + &def, &doc, &name)) return NULL; struct graph *graph = graph_new(); struct cmd_token *token = cmd_token_new(START_TKN, 0, NULL, NULL); graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del); - struct cmd_element cmd = {.string = def, .doc = doc}; - cmd_graph_parse(graph, &cmd); - cmd_graph_names(graph); + if (def) { + struct cmd_element cmd = { .string = def, .doc = doc }; + struct graph_node *last; + + cmd_graph_parse(graph, &cmd); + cmd_graph_names(graph); + + last = vector_slot(graph->nodes, + vector_active(graph->nodes) - 1); + assert(last->data == &cmd); + + last->data = cmd_token_new(CMD_ELEMENT_TKN, 0, name, def); + last->del = (void (*)(void *))cmd_token_del; + + gwrap->definition = strdup(def); + } else { + gwrap->definition = strdup("NULL"); + } gwrap->graph = graph; - gwrap->definition = strdup(def); - gwrap->nodewrappers = calloc(vector_active(graph->nodes), - sizeof(gwrap->nodewrappers[0])); return (PyObject *)gwrap; } diff --git a/lib/darr.h b/lib/darr.h index 404869d9a2..2b9a0a0c02 100644 --- a/lib/darr.h +++ b/lib/darr.h @@ -24,6 +24,8 @@ * - darr_ensure_i * - darr_ensure_i_mt * - darr_free + * - darr_free_free + * - darr_free_func * - darr_insert * - darr_insert_mt * - darr_insertz @@ -217,6 +219,41 @@ void *__darr_resize(void *a, uint count, size_t esize, struct memtype *mt); } \ } while (0) +/** + * Free memory allocated for the dynamic array `A`, calling `darr_free` for + * each element of the array first. + * + * Args: + * A: The dynamic array, can be NULL. + */ +#define darr_free_free(A) \ + do { \ + for (uint __i = 0; __i < darr_len(A); __i++) \ + if ((A)[__i]) { \ + struct darr_metadata *__meta = \ + _darr_meta((A)[__i]); \ + XFREE(__meta->mtype, __meta); \ + } \ + darr_free(A); \ + } while (0) + +/** + * Free memory allocated for the dynamic array `A`, calling `F` routine + * for each element of the array first. + * + * Args: + * A: The dynamic array, can be NULL. + * F: The function to call for each element. + */ + +#define darr_free_func(A, F) \ + do { \ + for (uint __i = 0; __i < darr_len(A); __i++) { \ + F((A)[__i]); \ + } \ + darr_free(A); \ + } while (0) + /** * Make sure that there is room in the dynamic array `A` to add `C` elements. * diff --git a/lib/event.c b/lib/event.c index fc46a11c0b..d925d0d5f0 100644 --- a/lib/event.c +++ b/lib/event.c @@ -304,9 +304,6 @@ static uint8_t parse_filter(const char *filterstr) return filter; } -#if CONFDATE > 20240707 - CPP_NOTICE("Remove `show thread ...` commands") -#endif DEFUN_NOSH (show_event_cpu, show_event_cpu_cmd, "show event cpu [FILTER]", @@ -332,14 +329,6 @@ DEFUN_NOSH (show_event_cpu, return CMD_SUCCESS; } -ALIAS(show_event_cpu, - show_thread_cpu_cmd, - "show thread cpu [FILTER]", - SHOW_STR - "Thread information\n" - "Thread CPU usage\n" - "Display filter (rwtex)\n") - DEFPY (service_cputime_stats, service_cputime_stats_cmd, "[no] service cputime-stats", @@ -440,19 +429,15 @@ DEFUN_NOSH (show_event_poll, return CMD_SUCCESS; } -ALIAS(show_event_poll, - show_thread_poll_cmd, - "show thread poll", - SHOW_STR - "Thread information\n" - "Show poll FD's and information\n") - -DEFUN (clear_thread_cpu, - clear_thread_cpu_cmd, - "clear thread cpu [FILTER]", +#if CONFDATE > 20241231 +CPP_NOTICE("Remove `clear thread cpu` command") +#endif +DEFUN (clear_event_cpu, + clear_event_cpu_cmd, + "clear event cpu [FILTER]", "Clear stored data in all pthreads\n" - "Thread information\n" - "Thread CPU usage\n" + "Event information\n" + "Event CPU usage\n" "Display filter (rwtexb)\n") { uint8_t filter = (uint8_t)-1U; @@ -472,6 +457,14 @@ DEFUN (clear_thread_cpu, return CMD_SUCCESS; } +ALIAS (clear_event_cpu, + clear_thread_cpu_cmd, + "clear thread cpu [FILTER]", + "Clear stored data in all pthreads\n" + "Thread information\n" + "Thread CPU usage\n" + "Display filter (rwtexb)\n") + static void show_event_timers_helper(struct vty *vty, struct event_loop *m) { const char *name = m->name ? m->name : "main"; @@ -507,26 +500,17 @@ DEFPY_NOSH (show_event_timers, return CMD_SUCCESS; } -ALIAS(show_event_timers, - show_thread_timers_cmd, - "show thread timers", - SHOW_STR - "Thread information\n" - "Show all timers and how long they have in the system\n") - void event_cmd_init(void) { - install_element(VIEW_NODE, &show_thread_cpu_cmd); install_element(VIEW_NODE, &show_event_cpu_cmd); - install_element(VIEW_NODE, &show_thread_poll_cmd); install_element(VIEW_NODE, &show_event_poll_cmd); install_element(ENABLE_NODE, &clear_thread_cpu_cmd); + install_element(ENABLE_NODE, &clear_event_cpu_cmd); install_element(CONFIG_NODE, &service_cputime_stats_cmd); install_element(CONFIG_NODE, &service_cputime_warning_cmd); install_element(CONFIG_NODE, &service_walltime_warning_cmd); - install_element(VIEW_NODE, &show_thread_timers_cmd); install_element(VIEW_NODE, &show_event_timers_cmd); } /* CLI end ------------------------------------------------------------------ */ @@ -571,8 +555,9 @@ struct event_loop *event_master_create(const char *name) } if (rv->fd_limit > STUPIDLY_LARGE_FD_SIZE) { - zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds also limiting size to %u", - rv->fd_limit, STUPIDLY_LARGE_FD_SIZE); + if (frr_is_daemon()) + zlog_warn("FD Limit set: %u is stupidly large. Is this what you intended? Consider using --limit-fds also limiting size to %u", + rv->fd_limit, STUPIDLY_LARGE_FD_SIZE); rv->fd_limit = STUPIDLY_LARGE_FD_SIZE; } diff --git a/lib/flex_algo.c b/lib/flex_algo.c index f48117ff1b..ab0eef67cb 100644 --- a/lib/flex_algo.c +++ b/lib/flex_algo.c @@ -20,9 +20,6 @@ DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO_DATABASE, "Flex-Algo database"); DEFINE_MTYPE_STATIC(LIB, FLEX_ALGO, "Flex-Algo algorithm information"); -static void _flex_algo_delete(struct flex_algos *flex_algos, - struct flex_algo *fa); - struct flex_algos *flex_algos_alloc(flex_algo_allocator_t allocator, flex_algo_releaser_t releaser) { @@ -42,7 +39,7 @@ void flex_algos_free(struct flex_algos *flex_algos) struct flex_algo *fa; for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa)) - _flex_algo_delete(flex_algos, fa); + flex_algo_free(flex_algos, fa); list_delete(&flex_algos->flex_algos); XFREE(MTYPE_FLEX_ALGO_DATABASE, flex_algos); } @@ -63,8 +60,7 @@ struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos, return fa; } -static void _flex_algo_delete(struct flex_algos *flex_algos, - struct flex_algo *fa) +void flex_algo_free(struct flex_algos *flex_algos, struct flex_algo *fa) { if (flex_algos->releaser) flex_algos->releaser(fa->data); @@ -75,19 +71,6 @@ static void _flex_algo_delete(struct flex_algos *flex_algos, XFREE(MTYPE_FLEX_ALGO, fa); } - -void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm) -{ - struct listnode *node, *nnode; - struct flex_algo *fa; - - for (ALL_LIST_ELEMENTS(flex_algos->flex_algos, node, nnode, fa)) { - if (fa->algorithm != algorithm) - continue; - _flex_algo_delete(flex_algos, fa); - } -} - /** * @brief Look up the local flex-algo object by its algorithm number. * @param algorithm flex-algo algorithm number diff --git a/lib/flex_algo.h b/lib/flex_algo.h index e617e7cae8..54b37783e6 100644 --- a/lib/flex_algo.h +++ b/lib/flex_algo.h @@ -115,11 +115,10 @@ struct flex_algos *flex_algos_alloc(flex_algo_allocator_t allocator, void flex_algos_free(struct flex_algos *flex_algos); struct flex_algo *flex_algo_alloc(struct flex_algos *flex_algos, uint8_t algorithm, void *arg); +void flex_algo_free(struct flex_algos *flex_algos, struct flex_algo *fa); struct flex_algo *flex_algo_lookup(struct flex_algos *flex_algos, uint8_t algorithm); -void flex_algos_free(struct flex_algos *flex_algos); bool flex_algo_definition_cmp(struct flex_algo *fa1, struct flex_algo *fa2); -void flex_algo_delete(struct flex_algos *flex_algos, uint8_t algorithm); bool flex_algo_id_valid(uint16_t algorithm); char *flex_algo_metric_type_print(char *type_str, size_t sz, enum flex_algo_metric_type metric_type); diff --git a/lib/frrcu.h b/lib/frrcu.h index 9f07a69b52..81ab5528a9 100644 --- a/lib/frrcu.h +++ b/lib/frrcu.h @@ -156,7 +156,7 @@ extern void rcu_enqueue(struct rcu_head *head, const struct rcu_action *action); #define rcu_call(func, ptr, field) \ do { \ typeof(ptr) _ptr = (ptr); \ - void (*fptype)(typeof(ptr)); \ + void (*_fptype)(typeof(ptr)); \ struct rcu_head *_rcu_head = &_ptr->field; \ static const struct rcu_action _rcu_action = { \ .type = RCUA_CALL, \ diff --git a/lib/hash.h b/lib/hash.h index 2d00a334be..efa7011bc2 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -13,6 +13,18 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new hash structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. + */ + /* Default hash table size. */ #define HASH_INITIAL_SIZE 256 /* Expansion threshold */ diff --git a/lib/libfrr.c b/lib/libfrr.c index cc60cfb829..07cd4a5306 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -102,23 +102,25 @@ static void opt_extend(const struct optspec *os) #define OPTION_SCRIPTDIR 1009 static const struct option lo_always[] = { - {"help", no_argument, NULL, 'h'}, - {"version", no_argument, NULL, 'v'}, - {"daemon", no_argument, NULL, 'd'}, - {"module", no_argument, NULL, 'M'}, - {"profile", required_argument, NULL, 'F'}, - {"pathspace", required_argument, NULL, 'N'}, - {"vrfdefaultname", required_argument, NULL, 'o'}, - {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, - {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, - {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR}, - {"log", required_argument, NULL, OPTION_LOG}, - {"log-level", required_argument, NULL, OPTION_LOGLEVEL}, - {"command-log-always", no_argument, NULL, OPTION_LOGGING}, - {"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS}, - {NULL}}; + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'v' }, + { "daemon", no_argument, NULL, 'd' }, + { "module", no_argument, NULL, 'M' }, + { "profile", required_argument, NULL, 'F' }, + { "pathspace", required_argument, NULL, 'N' }, + { "vrfdefaultname", required_argument, NULL, 'o' }, + { "graceful_restart", optional_argument, NULL, 'K' }, + { "vty_socket", required_argument, NULL, OPTION_VTYSOCK }, + { "moduledir", required_argument, NULL, OPTION_MODULEDIR }, + { "scriptdir", required_argument, NULL, OPTION_SCRIPTDIR }, + { "log", required_argument, NULL, OPTION_LOG }, + { "log-level", required_argument, NULL, OPTION_LOGLEVEL }, + { "command-log-always", no_argument, NULL, OPTION_LOGGING }, + { "limit-fds", required_argument, NULL, OPTION_LIMIT_FDS }, + { NULL } +}; static const struct optspec os_always = { - "hvdM:F:N:o:", + "hvdM:F:N:o:K::", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" @@ -126,13 +128,15 @@ static const struct optspec os_always = { " -F, --profile Use specified configuration profile\n" " -N, --pathspace Insert prefix into config & socket paths\n" " -o, --vrfdefaultname Set default VRF name.\n" + " -K, --graceful_restart FRR starting in Graceful Restart mode, with optional route-cleanup timer\n" " --vty_socket Override vty socket path\n" " --moduledir Override modules directory\n" " --scriptdir Override scripts directory\n" " --log Set Logging to stdout, syslog, or file:\n" " --log-level Set Logging Level to use, debug, info, warn, etc\n" " --limit-fds Limit number of fds supported\n", - lo_always}; + lo_always +}; static bool logging_to_stdout = false; /* set when --log stdout specified */ @@ -358,6 +362,8 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) strlcpy(frr_protonameinst, di->logname, sizeof(frr_protonameinst)); di->cli_mode = FRR_CLI_CLASSIC; + di->graceful_restart = false; + di->gr_cleanup_time = 0; /* we may be starting with extra FDs open for whatever purpose, * e.g. logging, some module, etc. Recording them here allows later @@ -520,6 +526,11 @@ static int frr_opt(int opt) di->db_file = optarg; break; #endif + case 'K': + di->graceful_restart = true; + if (optarg) + di->gr_cleanup_time = atoi(optarg); + break; case 'C': if (di->flags & FRR_NO_SPLIT_CONFIG) return 1; @@ -1256,6 +1267,8 @@ void frr_fini(void) /* frrmod_init -> nothing needed / hooks */ rcu_shutdown(); + frrmod_terminate(); + /* also log memstats to stderr when stderr goes to a file*/ if (debug_memstats_at_exit || !isatty(STDERR_FILENO)) have_leftovers = log_memstats(stderr, di->name); @@ -1463,3 +1476,11 @@ const char *frr_vers2str(uint32_t version, char *buf, int buflen) return buf; } + +bool frr_is_daemon(void) +{ + if (di) + return true; + + return false; +} diff --git a/lib/libfrr.h b/lib/libfrr.h index d52ee9aefe..7ed7be4d98 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -118,6 +118,8 @@ struct frr_daemon_info { bool dryrun; bool daemon_mode; bool terminal; + bool graceful_restart; + int gr_cleanup_time; enum frr_cli_mode cli_mode; struct event *read_in; @@ -188,7 +190,7 @@ extern const char *frr_get_progname(void); extern enum frr_cli_mode frr_get_cli_mode(void); extern uint32_t frr_get_fd_limit(void); extern bool frr_is_startup_fd(int fd); - +extern bool frr_is_daemon(void); /* call order of these hooks is as ordered here */ DECLARE_HOOK(frr_early_init, (struct event_loop * tm), (tm)); DECLARE_HOOK(frr_late_init, (struct event_loop * tm), (tm)); @@ -220,10 +222,39 @@ extern void frr_fini(void); extern char config_default[512]; extern char frr_zclientpath[512]; + +/* refer to lib/config_paths.h (generated during ./configure) for build config + * values of the following: + */ + +/* sysconfdir is generally /etc/frr/, some BSDs may use /usr/local/etc/frr/. + * Will NOT include "pathspace" (namespace) suffix from -N. (libfrr.c handles + * pathspace'ing config files.) Has a slash at the end for "historical" + * reasons. + */ extern const char frr_sysconfdir[]; + +/* runstatedir is *ephemeral* across reboots. It may either be a ramdisk, + * or be wiped during boot. Use only for pid files, sockets, and the like, + * not state. Commonly /run/frr or /var/run/frr. + * Will include "pathspace" (namespace) suffix from -N. + */ extern char frr_runstatedir[256]; + +/* libstatedir is *persistent*. It's the place to put state like sequence + * numbers or databases. Commonly /var/lib/frr. + * Will include "pathspace" (namespace) suffix from -N. + */ extern char frr_libstatedir[256]; + +/* moduledir is something along the lines of /usr/lib/frr/modules or + * /usr/lib/x86_64-linux-gnu/frr/modules. It is not guaranteed to be a + * subdirectory of the directory that the daemon binaries reside in. (e.g. + * the "x86_64-linux-gnu" component will be absent from daemon paths.) + */ extern const char frr_moduledir[]; + +/* scriptdir is for Lua scripts, generally ${frr_sysconfdir}/scripts */ extern const char frr_scriptdir[]; extern char frr_protoname[]; diff --git a/lib/libospf.h b/lib/libospf.h index 0ac490a00e..8a208beb3c 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -58,8 +58,10 @@ extern "C" { #define OSPF_HELLO_DELAY_DEFAULT 10 #define OSPF_ROUTER_PRIORITY_DEFAULT 1 #define OSPF_RETRANSMIT_INTERVAL_DEFAULT 5 +#define OSPF_RETRANSMIT_WINDOW_DEFAULT 50 /* milliseconds */ #define OSPF_TRANSMIT_DELAY_DEFAULT 1 #define OSPF_DEFAULT_BANDWIDTH 10000 /* Mbps */ +#define OSPF_ACK_DELAY_DEFAULT 1 #define OSPF_DEFAULT_REF_BANDWIDTH 100000 /* Kbps */ diff --git a/lib/link_state.c b/lib/link_state.c index c758b7f575..3d96c75f6d 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -414,6 +414,13 @@ int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2) || (p1->sr.sid_flag != p2->sr.sid_flag)) return 0; } + if (CHECK_FLAG(p1->flags, LS_PREF_SRV6)) { + if (memcmp(&p1->srv6.sid, &p2->srv6.sid, + sizeof(struct in6_addr)) || + (p1->srv6.flags != p2->srv6.flags) || + (p1->srv6.behavior != p2->srv6.behavior)) + return 0; + } /* OK, p1 & p2 are equal */ return 1; @@ -1388,6 +1395,11 @@ static struct ls_prefix *ls_parse_prefix(struct stream *s) STREAM_GETC(s, ls_pref->sr.sid_flag); STREAM_GETC(s, ls_pref->sr.algo); } + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + STREAM_GET(&ls_pref->srv6.sid, s, sizeof(struct in6_addr)); + STREAM_GETW(s, ls_pref->srv6.behavior); + STREAM_GETC(s, ls_pref->srv6.flags); + } return ls_pref; @@ -1632,6 +1644,11 @@ static int ls_format_prefix(struct stream *s, struct ls_prefix *ls_pref) stream_putc(s, ls_pref->sr.sid_flag); stream_putc(s, ls_pref->sr.algo); } + if (CHECK_FLAG(ls_pref->flags, LS_PREF_SRV6)) { + stream_put(s, &ls_pref->srv6.sid, sizeof(struct in6_addr)); + stream_putw(s, ls_pref->srv6.behavior); + stream_putc(s, ls_pref->srv6.flags); + } return 0; } @@ -2748,6 +2765,13 @@ static void ls_show_subnet_vty(struct ls_subnet *subnet, struct vty *vty, sbuf_push(&sbuf, 4, "SID: %d\tAlgorithm: %d\tFlags: 0x%x\n", pref->sr.sid, pref->sr.algo, pref->sr.sid_flag); + if (CHECK_FLAG(pref->flags, LS_PREF_SRV6)) + sbuf_push(&sbuf, 4, + "SIDv6: %pI6\tEndpoint behavior: %s\tFlags: 0x%x\n", + &pref->srv6.sid, + seg6local_action2str(pref->srv6.behavior), + pref->srv6.flags); + end: vty_out(vty, "%s\n", sbuf_buf(&sbuf)); sbuf_free(&sbuf); @@ -2757,7 +2781,7 @@ static void ls_show_subnet_json(struct ls_subnet *subnet, struct json_object *json) { struct ls_prefix *pref; - json_object *jsr; + json_object *jsr, *jsrv6; char buf[INET6_BUFSIZ]; pref = subnet->ls_pref; @@ -2787,6 +2811,16 @@ static void ls_show_subnet_json(struct ls_subnet *subnet, snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->sr.sid_flag); json_object_string_add(jsr, "flags", buf); } + if (CHECK_FLAG(pref->flags, LS_PREF_SRV6)) { + jsrv6 = json_object_new_object(); + json_object_object_add(json, "segment-routing-ipv6", jsrv6); + snprintfrr(buf, INET6_BUFSIZ, "%pI6", &pref->srv6.sid); + json_object_string_add(jsrv6, "sid", buf); + json_object_string_add(jsrv6, "behavior", + seg6local_action2str(pref->srv6.behavior)); + snprintfrr(buf, INET6_BUFSIZ, "0x%x", pref->srv6.flags); + json_object_string_add(jsrv6, "flags", buf); + } } void ls_show_subnet(struct ls_subnet *subnet, struct vty *vty, diff --git a/lib/link_state.h b/lib/link_state.h index d819c20db7..c54e2ec6d9 100644 --- a/lib/link_state.h +++ b/lib/link_state.h @@ -243,6 +243,7 @@ struct ls_attributes { #define LS_PREF_EXTENDED_TAG 0x04 #define LS_PREF_METRIC 0x08 #define LS_PREF_SR 0x10 +#define LS_PREF_SRV6 0x20 /* Link State Prefix */ struct ls_prefix { @@ -258,6 +259,11 @@ struct ls_prefix { uint8_t sid_flag; /* Segment Routing Flags */ uint8_t algo; /* Algorithm for Segment Routing */ } sr; + struct ls_srv6_sid { + struct in6_addr sid; /* Segment Routing ID */ + uint16_t behavior; /* Endpoint behavior bound to the SID */ + uint8_t flags; /* Flags */ + } srv6; }; /** diff --git a/lib/linklist.h b/lib/linklist.h index fd953d0769..f922891df9 100644 --- a/lib/linklist.h +++ b/lib/linklist.h @@ -10,6 +10,18 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new list structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. + */ + /* listnodes must always contain data to be valid. Adding an empty node * to a list is invalid */ diff --git a/lib/log.c b/lib/log.c index 969ca79256..880180ae5a 100644 --- a/lib/log.c +++ b/lib/log.c @@ -436,6 +436,9 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_SRV6_LOCATOR_DELETE), DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK), DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_LOCATOR), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_GET_SRV6_SID), + DESC_ENTRY(ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID), DESC_ENTRY(ZEBRA_ERROR), DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES), DESC_ENTRY(ZEBRA_OPAQUE_MESSAGE), @@ -461,7 +464,8 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_TC_CLASS_DELETE), DESC_ENTRY(ZEBRA_TC_FILTER_ADD), DESC_ENTRY(ZEBRA_TC_FILTER_DELETE), - DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY) + DESC_ENTRY(ZEBRA_OPAQUE_NOTIFY), + DESC_ENTRY(ZEBRA_SRV6_SID_NOTIFY) }; #undef DESC_ENTRY diff --git a/lib/mgmt_msg_native.c b/lib/mgmt_msg_native.c index 39ce9abae6..b85c7d1b61 100644 --- a/lib/mgmt_msg_native.c +++ b/lib/mgmt_msg_native.c @@ -6,6 +6,7 @@ * */ #include +#include "darr.h" #include "mgmt_msg_native.h" DEFINE_MGROUP(MSG_NATIVE, "Native message allocations"); @@ -18,6 +19,33 @@ DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT, "native edit msg"); DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_EDIT_REPLY, "native edit reply msg"); DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC, "native RPC msg"); DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_RPC_REPLY, "native RPC reply msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REQ, "native session-req msg"); +DEFINE_MTYPE(MSG_NATIVE, MSG_NATIVE_SESSION_REPLY, "native session-reply msg"); + + +size_t mgmt_msg_min_sizes[] = { + [MGMT_MSG_CODE_ERROR] = sizeof(struct mgmt_msg_error), + [MGMT_MSG_CODE_GET_TREE] = sizeof(struct mgmt_msg_get_tree), + [MGMT_MSG_CODE_TREE_DATA] = sizeof(struct mgmt_msg_tree_data), + [MGMT_MSG_CODE_GET_DATA] = sizeof(struct mgmt_msg_get_data), + [MGMT_MSG_CODE_NOTIFY] = sizeof(struct mgmt_msg_notify_data), + [MGMT_MSG_CODE_EDIT] = sizeof(struct mgmt_msg_edit), + [MGMT_MSG_CODE_EDIT_REPLY] = sizeof(struct mgmt_msg_edit_reply), + [MGMT_MSG_CODE_RPC] = sizeof(struct mgmt_msg_rpc), + [MGMT_MSG_CODE_RPC_REPLY] = sizeof(struct mgmt_msg_rpc_reply), + [MGMT_MSG_CODE_NOTIFY_SELECT] = sizeof(struct mgmt_msg_notify_select), + [MGMT_MSG_CODE_SESSION_REQ] = sizeof(struct mgmt_msg_session_req), + [MGMT_MSG_CODE_SESSION_REPLY] = sizeof(struct mgmt_msg_session_reply), +}; +size_t nmgmt_msg_min_sizes = sizeof(mgmt_msg_min_sizes) / + sizeof(*mgmt_msg_min_sizes); + +size_t mgmt_msg_get_min_size(uint code) +{ + if (code >= nmgmt_msg_min_sizes) + return 0; + return mgmt_msg_min_sizes[code]; +} int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id, uint64_t req_id, bool short_circuit_ok, @@ -50,3 +78,20 @@ int vmgmt_msg_native_send_error(struct msg_conn *conn, uint64_t sess_or_txn_id, mgmt_msg_native_free_msg(msg); return ret; } + +const char **_mgmt_msg_native_strings_decode(const void *_sdata, int sdlen) +{ + const char *sdata = _sdata; + const char **strings = NULL; + int len; + + if (sdata[sdlen - 1] != 0) + return NULL; + + for (; sdlen; sdata += len, sdlen -= len) { + *darr_append(strings) = darr_strdup(sdata); + len = 1 + darr_strlen(strings[darr_lasti(strings)]); + } + + return strings; +} diff --git a/lib/mgmt_msg_native.h b/lib/mgmt_msg_native.h index 21f702cc61..76a52658cd 100644 --- a/lib/mgmt_msg_native.h +++ b/lib/mgmt_msg_native.h @@ -163,6 +163,8 @@ DECLARE_MTYPE(MSG_NATIVE_EDIT); DECLARE_MTYPE(MSG_NATIVE_EDIT_REPLY); DECLARE_MTYPE(MSG_NATIVE_RPC); DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY); +DECLARE_MTYPE(MSG_NATIVE_SESSION_REQ); +DECLARE_MTYPE(MSG_NATIVE_SESSION_REPLY); /* * Native message codes @@ -176,6 +178,9 @@ DECLARE_MTYPE(MSG_NATIVE_RPC_REPLY); #define MGMT_MSG_CODE_EDIT_REPLY 6 /* Public API */ #define MGMT_MSG_CODE_RPC 7 /* Public API */ #define MGMT_MSG_CODE_RPC_REPLY 8 /* Public API */ +#define MGMT_MSG_CODE_NOTIFY_SELECT 9 /* Public API */ +#define MGMT_MSG_CODE_SESSION_REQ 10 /* Public API */ +#define MGMT_MSG_CODE_SESSION_REPLY 11 /* Public API */ /* * Datastores @@ -426,12 +431,72 @@ _Static_assert(sizeof(struct mgmt_msg_rpc_reply) == offsetof(struct mgmt_msg_rpc_reply, data), "Size mismatch"); +/** + * struct mgmt_msg_notify_select - Add notification selectors for FE client. + * + * Add xpath prefix notification selectors to limit the notifications sent + * to the front-end client. + * + * @selectors: the xpath prefixes to selectors notifications through. + * @replace: if true replace existing selectors with `selectors`. + */ +struct mgmt_msg_notify_select { + struct mgmt_msg_header; + uint8_t replace; + uint8_t resv2[7]; + + alignas(8) char selectors[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_notify_select) == + offsetof(struct mgmt_msg_notify_select, selectors), + "Size mismatch"); + +/** + * struct mgmt_msg_session_req - Create or delete a front-end session. + * + * @refer_id: Zero for create, otherwise the session-id to delete. + * @req_id: For create will use as client-id. + * @client_name: For first session request the client name, otherwise empty. + */ +struct mgmt_msg_session_req { + struct mgmt_msg_header; + uint8_t resv2[8]; /* bug in compiler produces error w/o this */ + + alignas(8) char client_name[]; +}; + +_Static_assert(sizeof(struct mgmt_msg_session_req) == + offsetof(struct mgmt_msg_session_req, client_name), + "Size mismatch"); + +/** + * struct mgmt_msg_session_reply - Reply to session request message. + * + * @created: true if this is a reply to a create request, otherwise 0. + * @refer_id: The session-id for the action (create or delete) just taken. + */ +struct mgmt_msg_session_reply { + struct mgmt_msg_header; + uint8_t created; + uint8_t resv2[7]; +}; + /* * Validate that the message ends in a NUL terminating byte */ #define MGMT_MSG_VALIDATE_NUL_TERM(msgp, len) \ ((len) >= sizeof(*msgp) + 1 && ((char *)msgp)[(len)-1] == 0) +/** + * mgmt_msg_get_min_size() - Get minimum message size given the type + * @code: The type of the message (MGMT_MSG_CODE_*) + * + * Return: + * The minimum size of a message of the given type or 0 if the message + * code is unknown. + */ +size_t mgmt_msg_get_min_size(uint code); /** * Send a native message error to the other end of the connection. @@ -524,6 +589,25 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn, p; \ }) +/** + * mgmt_msg_native_add_str() - Append [another] string to the msg. + * @msg: (IN/OUT) Pointer to the native message, variable may be updated. + * @s: string to append. + * + * Append string @s to the native message @msg. @msg is assumed to have a + * sequence of NUL-terminated strings at the end of it. This function appends + * the string @s and it's NUL terminating octet to the message. + * + * NOTE: Be aware @msg pointer may change as a result of reallocating the + * message to fit the new data. Any other pointers into the old message should + * be discarded. + */ +#define mgmt_msg_native_add_str(msg, s) \ + do { \ + int __len = strlen(s) + 1; \ + mgmt_msg_native_append(msg, s, __len); \ + } while (0) + /** * mgmt_msg_native_send_msg(msg, short_circuit_ok) - Send a native msg. * @conn: the mgmt_msg connection. @@ -689,6 +773,27 @@ extern int vmgmt_msg_native_send_error(struct msg_conn *conn, #define mgmt_msg_native_data_len_decode(msg, msglen) \ ((msglen) - sizeof(*msg) - msg->vsplit) +/** + * mgmt_msg_native_strings_decode() - Get dynamic array of str ptrs from the msg. + * @msg: Pointer to the native message. + * @msglen: Length of the message. + * @sdata: pointer to the variable length string data at end of @msg. + * + * Given a pointer to a sequence of NUL-terminated strings allocate + * and return a dynamic array of dynamic array strings. This function + * can be used to decode a message that was built using + * mgmt_msg_native_add_str(). + * + * Return: a dynamic array (darr) of string pointers, or NULL if the message + * is corrupt. + */ +#define mgmt_msg_native_strings_decode(msg, msg_len, sdata) \ + _mgmt_msg_native_strings_decode(sdata, \ + (msg_len) - ((sdata) - (char *)(msg))) + +extern const char **_mgmt_msg_native_strings_decode(const void *sdata, + int sdlen); + #ifdef __cplusplus } #endif diff --git a/lib/module.c b/lib/module.c index af7d20c3da..9d178bb0e4 100644 --- a/lib/module.c +++ b/lib/module.c @@ -202,3 +202,15 @@ void frrmod_unload(struct frrmod_runtime *module) { } #endif + +void frrmod_terminate(void) +{ + struct frrmod_runtime *rtinfo = frrmod_list; + + while (rtinfo) { + XFREE(MTYPE_MODULE_LOADNAME, rtinfo->load_name); + XFREE(MTYPE_MODULE_LOADARGS, rtinfo->load_args); + + rtinfo = rtinfo->next; + } +} diff --git a/lib/module.h b/lib/module.h index cd2be474e7..1810b335f6 100644 --- a/lib/module.h +++ b/lib/module.h @@ -79,6 +79,7 @@ extern union _frrmod_runtime_u _frrmod_this_module; extern struct frrmod_runtime *frrmod_list; extern void frrmod_init(struct frrmod_runtime *modinfo); +extern void frrmod_terminate(void); extern struct frrmod_runtime *frrmod_load(const char *spec, const char *dir, void (*pFerrlog)(const void *, const char *), diff --git a/lib/nexthop.c b/lib/nexthop.c index 26c338256f..65c12c1e69 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -1166,6 +1166,7 @@ void nexthop_json_helper(json_object *json_nexthop, json_object *json_labels = NULL; json_object *json_backups = NULL; json_object *json_seg6local = NULL; + json_object *json_seg6local_context = NULL; json_object *json_seg6 = NULL; json_object *json_segs = NULL; int i; @@ -1331,8 +1332,16 @@ void nexthop_json_helper(json_object *json_nexthop, seg6local_action2str( nexthop->nh_srv6 ->seg6local_action)); + json_seg6local_context = json_object_new_object(); json_object_object_add(json_nexthop, "seg6local", json_seg6local); + + seg6local_context2json(&nexthop->nh_srv6->seg6local_ctx, + nexthop->nh_srv6->seg6local_action, + json_seg6local_context); + json_object_object_add(json_nexthop, "seg6localContext", + json_seg6local_context); + if (nexthop->nh_srv6->seg6_segs && nexthop->nh_srv6->seg6_segs->num_segs == 1) { json_seg6 = json_object_new_object(); diff --git a/lib/openbsd-queue.h b/lib/openbsd-queue.h index df3bbd720f..a2df521f58 100644 --- a/lib/openbsd-queue.h +++ b/lib/openbsd-queue.h @@ -16,6 +16,22 @@ extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new queue structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. However, + * among converting datastrucutres, the the BSD ones are the lowest + * priority / should be converted last. They are already typesafe and + * use inline linking nodes, so the only gain is consistency. Please + * convert uses of linklist.h and hash.h first. + */ + /* * This file defines five types of data structures: singly-linked lists, * lists, simple queues, tail queues and XOR simple queues. diff --git a/lib/openbsd-tree.h b/lib/openbsd-tree.h index 4f3985bbca..ecc3a68f15 100644 --- a/lib/openbsd-tree.h +++ b/lib/openbsd-tree.h @@ -10,6 +10,21 @@ #ifdef __cplusplus extern "C" { #endif +/* + * NOTICE: + * + * If you are reading this file in an effort to add a new tree structure + * this is the wrong place to be using it. Please see the typesafe + * data structures, or ask one of the other developers. + * + * If you are reading this file as a way to update an existing usage + * of this data structure, please consider just converting the data + * structure to one of the typesafe data structures instead. However, + * among converting datastrucutres, the the BSD ones are the lowest + * priority / should be converted last. They are already typesafe and + * use inline linking nodes, so the only gain is consistency. Please + * convert uses of linklist.h and hash.h first. + */ /* * This file defines data structures for different types of trees: diff --git a/lib/seqlock.c b/lib/seqlock.c index 62ce316920..e74e6718bf 100644 --- a/lib/seqlock.c +++ b/lib/seqlock.c @@ -26,6 +26,39 @@ * OS specific synchronization wrappers * ****************************************/ +#ifndef __has_feature /* not available on old GCC */ +#define __has_feature(x) 0 +#endif + +#if (defined(__SANITIZE_THREAD__) || __has_feature(thread_sanitizer)) +/* TSAN really does not understand what is going on with the low-level + * futex/umtx calls. This leads to a whole bunch of warnings, a lot of which + * also have _extremely_ misleading text - since TSAN does not understand that + * there is in fact a synchronization primitive involved, it can end up pulling + * in completely unrelated things. + * + * What does work is the "unsupported platform" seqlock implementation based + * on a pthread mutex + condvar, since TSAN of course suppports these. + * + * It may be possible to also fix this with TSAN annotations (__tsan_acquire + * and __tsan_release), but using those (correctly) is not easy either, and + * for now just get things rolling. + */ + +#ifdef HAVE_SYNC_LINUX_FUTEX +#undef HAVE_SYNC_LINUX_FUTEX +#endif + +#ifdef HAVE_SYNC_OPENBSD_FUTEX +#undef HAVE_SYNC_OPENBSD_FUTEX +#endif + +#ifdef HAVE_SYNC_UMTX_OP +#undef HAVE_SYNC_UMTX_OP +#endif + +#endif /* TSAN */ + /* * Linux: sys_futex() */ diff --git a/lib/smux.h b/lib/smux.h index 8ec847afd0..0ed41410f5 100644 --- a/lib/smux.h +++ b/lib/smux.h @@ -101,6 +101,7 @@ extern bool smux_enabled(void); extern void libagentx_init(void); extern void smux_init(struct event_loop *tm); +extern void smux_terminate(void); extern void smux_agentx_enable(void); extern void smux_register_mib(const char *, struct variable *, size_t, int, oid[], size_t); diff --git a/lib/sockopt.h b/lib/sockopt.h index ce7d665fab..e6fb78d5e4 100644 --- a/lib/sockopt.h +++ b/lib/sockopt.h @@ -60,6 +60,16 @@ extern int setsockopt_ipv6_tclass(int, int); (((af) == AF_INET) : SOPT_SIZE_CMSG_IFINDEX_IPV4() \ ? SOPT_SIZE_CMSG_PKTINFO_IPV6()) +/* + * If not defined then define the value for `TCP_MD5SIG_MAXKEYLEN`. This seems + * to be unavailable for NetBSD 8, FreeBSD 11 and FreeBSD 12. + * + * The value below was copied from `linux/tcp.h` from the Linux kernel headers. + */ +#ifndef TCP_MD5SIG_MAXKEYLEN +#define TCP_MD5SIG_MAXKEYLEN 80 +#endif + extern int setsockopt_ipv4_multicast_if(int sock, struct in_addr if_addr, ifindex_t ifindex); extern int setsockopt_ipv4_multicast(int sock, int optname, diff --git a/lib/srv6.c b/lib/srv6.c index a82103e423..e6fc375fbb 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -10,8 +10,11 @@ #include "log.h" DEFINE_QOBJ_TYPE(srv6_locator); +DEFINE_QOBJ_TYPE(srv6_sid_format); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR, "SRV6 locator"); DEFINE_MTYPE_STATIC(LIB, SRV6_LOCATOR_CHUNK, "SRV6 locator chunk"); +DEFINE_MTYPE_STATIC(LIB, SRV6_SID_FORMAT, "SRv6 SID format"); +DEFINE_MTYPE_STATIC(LIB, SRV6_SID_CTX, "SRv6 SID context"); const char *seg6local_action2str(uint32_t action) { @@ -68,6 +71,44 @@ int snprintf_seg6_segs(char *str, return strlen(str); } +void seg6local_context2json(const struct seg6local_context *ctx, + uint32_t action, json_object *json) +{ + switch (action) { + case ZEBRA_SEG6_LOCAL_ACTION_END: + json_object_boolean_add(json, "USP", true); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + json_object_string_addf(json, "nh6", "%pI6", &ctx->nh6); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + json_object_string_addf(json, "nh4", "%pI4", &ctx->nh4); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_T: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT46: + json_object_int_add(json, "table", ctx->table); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: + json_object_boolean_add(json, "none", true); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_B6: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + json_object_string_addf(json, "nh6", "%pI6", &ctx->nh6); + return; + case ZEBRA_SEG6_LOCAL_ACTION_END_BM: + case ZEBRA_SEG6_LOCAL_ACTION_END_S: + case ZEBRA_SEG6_LOCAL_ACTION_END_AS: + case ZEBRA_SEG6_LOCAL_ACTION_END_AM: + case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: + default: + json_object_boolean_add(json, "unknown", true); + return; + } +} + const char *seg6local_context2str(char *str, size_t size, const struct seg6local_context *ctx, uint32_t action) @@ -139,6 +180,21 @@ struct srv6_locator_chunk *srv6_locator_chunk_alloc(void) return chunk; } +void srv6_locator_copy(struct srv6_locator *copy, + const struct srv6_locator *locator) +{ + strlcpy(copy->name, locator->name, sizeof(locator->name)); + copy->prefix = locator->prefix; + copy->block_bits_length = locator->block_bits_length; + copy->node_bits_length = locator->node_bits_length; + copy->function_bits_length = locator->function_bits_length; + copy->argument_bits_length = locator->argument_bits_length; + copy->algonum = locator->algonum; + copy->current = locator->current; + copy->status_up = locator->status_up; + copy->flags = locator->flags; +} + void srv6_locator_free(struct srv6_locator *locator) { if (locator) { @@ -154,6 +210,59 @@ void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk) XFREE(MTYPE_SRV6_LOCATOR_CHUNK, *chunk); } +struct srv6_sid_format *srv6_sid_format_alloc(const char *name) +{ + struct srv6_sid_format *format = NULL; + + format = XCALLOC(MTYPE_SRV6_SID_FORMAT, sizeof(struct srv6_sid_format)); + strlcpy(format->name, name, sizeof(format->name)); + + QOBJ_REG(format, srv6_sid_format); + return format; +} + +void srv6_sid_format_free(struct srv6_sid_format *format) +{ + if (!format) + return; + + QOBJ_UNREG(format); + XFREE(MTYPE_SRV6_SID_FORMAT, format); +} + +/** + * Free an SRv6 SID format. + * + * @param val SRv6 SID format to be freed + */ +void delete_srv6_sid_format(void *val) +{ + srv6_sid_format_free((struct srv6_sid_format *)val); +} + +struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior, + struct in_addr *nh4, + struct in6_addr *nh6, vrf_id_t vrf_id) +{ + struct srv6_sid_ctx *ctx = NULL; + + ctx = XCALLOC(MTYPE_SRV6_SID_CTX, sizeof(struct srv6_sid_ctx)); + ctx->behavior = behavior; + if (nh4) + ctx->nh4 = *nh4; + if (nh6) + ctx->nh6 = *nh6; + if (vrf_id) + ctx->vrf_id = vrf_id; + + return ctx; +} + +void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx) +{ + XFREE(MTYPE_SRV6_SID_CTX, ctx); +} + json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) { json_object *jo_root = NULL; @@ -223,23 +332,47 @@ json_object *srv6_locator_json(const struct srv6_locator *loc) /* set prefix */ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); - /* set block_bits_length */ - json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); - - /* set node_bits_length */ - json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); - - /* set function_bits_length */ - json_object_int_add(jo_root, "functionBitsLength", - loc->function_bits_length); - - /* set argument_bits_length */ - json_object_int_add(jo_root, "argumentBitsLength", - loc->argument_bits_length); - - /* set true if the locator is a Micro-segment (uSID) locator */ - if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) - json_object_string_add(jo_root, "behavior", "usid"); + if (loc->sid_format) { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->sid_format->block_len); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->sid_format->node_len); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->sid_format->function_len); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->sid_format->argument_len); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) + json_object_string_add(jo_root, "behavior", "usid"); + } else { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->block_bits_length); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->node_bits_length); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->function_bits_length); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->argument_bits_length); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + } /* set status_up */ json_object_boolean_add(jo_root, "statusUp", @@ -272,23 +405,47 @@ json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) /* set prefix */ json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); - /* set block_bits_length */ - json_object_int_add(jo_root, "blockBitsLength", loc->block_bits_length); - - /* set node_bits_length */ - json_object_int_add(jo_root, "nodeBitsLength", loc->node_bits_length); - - /* set function_bits_length */ - json_object_int_add(jo_root, "functionBitsLength", - loc->function_bits_length); - - /* set argument_bits_length */ - json_object_int_add(jo_root, "argumentBitsLength", - loc->argument_bits_length); - - /* set true if the locator is a Micro-segment (uSID) locator */ - if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) - json_object_string_add(jo_root, "behavior", "usid"); + if (loc->sid_format) { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->sid_format->block_len); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->sid_format->node_len); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->sid_format->function_len); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->sid_format->argument_len); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (loc->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) + json_object_string_add(jo_root, "behavior", "usid"); + } else { + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + loc->block_bits_length); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", + loc->node_bits_length); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + loc->function_bits_length); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + loc->argument_bits_length); + + /* set true if the locator is a Micro-segment (uSID) locator */ + if (CHECK_FLAG(loc->flags, SRV6_LOCATOR_USID)) + json_object_string_add(jo_root, "behavior", "usid"); + } /* set algonum */ json_object_int_add(jo_root, "algoNum", loc->algonum); diff --git a/lib/srv6.h b/lib/srv6.h index 433c5c14fd..03ada7fcfc 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -20,6 +20,8 @@ #define SRH_BASE_HEADER_LENGTH 8 #define SRH_SEGMENT_LENGTH 16 +#define SRV6_SID_FORMAT_NAME_SIZE 512 + #ifdef __cplusplus extern "C" { #endif @@ -127,6 +129,12 @@ struct srv6_locator { uint8_t flags; #define SRV6_LOCATOR_USID (1 << 0) /* The SRv6 Locator is a uSID Locator */ + /* Pointer to the SID format. */ + struct srv6_sid_format *sid_format; + + /* Pointer to the parent SID block of the locator. */ + void *sid_block; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(srv6_locator); @@ -183,6 +191,72 @@ struct nexthop_srv6 { struct seg6_seg_stack *seg6_segs; }; +/* SID format type */ +enum srv6_sid_format_type { + SRV6_SID_FORMAT_TYPE_UNSPEC = 0, + /* SRv6 SID uncompressed format */ + SRV6_SID_FORMAT_TYPE_UNCOMPRESSED = 1, + /* SRv6 SID compressed uSID format */ + SRV6_SID_FORMAT_TYPE_USID = 2, +}; + +/* SRv6 SID format */ +struct srv6_sid_format { + /* Name of the format */ + char name[SRV6_SID_FORMAT_NAME_SIZE]; + + /* Format type: uncompressed vs compressed */ + enum srv6_sid_format_type type; + + /* + * Lengths of block/node/function/argument parts of the SIDs allocated + * using this format + */ + uint8_t block_len; + uint8_t node_len; + uint8_t function_len; + uint8_t argument_len; + + union { + /* Configuration settings for compressed uSID format type */ + struct { + /* Start of the Local ID Block (LIB) range */ + uint32_t lib_start; + + /* Start/End of the Explicit LIB range */ + uint32_t elib_start; + uint32_t elib_end; + + /* Start/End of the Wide LIB range */ + uint32_t wlib_start; + uint32_t wlib_end; + + /* Start/End of the Explicit Wide LIB range */ + uint32_t ewlib_start; + } usid; + + /* Configuration settings for uncompressed format type */ + struct { + /* Start of the Explicit range */ + uint32_t explicit_start; + } uncompressed; + } config; + + QOBJ_FIELDS; +}; +DECLARE_QOBJ_TYPE(srv6_sid_format); + +/* Context for an SRv6 SID */ +struct srv6_sid_ctx { + /* Behavior associated with the SID */ + enum seg6local_action_t behavior; + + /* Behavior-specific attributes */ + struct in_addr nh4; + struct in6_addr nh6; + vrf_id_t vrf_id; +}; + static inline const char *seg6_mode2str(enum seg6_mode_t mode) { switch (mode) { @@ -245,6 +319,56 @@ seg6local_action2str(uint32_t action); const char *seg6local_context2str(char *str, size_t size, const struct seg6local_context *ctx, uint32_t action); +void seg6local_context2json(const struct seg6local_context *ctx, + uint32_t action, json_object *json); + +static inline const char *srv6_sid_ctx2str(char *str, size_t size, + const struct srv6_sid_ctx *ctx) +{ + int len = 0; + + len += snprintf(str + len, size - len, "%s", + seg6local_action2str(ctx->behavior)); + + switch (ctx->behavior) { + case ZEBRA_SEG6_LOCAL_ACTION_UNSPEC: + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END: + len += snprintf(str + len, size - len, " USP"); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_X: + case ZEBRA_SEG6_LOCAL_ACTION_END_DX6: + len += snprintfrr(str + len, size - len, " nh6 %pI6", &ctx->nh6); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_DX4: + len += snprintfrr(str + len, size - len, " nh4 %pI4", &ctx->nh4); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_T: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT6: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT4: + case ZEBRA_SEG6_LOCAL_ACTION_END_DT46: + len += snprintf(str + len, size - len, " vrf_id %u", + ctx->vrf_id); + break; + + case ZEBRA_SEG6_LOCAL_ACTION_END_DX2: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6: + case ZEBRA_SEG6_LOCAL_ACTION_END_B6_ENCAP: + case ZEBRA_SEG6_LOCAL_ACTION_END_BM: + case ZEBRA_SEG6_LOCAL_ACTION_END_S: + case ZEBRA_SEG6_LOCAL_ACTION_END_AS: + case ZEBRA_SEG6_LOCAL_ACTION_END_AM: + case ZEBRA_SEG6_LOCAL_ACTION_END_BPF: + default: + len += snprintf(str + len, size - len, " unknown(%s)", __func__); + } + + return str; +} int snprintf_seg6_segs(char *str, size_t size, const struct seg6_segs *segs); @@ -254,12 +378,24 @@ extern struct srv6_locator_chunk *srv6_locator_chunk_alloc(void); extern void srv6_locator_free(struct srv6_locator *locator); extern void srv6_locator_chunk_list_free(void *data); extern void srv6_locator_chunk_free(struct srv6_locator_chunk **chunk); +extern void srv6_locator_copy(struct srv6_locator *copy, + const struct srv6_locator *locator); json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk); json_object *srv6_locator_json(const struct srv6_locator *loc); json_object *srv6_locator_detailed_json(const struct srv6_locator *loc); json_object * srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk); +extern struct srv6_sid_format *srv6_sid_format_alloc(const char *name); +extern void srv6_sid_format_free(struct srv6_sid_format *format); +extern void delete_srv6_sid_format(void *format); + +extern struct srv6_sid_ctx *srv6_sid_ctx_alloc(enum seg6local_action_t behavior, + struct in_addr *nh4, + struct in6_addr *nh6, + vrf_id_t vrf_id); +extern void srv6_sid_ctx_free(struct srv6_sid_ctx *ctx); + #ifdef __cplusplus } #endif diff --git a/lib/subdir.am b/lib/subdir.am index 3264f31af7..4bcce9a2b0 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -504,20 +504,41 @@ SUFFIXES += .xref %.xref: % $(CLIPPY) $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py $(WERROR) $(XRELFO_FLAGS) -o $@ $< +# these run up to a total of 350k lines at the time of writing. That's a lot +# for the compiler to chug down - enough to warrant splitting it up so it can +# benefit from parallel build. +vtysh_cmd_split = \ + vtysh/vtysh_cmd.1.c \ + vtysh/vtysh_cmd.2.c \ + vtysh/vtysh_cmd.3.c \ + vtysh/vtysh_cmd.4.c \ + vtysh/vtysh_cmd.5.c \ + vtysh/vtysh_cmd.6.c \ + vtysh/vtysh_cmd.7.c \ + vtysh/vtysh_cmd.8.c \ + # end + # dependencies added in python/makefile.py frr.xref: - $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ -c vtysh/vtysh_cmd.c $^ + $(AM_V_XRELFO) $(CLIPPY) $(top_srcdir)/python/xrelfo.py -o $@ $^ \ + -c vtysh/vtysh_cmd.c $(vtysh_cmd_split) all-am: frr.xref clean-xref: -rm -rf $(xrefs) frr.xref clean-local: clean-xref -CLEANFILES += vtysh/vtysh_cmd.c vtysh/vtysh_cmd.c: frr.xref @test -f $@ || rm -f frr.xref || true @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) frr.xref +vtysh/vtysh_cmd.%.c: vtysh/vtysh_cmd.c + @test -f $@ || rm -f vtysh/vtysh_cmd.c || true + @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) vtysh/vtysh_cmd.c + +nodist_vtysh_vtysh_SOURCES = vtysh/vtysh_cmd.c $(vtysh_cmd_split) +CLEANFILES += vtysh/vtysh_cmd.c $(vtysh_cmd_split) + ## automake's "ylwrap" is a great piece of GNU software... not. .l.c: $(AM_V_LEX)$(am__skiplex) $(LEXCOMPILE) $< diff --git a/lib/termtable.c b/lib/termtable.c index 9b36d5ebfa..88cc25bf68 100644 --- a/lib/termtable.c +++ b/lib/termtable.c @@ -496,7 +496,9 @@ char *ttable_dump(struct ttable *tt, const char *newline) * l int64 * s string (default) */ -json_object *ttable_json(struct ttable *tt, const char *const formats) +static json_object *ttable_json_internal(struct ttable *tt, + const char *const formats, + const char *row_text[]) { struct ttable_cell *row; /* iteration pointers */ json_object *json = NULL; @@ -522,9 +524,55 @@ json_object *ttable_json(struct ttable *tt, const char *const formats) default: val = json_object_new_string(row[j].text); } - json_object_object_add(jobj, tt->table[0][j].text, val); + if (row_text) + json_object_object_add(jobj, row_text[j], val); + else + json_object_object_add(jobj, + tt->table[0][j].text, + val); } } return json; } + +json_object *ttable_json(struct ttable *tt, const char *const formats) +{ + return ttable_json_internal(tt, formats, NULL); +} + +json_object *ttable_json_with_json_text(struct ttable *tt, + const char *const formats, + const char *json_override_text) +{ + char **row_name; /* iteration pointers */ + char *res, *section, *orig; + int col = 0; + int ncols = 0, j; + json_object *json = NULL; + + if (json_override_text) { + /* count how many columns we have */ + for (j = 0; json_override_text[j]; j++) + ncols += !!(json_override_text[j] == '|'); + ncols++; + } + if (json_override_text == NULL || ncols != tt->ncols) + return ttable_json_internal(tt, formats, NULL); + + /* CALLOC a block of cells */ + row_name = XCALLOC(MTYPE_TTABLE, ncols * sizeof(char *)); + orig = XSTRDUP(MTYPE_TTABLE, json_override_text); + res = orig; + while (res && col < ncols) { + section = strsep(&res, "|"); + row_name[col] = XSTRDUP(MTYPE_TTABLE, section); + col++; + } + json = ttable_json_internal(tt, formats, (const char **)row_name); + for (j = 0; j < col; j++) + XFREE(MTYPE_TTABLE, row_name[j]); + XFREE(MTYPE_TTABLE, row_name); + XFREE(MTYPE_TTABLE, orig); + return json; +} diff --git a/lib/termtable.h b/lib/termtable.h index 7258682bd8..0782c82abd 100644 --- a/lib/termtable.h +++ b/lib/termtable.h @@ -289,6 +289,21 @@ char *ttable_dump(struct ttable *tt, const char *newline); */ json_object *ttable_json(struct ttable *tt, const char *const formats); +/** + * Convert a table to a JSON array of objects. + * + * Caller must free the returned json_object structure. + * + * @param tt the table to convert + * @param formats an array of characters indicating what JSON type should be + * used. + * @param formats an optinal string of row headers that overrids the first row of the table. + * This is useful to get naming convention that align with caml Format. + */ +json_object *ttable_json_with_json_text(struct ttable *tt, + const char *const formats, + const char *json_override_text); + #ifdef __cplusplus } #endif diff --git a/lib/vector.c b/lib/vector.c index 60d383101a..0636154960 100644 --- a/lib/vector.c +++ b/lib/vector.c @@ -24,45 +24,44 @@ vector vector_init(unsigned int size) v->alloced = size; v->active = 0; v->count = 0; + v->dynamic = true; v->index = XCALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * size); return v; } void vector_free(vector v) { - XFREE(MTYPE_VECTOR_INDEX, v->index); - XFREE(MTYPE_VECTOR, v); + if (v->alloced) + XFREE(MTYPE_VECTOR_INDEX, v->index); + if (v->dynamic) + XFREE(MTYPE_VECTOR, v); } -vector vector_copy(vector v) -{ - unsigned int size; - vector new = XCALLOC(MTYPE_VECTOR, sizeof(struct _vector)); - - new->active = v->active; - new->alloced = v->alloced; - new->count = v->count; - - size = sizeof(void *) * (v->alloced); - new->index = XCALLOC(MTYPE_VECTOR_INDEX, size); - memcpy(new->index, v->index, size); - - return new; -} - -/* Check assigned index, and if it runs short double index pointer */ +/* resize vector to a minimum of num + * may resize larger to avoid excessive realloc overhead + */ void vector_ensure(vector v, unsigned int num) { + unsigned int newsz; + if (v->alloced > num) return; - v->index = XREALLOC(MTYPE_VECTOR_INDEX, v->index, - sizeof(void *) * (v->alloced * 2)); - memset(&v->index[v->alloced], 0, sizeof(void *) * v->alloced); - v->alloced *= 2; + newsz = MAX(v->active * 2, num + 1); + + if (!v->alloced && v->index) { + /* currently using global variable, not malloc'd memory */ + void **orig_index = v->index; - if (v->alloced <= num) - vector_ensure(v, num); + v->index = XMALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * newsz); + memcpy(v->index, orig_index, v->active * sizeof(void *)); + v->alloced = v->active; + } else + v->index = XREALLOC(MTYPE_VECTOR_INDEX, v->index, + sizeof(void *) * newsz); + + memset(&v->index[v->alloced], 0, sizeof(void *) * (newsz - v->alloced)); + v->alloced = newsz; } /* This function only returns next empty slot index. It dose not mean @@ -140,7 +139,7 @@ void *vector_lookup_ensure(vector v, unsigned int i) /* Unset value at specified index slot. */ void vector_unset(vector v, unsigned int i) { - if (i >= v->alloced) + if (i >= v->active) return; if (v->index[i]) diff --git a/lib/vector.h b/lib/vector.h index fcbc13257a..ae05d4d3e0 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -15,9 +15,26 @@ extern "C" { /* struct for vector */ struct _vector { - unsigned int active; /* number of active slots */ - unsigned int alloced; /* number of allocated slot */ + /* active: index of last non-NULL item (+1) + * count: number of non-NULL items (+1) + * + * the two will be different if a slot is set to NULL (without pulling + * up later items in the array). Whether this happens depends on + * which vector functions are used. If no empty slots are used, the + * two fields will be identical. + * + * alloced: size of array pointed to by index. If this is 0, index + * points at a global variable rather than a malloc'd bit of memory. + * The vector code will convert to malloc'd memory if necessary to + * perform updates. + */ + unsigned int active; + unsigned int alloced; unsigned int count; + + /* whether struct _vector itself is dynamically allocated */ + bool dynamic; + void **index; /* index to data */ }; typedef struct _vector *vector; @@ -51,7 +68,6 @@ static inline unsigned int vector_count(vector v) } extern void vector_free(vector v); -extern vector vector_copy(vector v); extern void *vector_lookup(vector, unsigned int); extern void *vector_lookup_ensure(vector, unsigned int); diff --git a/lib/yang.c b/lib/yang.c index 44459df4a5..6a8e5223a0 100644 --- a/lib/yang.c +++ b/lib/yang.c @@ -25,6 +25,11 @@ DEFINE_MTYPE_STATIC(LIB, YANG_DATA, "YANG data structure"); #define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \ set) \ lyd_find_xpath3(ctx_node, tree, xpath, vars, set) + +#ifndef LYD_NEW_VAL_OUTPUT +#define LYD_NEW_VAL_OUTPUT LYD_NEW_PATH_OUTPUT +#endif + #else #define yang_lyd_find_xpath3(ctx_node, tree, xpath, format, prefix_data, vars, \ set) \ @@ -671,7 +676,7 @@ void yang_dnode_rpc_output_add(struct lyd_node *output, const char *xpath, LY_ERR err; err = lyd_new_path(output, ly_native_ctx, xpath, value, - LYD_NEW_PATH_OUTPUT | LYD_NEW_PATH_UPDATE, NULL); + LYD_NEW_VAL_OUTPUT | LYD_NEW_PATH_UPDATE, NULL); assert(err == LY_SUCCESS); } diff --git a/lib/zclient.c b/lib/zclient.c index 1aab7b48ba..0e832f0d8f 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -1125,6 +1125,10 @@ int zapi_srv6_locator_encode(struct stream *s, const struct srv6_locator *l) stream_put(s, l->name, strlen(l->name)); stream_putw(s, l->prefix.prefixlen); stream_put(s, &l->prefix.prefix, sizeof(l->prefix.prefix)); + stream_putc(s, l->block_bits_length); + stream_putc(s, l->node_bits_length); + stream_putc(s, l->function_bits_length); + stream_putc(s, l->argument_bits_length); stream_putc(s, l->flags); return 0; } @@ -1141,6 +1145,10 @@ int zapi_srv6_locator_decode(struct stream *s, struct srv6_locator *l) STREAM_GETW(s, l->prefix.prefixlen); STREAM_GET(&l->prefix.prefix, s, sizeof(l->prefix.prefix)); l->prefix.family = AF_INET6; + STREAM_GETC(s, l->block_bits_length); + STREAM_GETC(s, l->node_bits_length); + STREAM_GETC(s, l->function_bits_length); + STREAM_GETC(s, l->argument_bits_length); STREAM_GETC(s, l->flags); return 0; @@ -2125,6 +2133,46 @@ bool zapi_iptable_notify_decode(struct stream *s, return false; } +bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t *func, + uint32_t *wide_func, + enum zapi_srv6_sid_notify *note, + char **p_locator_name) +{ + uint32_t f, wf; + uint16_t len; + static char locator_name[SRV6_LOCNAME_SIZE] = {}; + + STREAM_GET(note, s, sizeof(*note)); + STREAM_GET(ctx, s, sizeof(struct srv6_sid_ctx)); + STREAM_GET(sid_value, s, sizeof(struct in6_addr)); + STREAM_GETL(s, f); + STREAM_GETL(s, wf); + + if (func) + *func = f; + if (wide_func) + *wide_func = wf; + + STREAM_GETW(s, len); + if (len > SRV6_LOCNAME_SIZE) { + *p_locator_name = NULL; + return false; + } + if (p_locator_name) { + if (len == 0) + *p_locator_name = NULL; + else { + STREAM_GET(locator_name, s, len); + *p_locator_name = locator_name; + } + } + return true; + +stream_failure: + return false; +} + struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) { struct nexthop *n = nexthop_new(); @@ -2134,6 +2182,7 @@ struct nexthop *nexthop_from_zapi_nexthop(const struct zapi_nexthop *znh) n->ifindex = znh->ifindex; n->gate = znh->gate; n->srte_color = znh->srte_color; + n->weight = znh->weight; /* * This function currently handles labels @@ -3268,10 +3317,154 @@ int srv6_manager_release_locator_chunk(struct zclient *zclient, return zclient_send_message(zclient); } +/** + * Function to request a SRv6 locator in an asynchronous way + * + * @param zclient The zclient used to connect to SRv6 Manager (zebra) + * @param locator_name Name of SRv6 locator + * @return 0 on success, -1 otherwise + */ +int srv6_manager_get_locator(struct zclient *zclient, const char *locator_name) +{ + struct stream *s; + size_t len; + + if (!locator_name) + return -1; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return -1; + } + + if (zclient_debug) + zlog_debug("Getting SRv6 Locator %s", locator_name); + + len = strlen(locator_name); + + /* Send request */ + s = zclient->obuf; + stream_reset(s); + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_LOCATOR, VRF_DEFAULT); + + /* Locator name */ + stream_putw(s, len); + stream_put(s, locator_name, len); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + return zclient_send_message(zclient); +} + +/** + * Function to request an SRv6 SID in an asynchronous way + * + * @param zclient The zclient used to connect to SRv6 manager (zebra) + * @param ctx Context associated with the SRv6 SID + * @param sid_value SRv6 SID value for explicit SID allocation + * @param locator_name Name of the parent locator for dynamic SID allocation + * @param sid_func SID function assigned by the SRv6 Manager + * @result 0 on success, -1 otherwise + */ +int srv6_manager_get_sid(struct zclient *zclient, const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name, + uint32_t *sid_func) +{ + struct stream *s; + uint8_t flags = 0; + size_t len; + char buf[256]; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return ZCLIENT_SEND_FAILURE; + } + + if (zclient_debug) + zlog_debug("Getting SRv6 SID: %s", + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* send request */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_GET_SRV6_SID, VRF_DEFAULT); + + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + + /* Flags */ + if (!sid_zero_ipv6(sid_value)) + SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE); + if (locator_name) + SET_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR); + stream_putc(s, flags); + + /* SRv6 SID value */ + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) + stream_put(s, sid_value, sizeof(struct in6_addr)); + + /* SRv6 locator */ + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) { + len = strlen(locator_name); + stream_putw(s, len); + stream_put(s, locator_name, len); + } + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + /* Send the request to SRv6 Manager */ + return zclient_send_message(zclient); +} + +/** + * Function to release an SRv6 SID + * + * @param zclient Zclient used to connect to SRv6 manager (zebra) + * @param ctx Context associated with the SRv6 SID to be removed + * @result 0 on success, -1 otherwise + */ +int srv6_manager_release_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx) +{ + struct stream *s; + char buf[256]; + + if (zclient->sock < 0) { + flog_err(EC_LIB_ZAPI_SOCKET, "%s: invalid zclient socket", + __func__); + return -1; + } + + if (zclient_debug) + zlog_debug("Releasing SRv6 SID: %s", + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* send request */ + s = zclient->obuf; + stream_reset(s); + + zclient_create_header(s, ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID, + VRF_DEFAULT); + + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + + /* Put length at the first point of the stream. */ + stream_putw_at(s, 0, stream_get_endp(s)); + + /* Send the SID release message */ + return zclient_send_message(zclient); +} + /* * Asynchronous label chunk request * - * @param zclient Zclient used to connect to label manager (zebra) + * @param zclient The zclient used to connect to label manager (zebra) * @param keep Avoid garbage collection * @param chunk_size Amount of labels requested * @param base Base for the label chunk. if MPLS_LABEL_BASE_ANY we do not care diff --git a/lib/zclient.h b/lib/zclient.h index 3759f94542..2877b347d8 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -209,6 +209,9 @@ typedef enum { ZEBRA_SRV6_LOCATOR_DELETE, ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK, ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK, + ZEBRA_SRV6_MANAGER_GET_LOCATOR, + ZEBRA_SRV6_MANAGER_GET_SRV6_SID, + ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID, ZEBRA_ERROR, ZEBRA_CLIENT_CAPABILITIES, ZEBRA_OPAQUE_MESSAGE, @@ -235,6 +238,7 @@ typedef enum { ZEBRA_TC_FILTER_ADD, ZEBRA_TC_FILTER_DELETE, ZEBRA_OPAQUE_NOTIFY, + ZEBRA_SRV6_SID_NOTIFY, } zebra_message_types_t; /* Zebra message types. Please update the corresponding * command_types array with any changes! @@ -761,6 +765,13 @@ enum zapi_iptable_notify_owner { ZAPI_IPTABLE_FAIL_REMOVE, }; +enum zapi_srv6_sid_notify { + ZAPI_SRV6_SID_FAIL_ALLOC = 0, + ZAPI_SRV6_SID_ALLOCATED, + ZAPI_SRV6_SID_RELEASED, + ZAPI_SRV6_SID_FAIL_RELEASE, +}; + enum zclient_send_status { ZCLIENT_SEND_FAILURE = -1, ZCLIENT_SEND_SUCCESS = 0, @@ -813,6 +824,28 @@ zapi_rule_notify_owner2str(enum zapi_rule_notify_owner note) return ret; } +static inline const char *zapi_srv6_sid_notify2str(enum zapi_srv6_sid_notify note) +{ + const char *ret = "UNKNOWN"; + + switch (note) { + case ZAPI_SRV6_SID_FAIL_ALLOC: + ret = "ZAPI_SRV6_SID_FAIL_ALLOC"; + break; + case ZAPI_SRV6_SID_ALLOCATED: + ret = "ZAPI_SRV6_SID_ALLOCATED"; + break; + case ZAPI_SRV6_SID_FAIL_RELEASE: + ret = "ZAPI_SRV6_SID_FAIL_RELEASE"; + break; + case ZAPI_SRV6_SID_RELEASED: + ret = "ZAPI_SRV6_SID_RELEASED"; + break; + } + + return ret; +} + /* Zebra MAC types */ #define ZEBRA_MACIP_TYPE_STICKY 0x01 /* Sticky MAC*/ #define ZEBRA_MACIP_TYPE_GW 0x02 /* gateway (SVI) mac*/ @@ -1070,10 +1103,23 @@ extern int tm_get_table_chunk(struct zclient *zclient, uint32_t chunk_size, uint32_t *start, uint32_t *end); extern int tm_release_table_chunk(struct zclient *zclient, uint32_t start, uint32_t end); + +/* Zebra SRv6 Manager flags */ +#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE 0x01 +#define ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR 0x02 + extern int srv6_manager_get_locator_chunk(struct zclient *zclient, const char *locator_name); extern int srv6_manager_release_locator_chunk(struct zclient *zclient, const char *locator_name); +extern int srv6_manager_get_locator(struct zclient *zclient, + const char *locator_name); +extern int srv6_manager_get_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name, uint32_t *sid_func); +extern int srv6_manager_release_sid(struct zclient *zclient, + const struct srv6_sid_ctx *ctx); extern enum zclient_send_status zebra_send_sr_policy(struct zclient *zclient, int cmd, @@ -1128,6 +1174,11 @@ bool zapi_rule_notify_decode(struct stream *s, uint32_t *seqno, bool zapi_ipset_notify_decode(struct stream *s, uint32_t *unique, enum zapi_ipset_notify_owner *note); +bool zapi_srv6_sid_notify_decode(struct stream *s, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t *func, + uint32_t *wide_func, + enum zapi_srv6_sid_notify *note, + char **locator_name); /* Nexthop-group message apis */ extern enum zclient_send_status diff --git a/mgmtd/.gitignore b/mgmtd/.gitignore index 7ce107e93b..e12bcc08cd 100644 --- a/mgmtd/.gitignore +++ b/mgmtd/.gitignore @@ -1 +1,2 @@ mgmtd +mgmtd_testc diff --git a/mgmtd/mgmt_fe_adapter.c b/mgmtd/mgmt_fe_adapter.c index fc1bde0b38..5f53c928a4 100644 --- a/mgmtd/mgmt_fe_adapter.c +++ b/mgmtd/mgmt_fe_adapter.c @@ -43,6 +43,7 @@ struct mgmt_fe_session_ctx { uint64_t txn_id; uint64_t cfg_txn_id; uint8_t ds_locked[MGMTD_DS_MAX_ID]; + const char **notify_xpaths; struct event *proc_cfg_txn_clnp; struct event *proc_show_txn_clnp; @@ -489,6 +490,26 @@ static int fe_adapter_send_get_reply(struct mgmt_fe_session_ctx *session, return fe_adapter_send_msg(session->adapter, &fe_msg, false); } +static int fe_adapter_conn_send_error(struct msg_conn *conn, + uint64_t session_id, uint64_t req_id, + bool short_circuit_ok, int16_t error, + const char *errfmt, ...) PRINTFRR(6, 7); +static int fe_adapter_conn_send_error(struct msg_conn *conn, uint64_t session_id, + uint64_t req_id, bool short_circuit_ok, + int16_t error, const char *errfmt, ...) +{ + va_list ap; + int ret; + + va_start(ap, errfmt); + + ret = vmgmt_msg_native_send_error(conn, session_id, req_id, + short_circuit_ok, error, errfmt, ap); + va_end(ap); + + return ret; +} + static int fe_adapter_send_error(struct mgmt_fe_session_ctx *session, uint64_t req_id, bool short_circuit_ok, int16_t error, const char *errfmt, ...) @@ -1169,6 +1190,88 @@ static int fe_adapter_send_edit_reply(struct mgmt_fe_session_ctx *session, return ret; } +static int +fe_adapter_native_send_session_reply(struct mgmt_fe_client_adapter *adapter, + uint64_t req_id, uint64_t session_id, + bool created) +{ + struct mgmt_msg_session_reply *msg; + int ret; + + msg = mgmt_msg_native_alloc_msg(struct mgmt_msg_session_reply, 0, + MTYPE_MSG_NATIVE_SESSION_REPLY); + msg->refer_id = session_id; + msg->req_id = req_id; + msg->code = MGMT_MSG_CODE_SESSION_REPLY; + msg->created = created; + + __dbg("Sending session-reply from adapter %s to session-id %" PRIu64 + " req-id %" PRIu64 " len %u", + adapter->name, session_id, req_id, + mgmt_msg_native_get_msg_len(msg)); + + ret = fe_adapter_send_native_msg(adapter, msg, + mgmt_msg_native_get_msg_len(msg), + false); + mgmt_msg_native_free_msg(msg); + + return ret; +} + +/** + * fe_adapter_handle_session_req() - Handle a session-req message from a FE client. + * @msg_raw: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_session_req(struct mgmt_fe_client_adapter *adapter, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_session_req *msg = __msg; + struct mgmt_fe_session_ctx *session; + uint64_t client_id; + + __dbg("Got session-req creating: %u for refer-id %" PRIu64 " from '%s'", + msg->refer_id == 0, msg->refer_id, adapter->name); + + if (msg->refer_id) { + uint64_t session_id = msg->refer_id; + + session = mgmt_session_id2ctx(session_id); + if (!session) { + fe_adapter_conn_send_error( + adapter->conn, session_id, msg->req_id, false, + -EINVAL, + "No session to delete for session-id: %" PRIu64, + session_id); + return; + } + fe_adapter_native_send_session_reply(adapter, msg->req_id, + session_id, false); + mgmt_fe_cleanup_session(&session); + return; + } + + client_id = msg->req_id; + + /* See if we have a client name to register */ + if (msg_len > sizeof(*msg)) { + if (!MGMT_MSG_VALIDATE_NUL_TERM(msg, msg_len)) { + fe_adapter_conn_send_error( + adapter->conn, client_id, msg->req_id, false, + -EINVAL, + "Corrupt session-req message rcvd from client-id: %" PRIu64, + client_id); + return; + } + __dbg("Set client-name to '%s'", msg->client_name); + strlcpy(adapter->name, msg->client_name, sizeof(adapter->name)); + } + + session = mgmt_fe_create_session(adapter, client_id); + fe_adapter_native_send_session_reply(adapter, client_id, + session->session_id, true); +} + /** * fe_adapter_handle_get_data() - Handle a get-tree message from a FE client. * @session: the client session. @@ -1401,10 +1504,45 @@ static void fe_adapter_handle_edit(struct mgmt_fe_session_ctx *session, } } +/** + * fe_adapter_handle_notify_select() - Handle an Notify Select message. + * @session: the client session. + * @__msg: the message data. + * @msg_len: the length of the message data. + */ +static void fe_adapter_handle_notify_select(struct mgmt_fe_session_ctx *session, + void *__msg, size_t msg_len) +{ + struct mgmt_msg_notify_select *msg = __msg; + uint64_t req_id = msg->req_id; + const char **selectors = NULL; + const char **new; + + /* An empty message clears the selectors */ + if (msg_len >= sizeof(*msg)) { + selectors = mgmt_msg_native_strings_decode(msg, msg_len, + msg->selectors); + if (!selectors) { + fe_adapter_send_error(session, req_id, false, -EINVAL, + "Invalid message"); + return; + } + } + if (msg->replace) { + darr_free_free(session->notify_xpaths); + session->notify_xpaths = selectors; + } else { + new = darr_append_nz(session->notify_xpaths, + darr_len(selectors)); + memcpy(new, selectors, darr_len(selectors) * sizeof(*selectors)); + darr_free(selectors); + } +} + /** * fe_adapter_handle_rpc() - Handle an RPC message from an FE client. * @session: the client session. - * @msg_raw: the message data. + * @__msg: the message data. * @msg_len: the length of the message data. */ static void fe_adapter_handle_rpc(struct mgmt_fe_session_ctx *session, @@ -1493,6 +1631,28 @@ static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter, size_t msg_len) { struct mgmt_fe_session_ctx *session; + size_t min_size = mgmt_msg_get_min_size(msg->code); + + if (msg_len < min_size) { + if (!min_size) + __log_err("adapter %s: recv msg refer-id %" PRIu64 + " unknown message type %u", + adapter->name, msg->refer_id, msg->code); + else + __log_err("adapter %s: recv msg refer-id %" PRIu64 + " short (%zu<%zu) msg for type %u", + adapter->name, msg->refer_id, msg_len, + min_size, msg->code); + return; + } + + if (msg->code == MGMT_MSG_CODE_SESSION_REQ) { + __dbg("adapter %s: session-id %" PRIu64 + " received SESSION_REQ message", + adapter->name, msg->refer_id); + fe_adapter_handle_session_req(adapter, msg, msg_len); + return; + } session = mgmt_session_id2ctx(msg->refer_id); if (!session) { @@ -1503,13 +1663,26 @@ static void fe_adapter_handle_native_msg(struct mgmt_fe_client_adapter *adapter, assert(session->adapter == adapter); switch (msg->code) { - case MGMT_MSG_CODE_GET_DATA: - fe_adapter_handle_get_data(session, msg, msg_len); - break; case MGMT_MSG_CODE_EDIT: + __dbg("adapter %s: session-id %" PRIu64 " received EDIT message", + adapter->name, msg->refer_id); fe_adapter_handle_edit(session, msg, msg_len); break; + case MGMT_MSG_CODE_NOTIFY_SELECT: + __dbg("adapter %s: session-id %" PRIu64 + " received NOTIFY_SELECT message", + adapter->name, msg->refer_id); + fe_adapter_handle_notify_select(session, msg, msg_len); + break; + case MGMT_MSG_CODE_GET_DATA: + __dbg("adapter %s: session-id %" PRIu64 + " received GET_DATA message", + adapter->name, msg->refer_id); + fe_adapter_handle_get_data(session, msg, msg_len); + break; case MGMT_MSG_CODE_RPC: + __dbg("adapter %s: session-id %" PRIu64 " received RPC message", + adapter->name, msg->refer_id); fe_adapter_handle_rpc(session, msg, msg_len); break; default: @@ -1554,14 +1727,48 @@ void mgmt_fe_adapter_send_notify(struct mgmt_msg_notify_data *msg, size_t msglen { struct mgmt_fe_client_adapter *adapter; struct mgmt_fe_session_ctx *session; + struct nb_node *nb_node; + const char **xpath_prefix; + const char *notif; + bool sendit; + uint len; assert(msg->refer_id == 0); + notif = mgmt_msg_native_xpath_decode(msg, msglen); + if (!notif) { + __log_err("Corrupt notify msg"); + return; + } + + /* + * We need the nb_node to obtain a path which does not include any + * specific list entry selectors + */ + nb_node = nb_node_find(notif); + if (!nb_node) { + __log_err("No schema found for notification: %s", notif); + return; + } + FOREACH_ADAPTER_IN_LIST (adapter) { FOREACH_SESSION_IN_LIST (adapter, session) { - msg->refer_id = session->session_id; - (void)fe_adapter_send_native_msg(adapter, msg, msglen, - false); + /* If no selectors then always send */ + sendit = !session->notify_xpaths; + darr_foreach_p (session->notify_xpaths, xpath_prefix) { + len = strlen(*xpath_prefix); + if (!strncmp(*xpath_prefix, notif, len) || + !strncmp(*xpath_prefix, nb_node->xpath, + len)) { + sendit = true; + break; + } + } + if (sendit) { + msg->refer_id = session->session_id; + (void)fe_adapter_send_native_msg(adapter, msg, + msglen, false); + } } } msg->refer_id = 0; diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 7d0ab9762f..e81a2efbb6 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -99,6 +99,8 @@ static int nhrp_if_delete_hook(struct interface *ifp) free(nifp->ipsec_fallback_profile); if (nifp->source) free(nifp->source); + if (nifp->auth_token) + zbuf_free(nifp->auth_token); XFREE(MTYPE_NHRP_IF, ifp->info); return 0; diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index f779f93486..b8958ba225 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -216,7 +216,7 @@ static void nhrp_reg_send_req(struct event *t) cie->holding_time = htons(if_ad->holdtime); cie->mtu = htons(if_ad->mtu); - nhrp_ext_request(zb, hdr, ifp); + nhrp_ext_request(zb, hdr); /* Cisco NAT detection extension */ if (sockunion_family(&r->proto_addr) != AF_UNSPEC) { @@ -240,7 +240,7 @@ static void nhrp_reg_send_req(struct event *t) cie->mtu = htons(if_ad->mtu); nhrp_ext_complete(zb, ext); - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(r->peer, zb); zbuf_free(zb); } diff --git a/nhrpd/nhrp_packet.c b/nhrpd/nhrp_packet.c index c6bd3bbbde..71f5c2f007 100644 --- a/nhrpd/nhrp_packet.c +++ b/nhrpd/nhrp_packet.c @@ -115,14 +115,32 @@ uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len) return (~csum) & 0xffff; } -void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr) +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp) { + nhrp_packet_complete_auth(zb, hdr, ifp, true); +} + +void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp, bool auth) +{ + struct nhrp_interface *nifp = ifp->info; + struct zbuf *auth_token = nifp->auth_token; + struct nhrp_extension_header *dst; unsigned short size; + if (auth && auth_token) { + dst = nhrp_ext_push(zb, hdr, + NHRP_EXTENSION_AUTHENTICATION | + NHRP_EXTENSION_FLAG_COMPULSORY); + zbuf_copy_peek(zb, auth_token, zbuf_size(auth_token)); + nhrp_ext_complete(zb, dst); + } + if (hdr->extension_offset) nhrp_ext_push(zb, hdr, - NHRP_EXTENSION_END - | NHRP_EXTENSION_FLAG_COMPULSORY); + NHRP_EXTENSION_END | + NHRP_EXTENSION_FLAG_COMPULSORY); size = zb->tail - (uint8_t *)hdr; hdr->packet_size = htons(size); @@ -225,8 +243,7 @@ struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, return ext; } -void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, - struct interface *ifp) +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr) { /* Place holders for standard extensions */ nhrp_ext_push(zb, hdr, diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 6e7857c777..3495317d4c 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -603,7 +603,7 @@ static void nhrp_handle_resolution_req(struct nhrp_packet_parser *pp) break; } } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(peer, zb); err: nhrp_peer_unref(peer); @@ -730,7 +730,8 @@ static void nhrp_handle_registration_request(struct nhrp_packet_parser *p) } } - nhrp_packet_complete(zb, hdr); + /* auth ext was validated and copied from the request */ + nhrp_packet_complete_auth(zb, hdr, ifp, false); nhrp_peer_send(p->peer, zb); err: zbuf_free(zb); @@ -812,7 +813,7 @@ void nhrp_peer_send_indication(struct interface *ifp, uint16_t protocol_type, /* Payload is the packet causing indication */ zbuf_copy(zb, pkt, zbuf_used(pkt)); - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(p, zb); nhrp_peer_unref(p); zbuf_free(zb); @@ -958,9 +959,12 @@ static void nhrp_peer_forward(struct nhrp_peer *p, if (type == NHRP_EXTENSION_END) break; - dst = nhrp_ext_push(zb, hdr, htons(ext->type)); - if (!dst) - goto err; + dst = NULL; + if (type != NHRP_EXTENSION_AUTHENTICATION) { + dst = nhrp_ext_push(zb, hdr, htons(ext->type)); + if (!dst) + goto err; + } switch (type) { case NHRP_EXTENSION_FORWARD_TRANSIT_NHS: @@ -1045,6 +1049,12 @@ static void nhrp_peer_forward(struct nhrp_peer *p, zbuf_put(zb, extpl.head, len); } break; + case NHRP_EXTENSION_AUTHENTICATION: + /* Extensions can be copied from original packet except + * authentication extension which must be regenerated + * hop by hop. + */ + break; default: if (htons(ext->type) & NHRP_EXTENSION_FLAG_COMPULSORY) /* FIXME: RFC says to just copy, but not @@ -1060,10 +1070,11 @@ static void nhrp_peer_forward(struct nhrp_peer *p, zbuf_copy(zb, &extpl, len); break; } - nhrp_ext_complete(zb, dst); + if (dst) + nhrp_ext_complete(zb, dst); } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete_auth(zb, hdr, pp->ifp, true); nhrp_peer_send(p, zb); zbuf_free(zb); zbuf_free(zb_copy); @@ -1089,8 +1100,7 @@ static void nhrp_packet_debug(struct zbuf *zb, const char *dir) reply = packet_types[hdr->type].type == PACKET_REPLY; debugf(NHRP_DEBUG_COMMON, "%s %s(%d) %pSU -> %pSU", dir, - (packet_types[hdr->type].name ? packet_types[hdr->type].name - : "Unknown"), + (packet_types[hdr->type].name ? : "Unknown"), hdr->type, reply ? &dst_proto : &src_proto, reply ? &src_proto : &dst_proto); } @@ -1106,11 +1116,78 @@ static int proto2afi(uint16_t proto) return AF_UNSPEC; } -struct nhrp_route_info { - int local; - struct interface *ifp; - struct nhrp_vc *vc; -}; +static int nhrp_packet_send_error(struct nhrp_packet_parser *pp, + uint16_t indication_code, uint16_t offset) +{ + union sockunion src_proto, dst_proto; + struct nhrp_packet_header *hdr; + struct zbuf *zb; + + src_proto = pp->src_proto; + dst_proto = pp->dst_proto; + if (packet_types[pp->hdr->type].type != PACKET_REPLY) { + src_proto = pp->dst_proto; + dst_proto = pp->src_proto; + } + /* Create reply */ + zb = zbuf_alloc(1500); + hdr = nhrp_packet_push(zb, NHRP_PACKET_ERROR_INDICATION, &pp->src_nbma, + &src_proto, &dst_proto); + + hdr->u.error.code = htons(indication_code); + hdr->u.error.offset = htons(offset); + hdr->flags = pp->hdr->flags; + hdr->hop_count = 0; /* XXX: cisco returns 255 */ + + /* Payload is the packet causing error */ + /* Don`t add extension according to RFC */ + zbuf_put(zb, pp->hdr, sizeof(*pp->hdr)); + zbuf_put(zb, sockunion_get_addr(&pp->src_nbma), + hdr->src_nbma_address_len); + zbuf_put(zb, sockunion_get_addr(&pp->src_proto), + hdr->src_protocol_address_len); + zbuf_put(zb, sockunion_get_addr(&pp->dst_proto), + hdr->dst_protocol_address_len); + nhrp_packet_complete_auth(zb, hdr, pp->ifp, false); + + nhrp_peer_send(pp->peer, zb); + zbuf_free(zb); + return 0; +} + +static bool nhrp_connection_authorized(struct nhrp_packet_parser *pp) +{ + struct nhrp_cisco_authentication_extension *auth_ext; + struct nhrp_interface *nifp = pp->ifp->info; + struct zbuf *auth = nifp->auth_token; + struct nhrp_extension_header *ext; + struct zbuf *extensions, pl; + int cmp = 1; + + extensions = zbuf_alloc(zbuf_used(&pp->extensions)); + zbuf_copy_peek(extensions, &pp->extensions, zbuf_used(&pp->extensions)); + while ((ext = nhrp_ext_pull(extensions, &pl)) != NULL) { + switch (htons(ext->type) & ~NHRP_EXTENSION_FLAG_COMPULSORY) { + case NHRP_EXTENSION_AUTHENTICATION: + cmp = memcmp(auth->buf, pl.buf, zbuf_size(auth)); + auth_ext = (struct nhrp_cisco_authentication_extension *) + auth->buf; + debugf(NHRP_DEBUG_COMMON, + "Processing Authentication Extension for (%s:%s|%d)", + auth_ext->secret, + ((struct nhrp_cisco_authentication_extension *) + pl.buf) + ->secret, + cmp); + break; + default: + /* Ignoring all received extensions except Authentication*/ + break; + } + } + zbuf_free(extensions); + return cmp == 0; +} void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) { @@ -1191,10 +1268,20 @@ void nhrp_peer_recv(struct nhrp_peer *p, struct zbuf *zb) goto drop; } + /* RFC2332 5.3.4 - Authentication is always done pairwise on an NHRP + * hop-by-hop basis; i.e. regenerated at each hop. */ nhrp_packet_debug(zb, "Recv"); - - /* FIXME: Check authentication here. This extension needs to be - * pre-handled. */ + if (nifp->auth_token && + (hdr->type != NHRP_PACKET_ERROR_INDICATION || + hdr->u.error.code != NHRP_ERROR_AUTHENTICATION_FAILURE)) { + if (!nhrp_connection_authorized(&pp)) { + nhrp_packet_send_error(&pp, + NHRP_ERROR_AUTHENTICATION_FAILURE, + 0); + info = "authentication failure"; + goto drop; + } + } /* Figure out if this is local */ target_addr = (packet_types[hdr->type].type == PACKET_REPLY) diff --git a/nhrpd/nhrp_shortcut.c b/nhrpd/nhrp_shortcut.c index e83ce7f58f..9b47d974c3 100644 --- a/nhrpd/nhrp_shortcut.c +++ b/nhrpd/nhrp_shortcut.c @@ -425,7 +425,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) "Shortcut res_req: set cie ht to %u and mtu to %u. shortcut ht is %u", ntohs(cie->holding_time), ntohs(cie->mtu), s->holding_time); - nhrp_ext_request(zb, hdr, ifp); + nhrp_ext_request(zb, hdr); /* Cisco NAT detection extension */ hdr->flags |= htons(NHRP_FLAG_RESOLUTION_NAT); @@ -438,7 +438,7 @@ static void nhrp_shortcut_send_resolution_req(struct nhrp_shortcut *s) nhrp_ext_complete(zb, ext); } - nhrp_packet_complete(zb, hdr); + nhrp_packet_complete(zb, hdr, ifp); nhrp_peer_send(peer, zb); nhrp_peer_unref(peer); diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 40d38c44d2..22b6bdcec7 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -12,6 +12,9 @@ #include "nhrpd.h" #include "netlink.h" +#include "nhrp_protocol.h" + +#include "nhrpd/nhrp_vty_clippy.c" static int nhrp_config_write(struct vty *vty); static struct cmd_node zebra_node = { @@ -459,6 +462,59 @@ DEFUN(if_no_nhrp_holdtime, if_no_nhrp_holdtime_cmd, return CMD_SUCCESS; } +#define NHRP_CISCO_PASS_LEN 8 +DEFPY(if_nhrp_authentication, if_nhrp_authentication_cmd, + AFI_CMD "nhrp authentication PASSWORD$password", + AFI_STR + NHRP_STR + "Specify plain text password used for authenticantion\n" + "Password, plain text, limited to 8 characters\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct nhrp_cisco_authentication_extension *auth; + struct nhrp_interface *nifp = ifp->info; + int pass_len = strlen(password); + + if (pass_len > NHRP_CISCO_PASS_LEN) { + vty_out(vty, "Password size limit exceeded (%d>%d)\n", + pass_len, NHRP_CISCO_PASS_LEN); + return CMD_WARNING_CONFIG_FAILED; + } + + if (nifp->auth_token) { + zbuf_free(nifp->auth_token); + nifp->auth_token = NULL; + } + + nifp->auth_token = zbuf_alloc(pass_len + sizeof(uint32_t)); + auth = (struct nhrp_cisco_authentication_extension *) + nifp->auth_token->buf; + auth->type = htonl(NHRP_AUTHENTICATION_PLAINTEXT); + memcpy(auth->secret, password, pass_len); + + return CMD_SUCCESS; +} + + +DEFPY(if_no_nhrp_authentication, if_no_nhrp_authentication_cmd, + "no " AFI_CMD "nhrp authentication PASSWORD$password", + NO_STR + AFI_STR + NHRP_STR + "Specify plain text password used for authenticantion\n" + "Password, plain text, limited to 8 characters\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct nhrp_interface *nifp = ifp->info; + + if (nifp->auth_token) { + zbuf_free(nifp->auth_token); + nifp->auth_token = NULL; + } + return CMD_SUCCESS; +} + + DEFUN(if_nhrp_mtu, if_nhrp_mtu_cmd, "ip nhrp mtu <(576-1500)|opennhrp>", IP_STR @@ -1053,6 +1109,7 @@ DEFUN(show_dmvpn, show_dmvpn_cmd, static void clear_nhrp_cache(struct nhrp_cache *c, void *data) { struct info_ctx *ctx = data; + if (c->cur.type <= NHRP_CACHE_DYNAMIC) { nhrp_cache_update_binding(c, c->cur.type, -1, NULL, 0, NULL, NULL); @@ -1129,6 +1186,7 @@ static void interface_config_write_nhrp_map(struct nhrp_cache_config *c, static int interface_config_write(struct vty *vty) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct nhrp_cisco_authentication_extension *auth; struct write_map_ctx mapctx; struct interface *ifp; struct nhrp_interface *nifp; @@ -1155,6 +1213,12 @@ static int interface_config_write(struct vty *vty) if (nifp->source) vty_out(vty, " tunnel source %s\n", nifp->source); + if (nifp->auth_token) { + auth = (struct nhrp_cisco_authentication_extension *) + nifp->auth_token->buf; + vty_out(vty, " ip nhrp authentication %s\n", auth->secret); + } + for (afi = 0; afi < AFI_MAX; afi++) { struct nhrp_afi_data *ad = &nifp->afi[afi]; @@ -1256,6 +1320,8 @@ void nhrp_config_init(void) install_element(INTERFACE_NODE, &if_no_nhrp_network_id_cmd); install_element(INTERFACE_NODE, &if_nhrp_holdtime_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_holdtime_cmd); + install_element(INTERFACE_NODE, &if_nhrp_authentication_cmd); + install_element(INTERFACE_NODE, &if_no_nhrp_authentication_cmd); install_element(INTERFACE_NODE, &if_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_no_nhrp_mtu_cmd); install_element(INTERFACE_NODE, &if_nhrp_flags_cmd); diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index e389b7489d..344e1d5178 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -311,6 +311,7 @@ DECLARE_DLIST(nhrp_reglist, struct nhrp_registration, reglist_entry); struct nhrp_interface { struct interface *ifp; + struct zbuf *auth_token; unsigned enabled : 1; char *ipsec_profile, *ipsec_fallback_profile, *source; @@ -480,9 +481,13 @@ struct nhrp_packet_header *nhrp_packet_push(struct zbuf *zb, uint8_t type, const union sockunion *src_nbma, const union sockunion *src_proto, const union sockunion *dst_proto); -void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr); uint16_t nhrp_packet_calculate_checksum(const uint8_t *pdu, uint16_t len); +void nhrp_packet_complete(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp); +void nhrp_packet_complete_auth(struct zbuf *zb, struct nhrp_packet_header *hdr, + struct interface *ifp, bool auth); + struct nhrp_packet_header *nhrp_packet_pull(struct zbuf *zb, union sockunion *src_nbma, union sockunion *src_proto, @@ -501,8 +506,7 @@ nhrp_ext_push(struct zbuf *zb, struct nhrp_packet_header *hdr, uint16_t type); void nhrp_ext_complete(struct zbuf *zb, struct nhrp_extension_header *ext); struct nhrp_extension_header *nhrp_ext_pull(struct zbuf *zb, struct zbuf *payload); -void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr, - struct interface *); +void nhrp_ext_request(struct zbuf *zb, struct nhrp_packet_header *hdr); int nhrp_ext_reply(struct zbuf *zb, struct nhrp_packet_header *hdr, struct interface *ifp, struct nhrp_extension_header *ext, struct zbuf *extpayload); diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index 227ff6c678..94fb3bb5be 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -42,3 +42,7 @@ noinst_HEADERS += \ nhrpd/zbuf.h \ nhrpd/znl.h \ # end + +clippy_scan += \ + nhrpd/nhrp_vty.c \ + # end diff --git a/ospfd/ospf_flood.c b/ospfd/ospf_flood.c index e15871ac81..2af4ae3170 100644 --- a/ospfd/ospf_flood.c +++ b/ospfd/ospf_flood.c @@ -110,6 +110,9 @@ void ospf_area_update_fr_state(struct ospf_area *area) static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_interface *oi = inbr->oi; + /* LSA is more recent than database copy, but was not flooded back out receiving interface. Delayed acknowledgment sent. If interface is in Backup state @@ -122,12 +125,27 @@ static void ospf_flood_delayed_lsa_ack(struct ospf_neighbor *inbr, worked out previously */ /* Deal with router as BDR */ - if (inbr->oi->state == ISM_Backup && !NBR_IS_DR(inbr)) + if (oi->state == ISM_Backup && !NBR_IS_DR(inbr)) return; - /* Schedule a delayed LSA Ack to be sent */ - listnode_add(inbr->oi->ls_ack, - ospf_lsa_lock(lsa)); /* delayed LSA Ack */ + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &inbr->router_id, + IF_NAME(inbr->oi)); + + /* Add the LSA to the interface delayed Ack list. */ + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&oi->ls_ack_delayed, ls_ack_list_entry); + + /* Set LS Ack timer if it is not already scheduled. */ + if (!oi->t_ls_ack_delayed) + OSPF_ISM_TIMER_ON(oi->t_ls_ack_delayed, + ospf_ls_ack_delayed_timer, + oi->v_ls_ack_delayed); } /* Check LSA is related to external info. */ @@ -1015,7 +1033,7 @@ void ospf_ls_request_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) ospf_lsdb_delete(&nbr->ls_req, lsa); } -/* Remove all LSA from neighbor's ls-requenst list. */ +/* Remove all LSAs from neighbor's ls-request list. */ void ospf_ls_request_delete_all(struct ospf_neighbor *nbr) { ospf_lsa_unlock(&nbr->ls_req_last); @@ -1061,58 +1079,114 @@ int ospf_ls_retransmit_isempty(struct ospf_neighbor *nbr) /* Add LSA to be retransmitted to neighbor's ls-retransmit list. */ void ospf_ls_retransmit_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - struct ospf_lsa *old; + struct ospf_lsdb_linked_node *ls_rxmt_node; + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct ospf_lsa *old = NULL; + bool rxmt_head_replaced = false; - old = ospf_ls_retransmit_lookup(nbr, lsa); + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + if (ls_rxmt_node) + old = ls_rxmt_node->info; if (ospf_lsa_more_recent(old, lsa) < 0) { if (old) { old->retransmit_counter--; + if (ls_rxmt_node->lsa_list_entry == + ospf_lsa_list_first(&nbr->ls_rxmt_list)) + rxmt_head_replaced = true; + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_node->lsa_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry); + ospf_lsdb_delete(&nbr->ls_rxmt, old); if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Old Delete LSA[%s] on Add", ospf_ls_retransmit_count(nbr), &nbr->router_id, ospf_get_name(nbr->oi->ospf), - dump_lsa_key(old)); - ospf_lsdb_delete(&nbr->ls_rxmt, old); + dump_lsa_key(lsa)); + ospf_lsa_unlock(&old); } lsa->retransmit_counter++; + ls_rxmt_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); + /* + * Set the LSA retransmission time for the neighbor; + */ + monotime(&ls_rxmt_list_entry->list_entry_time); + ls_rxmt_list_entry->list_entry_time.tv_sec += nbr->v_ls_rxmt; + /* - * We cannot make use of the newly introduced callback function - * "lsdb->new_lsa_hook" to replace debug output below, just - * because - * it seems no simple and smart way to pass neighbor information - * to - * the common function "ospf_lsdb_add()" -- endo. + * Add the LSA to the neighbor retransmission list. */ + ls_rxmt_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsdb_add(&nbr->ls_rxmt, lsa); + + /* + * Look up the newly added node and set the list pointer. + */ + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + ls_rxmt_node->lsa_list_entry = ls_rxmt_list_entry; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) - zlog_debug("RXmtL(%lu)++, NBR(%pI4(%s)), LSA[%s]", + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Add LSA[%s] retrans at (%ld/%ld)", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), - dump_lsa_key(lsa)); - ospf_lsdb_add(&nbr->ls_rxmt, lsa); + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + dump_lsa_key(lsa), + (long)ls_rxmt_list_entry->list_entry_time + .tv_sec, + (long)ls_rxmt_list_entry->list_entry_time + .tv_usec); + /* + * Reset the neighbor LSA retransmission timer if isn't currently + * running or the LSA at the head of the list was updated. + */ + if (!nbr->t_ls_rxmt || rxmt_head_replaced) + ospf_ls_retransmit_set_timer(nbr); } } /* Remove LSA from neibghbor's ls-retransmit list. */ void ospf_ls_retransmit_delete(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { - if (ospf_ls_retransmit_lookup(nbr, lsa)) { + struct ospf_lsdb_linked_node *ls_rxmt_node; + + ls_rxmt_node = ospf_lsdb_linked_lookup(&nbr->ls_rxmt, lsa); + + if (ls_rxmt_node) { + bool rxmt_timer_reset; + + if (ls_rxmt_node->lsa_list_entry == + ospf_lsa_list_first(&nbr->ls_rxmt_list)) + rxmt_timer_reset = true; + else + rxmt_timer_reset = false; + lsa->retransmit_counter--; - if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) /* -- endo. */ - zlog_debug("RXmtL(%lu)--, NBR(%pI4(%s)), LSA[%s]", + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_node->lsa_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_node->lsa_list_entry); + ospf_lsdb_delete(&nbr->ls_rxmt, lsa); + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) Delete LSA[%s]", ospf_ls_retransmit_count(nbr), - &nbr->router_id, - ospf_get_name(nbr->oi->ospf), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), dump_lsa_key(lsa)); - ospf_lsdb_delete(&nbr->ls_rxmt, lsa); + ospf_lsa_unlock(&lsa); + + /* + * If the LS retransmission entry at the head of the list was + * deleted, reset the timer. + */ + if (rxmt_timer_reset) + ospf_ls_retransmit_set_timer(nbr); } } /* Clear neighbor's ls-retransmit list. */ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; struct ospf_lsdb *lsdb; int i; @@ -1128,10 +1202,54 @@ void ospf_ls_retransmit_clear(struct ospf_neighbor *nbr) ospf_ls_retransmit_delete(nbr, lsa); } + frr_each_safe (ospf_lsa_list, &nbr->ls_rxmt_list, ls_rxmt_list_entry) { + ospf_lsa_list_del(&nbr->ls_rxmt_list, ls_rxmt_list_entry); + ospf_lsa_unlock(&ls_rxmt_list_entry->lsa); + XFREE(MTYPE_OSPF_LSA_LIST, ls_rxmt_list_entry); + } + ospf_lsa_unlock(&nbr->ls_req_last); nbr->ls_req_last = NULL; } +/* + * Set the neighbor's ls-retransmit timer based on the next + * LSA retransmit time. + */ +void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr) +{ + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + + if (nbr->t_ls_rxmt) + EVENT_OFF(nbr->t_ls_rxmt); + + ls_rxmt_list_entry = ospf_lsa_list_first(&nbr->ls_rxmt_list); + if (ls_rxmt_list_entry) { + struct timeval current_time, delay; + unsigned long delay_milliseconds; + + monotime(¤t_time); + if (timercmp(¤t_time, + &ls_rxmt_list_entry->list_entry_time, >=)) + delay_milliseconds = 10; + else { + timersub(&ls_rxmt_list_entry->list_entry_time, + ¤t_time, &delay); + delay_milliseconds = (delay.tv_sec * 1000) + + (delay.tv_usec / 1000); + } + + event_add_timer_msec(master, ospf_ls_rxmt_timer, nbr, + delay_milliseconds, &nbr->t_ls_rxmt); + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) retrans timer set in %ld msecs - Head LSA(%s)", + ospf_ls_retransmit_count(nbr), + &nbr->router_id, ospf_get_name(nbr->oi->ospf), + delay_milliseconds, + dump_lsa_key(ls_rxmt_list_entry->lsa)); + } +} + /* Lookup LSA from neighbor's ls-retransmit list. */ struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) diff --git a/ospfd/ospf_flood.h b/ospfd/ospf_flood.h index 3757400d0c..2412052970 100644 --- a/ospfd/ospf_flood.h +++ b/ospfd/ospf_flood.h @@ -7,6 +7,39 @@ #ifndef _ZEBRA_OSPF_FLOOD_H #define _ZEBRA_OSPF_FLOOD_H +#include "typesafe.h" + +/* + * OSPF Temporal LSA List + */ +PREDECL_DLIST(ospf_lsa_list); + +struct ospf_lsa_list_entry { + /* Linkage for LSA List */ + struct ospf_lsa_list_item list_linkage; + + union { + /* + * Time associated with the list entry. For example, for a + * neigbhor link retransmission list, this is the + * retransmission time. + */ + struct timeval list_entry_timeval; + + /* + * Destanation address specific to the LSA list. For example, + * the distination for an associated direct LS acknowledgment. + */ + struct in_addr list_entry_dst_addr; + } u; + + struct ospf_lsa *lsa; +}; +#define list_entry_time u.list_entry_timeval +#define list_entry_dst u.list_entry_dst_addr + +DECLARE_DLIST(ospf_lsa_list, struct ospf_lsa_list_entry, list_linkage); + extern int ospf_flood(struct ospf *, struct ospf_neighbor *, struct ospf_lsa *, struct ospf_lsa *); extern int ospf_flood_through(struct ospf *, struct ospf_neighbor *, @@ -36,6 +69,8 @@ extern void ospf_ls_retransmit_add(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_clear(struct ospf_neighbor *); +extern void ospf_ls_retransmit_set_timer(struct ospf_neighbor *nbr); + extern struct ospf_lsa *ospf_ls_retransmit_lookup(struct ospf_neighbor *, struct ospf_lsa *); extern void ospf_ls_retransmit_delete_nbr_area(struct ospf_area *, diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 11ac7af7c9..c4210eb70c 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -186,10 +186,12 @@ static void ospf_if_default_variables(struct ospf_interface *oi) oi->crypt_seqnum = 0; - /* This must be short, (less than RxmtInterval) - - RFC 2328 Section 13.5 para 3. Set to 1 second to avoid Acks being - held back for too long - MAG */ - oi->v_ls_ack = 1; + /* + * The OSPF LS ACK Delay timer must be less than the LS Retransmision + * timer. As per RFC 2328 Section 13.5 paragraph 3, Set to 1 second + * to avoid Acks being held back for too long + */ + oi->v_ls_ack_delayed = OSPF_ACK_DELAY_DEFAULT; } /* lookup oi for specified prefix/ifp */ @@ -272,9 +274,9 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, /* Initialize static neighbor list. */ oi->nbr_nbma = list_new(); - /* Initialize Link State Acknowledgment list. */ - oi->ls_ack = list_new(); - oi->ls_ack_direct.ls_ack = list_new(); + /* Initialize Link State Acknowledgment lists. */ + ospf_lsa_list_init(&oi->ls_ack_delayed); + ospf_lsa_list_init(&oi->ls_ack_direct); /* Set default values. */ ospf_if_default_variables(oi); @@ -306,6 +308,22 @@ struct ospf_interface *ospf_if_new(struct ospf *ospf, struct interface *ifp, return oi; } +/* + * Cleanup Interface Ack List + */ +static void ospf_if_cleanup_ack_list(struct ospf_lsa_list_head *ls_ack_list) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + /* Restore an interface to its pre UP state Used from ism_interface_down only */ void ospf_if_cleanup(struct ospf_interface *oi) @@ -314,7 +332,6 @@ void ospf_if_cleanup(struct ospf_interface *oi) struct listnode *node, *nnode; struct ospf_neighbor *nbr; struct ospf_nbr_nbma *nbr_nbma; - struct ospf_lsa *lsa; /* oi->nbrs and oi->nbr_nbma should be deleted on InterfaceDown event */ /* delete all static neighbors attached to this interface */ @@ -338,10 +355,9 @@ void ospf_if_cleanup(struct ospf_interface *oi) OSPF_NSM_EVENT_EXECUTE(nbr, NSM_KillNbr); } - /* Cleanup Link State Acknowlegdment list. */ - for (ALL_LIST_ELEMENTS(oi->ls_ack, node, nnode, lsa)) - ospf_lsa_unlock(&lsa); /* oi->ls_ack */ - list_delete_all_node(oi->ls_ack); + /* Cleanup Link State Delayed Acknowlegdment list. */ + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); oi->crypt_seqnum = 0; @@ -377,8 +393,8 @@ void ospf_if_free(struct ospf_interface *oi) /* Free any lists that should be freed */ list_delete(&oi->nbr_nbma); - list_delete(&oi->ls_ack); - list_delete(&oi->ls_ack_direct.ls_ack); + ospf_if_cleanup_ack_list(&oi->ls_ack_delayed); + ospf_if_cleanup_ack_list(&oi->ls_ack_direct); if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ospf interface %s vrf %s id %u deleted", @@ -542,6 +558,7 @@ static struct ospf_if_params *ospf_new_if_params(void) UNSET_IF_PARAM(oip, output_cost_cmd); UNSET_IF_PARAM(oip, transmit_delay); UNSET_IF_PARAM(oip, retransmit_interval); + UNSET_IF_PARAM(oip, retransmit_window); UNSET_IF_PARAM(oip, passive_interface); UNSET_IF_PARAM(oip, v_hello); UNSET_IF_PARAM(oip, fast_hello); @@ -599,6 +616,7 @@ void ospf_free_if_params(struct interface *ifp, struct in_addr addr) if (!OSPF_IF_PARAM_CONFIGURED(oip, output_cost_cmd) && !OSPF_IF_PARAM_CONFIGURED(oip, transmit_delay) && !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_interval) && + !OSPF_IF_PARAM_CONFIGURED(oip, retransmit_window) && !OSPF_IF_PARAM_CONFIGURED(oip, passive_interface) && !OSPF_IF_PARAM_CONFIGURED(oip, v_hello) && !OSPF_IF_PARAM_CONFIGURED(oip, fast_hello) && @@ -695,6 +713,9 @@ int ospf_if_new_hook(struct interface *ifp) IF_DEF_PARAMS(ifp)->retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + SET_IF_PARAM(IF_DEF_PARAMS(ifp), priority); IF_DEF_PARAMS(ifp)->priority = OSPF_ROUTER_PRIORITY_DEFAULT; diff --git a/ospfd/ospf_interface.h b/ospfd/ospf_interface.h index 45d0b7943a..78a4fb9e59 100644 --- a/ospfd/ospf_interface.h +++ b/ospfd/ospf_interface.h @@ -13,6 +13,7 @@ #include "keychain.h" #include "ospfd/ospf_packet.h" #include "ospfd/ospf_spf.h" +#include #define IF_OSPF_IF_INFO(I) ((struct ospf_if_info *)((I)->info)) #define IF_DEF_PARAMS(I) (IF_OSPF_IF_INFO (I)->def_params) @@ -47,6 +48,8 @@ struct ospf_if_params { output_cost_cmd); /* Command Interface Output Cost */ DECLARE_IF_PARAM(uint32_t, retransmit_interval); /* Retransmission Interval */ + DECLARE_IF_PARAM(uint32_t, + retransmit_window); /* Retransmission Window */ DECLARE_IF_PARAM(uint8_t, passive_interface); /* OSPF Interface is passive: no sending or receiving (no need to @@ -263,20 +266,20 @@ struct ospf_interface { struct route_table *ls_upd_queue; - struct list *ls_ack; /* Link State Acknowledgment list. */ - - struct { - struct list *ls_ack; - struct in_addr dst; - } ls_ack_direct; + /* + * List of LSAs for delayed and direct link + * state acknowledgment transmission. + */ + struct ospf_lsa_list_head ls_ack_delayed; + struct ospf_lsa_list_head ls_ack_direct; /* Timer values. */ - uint32_t v_ls_ack; /* Delayed Link State Acknowledgment */ + uint32_t v_ls_ack_delayed; /* Delayed Link State Acknowledgment */ /* Threads. */ struct event *t_hello; /* timer */ struct event *t_wait; /* timer */ - struct event *t_ls_ack; /* timer */ + struct event *t_ls_ack_delayed; /* timer */ struct event *t_ls_ack_direct; /* event */ struct event *t_ls_upd_event; /* event */ struct event *t_opaque_lsa_self; /* Type-9 Opaque-LSAs */ @@ -296,6 +299,7 @@ struct ospf_interface { uint32_t ls_ack_out; /* LS Ack message output count. */ uint32_t discarded; /* discarded input count by error. */ uint32_t state_change; /* Number of status change. */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmitted. */ uint32_t full_nbrs; diff --git a/ospfd/ospf_ism.c b/ospfd/ospf_ism.c index 878ab725bd..377e7a6bcc 100644 --- a/ospfd/ospf_ism.c +++ b/ospfd/ospf_ism.c @@ -285,7 +285,7 @@ static void ism_timer_set(struct ospf_interface *oi) reset also. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Loopback: @@ -293,7 +293,7 @@ static void ism_timer_set(struct ospf_interface *oi) unavailable for regular data traffic. */ EVENT_OFF(oi->t_hello); EVENT_OFF(oi->t_wait); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); EVENT_OFF(oi->gr.hello_delay.t_grace_send); break; case ISM_Waiting: @@ -304,7 +304,7 @@ static void ism_timer_set(struct ospf_interface *oi) OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); OSPF_ISM_TIMER_ON(oi->t_wait, ospf_wait_timer, OSPF_IF_PARAM(oi, v_wait)); - EVENT_OFF(oi->t_ls_ack); + EVENT_OFF(oi->t_ls_ack_delayed); break; case ISM_PointToPoint: /* The interface connects to a physical Point-to-point network @@ -314,8 +314,6 @@ static void ism_timer_set(struct ospf_interface *oi) /* send first hello immediately */ OSPF_ISM_TIMER_MSEC_ON(oi->t_hello, ospf_hello_timer, 1); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DROther: /* The network type of the interface is broadcast or NBMA @@ -324,8 +322,6 @@ static void ism_timer_set(struct ospf_interface *oi) Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_Backup: /* The network type of the interface is broadcast os NBMA @@ -333,8 +329,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Backup Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; case ISM_DR: /* The network type of the interface is broadcast or NBMA @@ -342,8 +336,6 @@ static void ism_timer_set(struct ospf_interface *oi) and the router is Designated Router. */ OSPF_HELLO_TIMER_ON(oi); EVENT_OFF(oi->t_wait); - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, - oi->v_ls_ack); break; } } diff --git a/ospfd/ospf_lsdb.c b/ospfd/ospf_lsdb.c index 0111c4924e..d1b3eb0d35 100644 --- a/ospfd/ospf_lsdb.c +++ b/ospfd/ospf_lsdb.c @@ -34,6 +34,59 @@ void ospf_lsdb_init(struct ospf_lsdb *lsdb) lsdb->type[i].db = route_table_init(); } +static struct route_node * +ospf_lsdb_linked_node_create(route_table_delegate_t *delegate, + struct route_table *table) +{ + struct ospf_lsdb_linked_node *node; + + node = XCALLOC(MTYPE_OSPF_LSDB_NODE, + sizeof(struct ospf_lsdb_linked_node)); + + return (struct route_node *)node; +} + +static void ospf_lsdb_linked_node_destroy(route_table_delegate_t *delegate, + struct route_table *table, + struct route_node *node) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node = + (struct ospf_lsdb_linked_node *)node; + + XFREE(MTYPE_OSPF_LSDB_NODE, lsdb_linked_node); +} + +static route_table_delegate_t ospf_lsdb_linked_table_delegate = { + .create_node = ospf_lsdb_linked_node_create, + .destroy_node = ospf_lsdb_linked_node_destroy, +}; + +void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb) +{ + int i; + + for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) + lsdb->type[i].db = route_table_init_with_delegate( + &ospf_lsdb_linked_table_delegate); +} + +struct ospf_lsdb_linked_node *ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, + struct ospf_lsa *lsa) +{ + struct ospf_lsdb_linked_node *lsdb_linked_node; + struct route_table *table; + struct prefix_ls lp; + + table = lsdb->type[lsa->data->type].db; + ls_prefix_set(&lp, lsa); + lsdb_linked_node = (struct ospf_lsdb_linked_node *) + route_node_lookup(table, (struct prefix *)&lp); + if (lsdb_linked_node) + route_unlock_node((struct route_node *)lsdb_linked_node); + + return lsdb_linked_node; +} + void ospf_lsdb_free(struct ospf_lsdb *lsdb) { ospf_lsdb_cleanup(lsdb); diff --git a/ospfd/ospf_lsdb.h b/ospfd/ospf_lsdb.h index bf295ca830..e5e3be8baa 100644 --- a/ospfd/ospf_lsdb.h +++ b/ospfd/ospf_lsdb.h @@ -7,6 +7,9 @@ #ifndef _ZEBRA_OSPF_LSDB_H #define _ZEBRA_OSPF_LSDB_H +#include "prefix.h" +#include "table.h" + /* OSPF LSDB structure. */ struct ospf_lsdb { struct { @@ -43,9 +46,29 @@ struct ospf_lsdb { #define AREA_LSDB(A,T) ((A)->lsdb->type[(T)].db) #define AS_LSDB(O,T) ((O)->lsdb->type[(T)].db) +/* + * Alternate route node structure for LSDB nodes linked to + * list elements. + */ +struct ospf_lsdb_linked_node { + /* + * Caution these must be the very first fields + */ + ROUTE_NODE_FIELDS + + /* + * List entry on an LSA list, e.g., a neighbor + * retransmission list. + */ + struct ospf_lsa_list_entry *lsa_list_entry; +}; + /* OSPF LSDB related functions. */ extern struct ospf_lsdb *ospf_lsdb_new(void); extern void ospf_lsdb_init(struct ospf_lsdb *); +extern void ospf_lsdb_linked_init(struct ospf_lsdb *lsdb); +extern struct ospf_lsdb_linked_node * +ospf_lsdb_linked_lookup(struct ospf_lsdb *lsdb, struct ospf_lsa *lsa); extern void ospf_lsdb_free(struct ospf_lsdb *); extern void ospf_lsdb_cleanup(struct ospf_lsdb *); extern void ls_prefix_set(struct prefix_ls *lp, struct ospf_lsa *lsa); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index fdb4e5c587..5c11027506 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -48,14 +48,20 @@ #include "ospfd/ospf_apiserver.h" #define OSPFD_STATE_NAME "%s/ospfd.json", frr_libstatedir -#define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_runstatedir, i +#define OSPFD_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_libstatedir, i /* this one includes the path... because the instance number was in the path * before :( ... which totally didn't have a mkdir anywhere. + * + * ... and libstatedir & runstatedir got switched around while changing this; + * for non-instance it read the wrong path, for instance it wrote the wrong + * path. (There is no COMPAT2 for non-instance because it was writing to the + * right place, i.e. no extra path to check exists from reading a wrong path.) */ -#define OSPFD_COMPAT_STATE_NAME "%s/ospfd-gr.json", frr_libstatedir -#define OSPFD_COMPAT_INST_STATE_NAME(i) \ +#define OSPFD_COMPAT_STATE_NAME "%s/ospfd-gr.json", frr_runstatedir +#define OSPFD_COMPAT1_INST_STATE_NAME(i) \ "%s-%d/ospfd-gr.json", frr_runstatedir, i +#define OSPFD_COMPAT2_INST_STATE_NAME(i) "%s/ospfd-%d.json", frr_runstatedir, i /* ospfd privileges */ zebra_capabilities_t _caps_p[] = {ZCAP_NET_RAW, ZCAP_BIND, ZCAP_NET_ADMIN, @@ -139,10 +145,12 @@ static const struct frr_yang_module_info *const ospfd_yang_modules[] = { /* actual paths filled in main() */ static char state_path[512]; -static char state_compat_path[512]; +static char state_compat1_path[512]; +static char state_compat2_path[512]; static char *state_paths[] = { state_path, - state_compat_path, + state_compat1_path, + state_compat2_path, /* NULLed out if not needed */ NULL, }; @@ -242,12 +250,18 @@ int main(int argc, char **argv) if (ospf_instance) { snprintf(state_path, sizeof(state_path), OSPFD_INST_STATE_NAME(ospf_instance)); - snprintf(state_compat_path, sizeof(state_compat_path), - OSPFD_COMPAT_INST_STATE_NAME(ospf_instance)); + snprintf(state_compat1_path, sizeof(state_compat1_path), + OSPFD_COMPAT1_INST_STATE_NAME(ospf_instance)); + snprintf(state_compat2_path, sizeof(state_compat2_path), + OSPFD_COMPAT2_INST_STATE_NAME(ospf_instance)); } else { snprintf(state_path, sizeof(state_path), OSPFD_STATE_NAME); - snprintf(state_compat_path, sizeof(state_compat_path), + snprintf(state_compat1_path, sizeof(state_compat1_path), OSPFD_COMPAT_STATE_NAME); + /* no COMPAT2 here since it was reading that was broken, + * there is no additional path that would've been written + */ + state_paths[2] = NULL; } /* OSPF master init. */ diff --git a/ospfd/ospf_memory.c b/ospfd/ospf_memory.c index 9854c8cae8..478af323d3 100644 --- a/ospfd/ospf_memory.c +++ b/ospfd/ospf_memory.c @@ -45,3 +45,5 @@ DEFINE_MTYPE(OSPFD, OSPF_GR_HELPER, "OSPF Graceful Restart Helper"); DEFINE_MTYPE(OSPFD, OSPF_EXTERNAL_RT_AGGR, "OSPF External Route Summarisation"); DEFINE_MTYPE(OSPFD, OSPF_P_SPACE, "OSPF TI-LFA P-Space"); DEFINE_MTYPE(OSPFD, OSPF_Q_SPACE, "OSPF TI-LFA Q-Space"); +DEFINE_MTYPE(OSPFD, OSPF_LSA_LIST, "OSPF LSA List"); +DEFINE_MTYPE(OSPFD, OSPF_LSDB_NODE, "OSPF LSDB Linked Node"); diff --git a/ospfd/ospf_memory.h b/ospfd/ospf_memory.h index d11b69abb0..e2139b517b 100644 --- a/ospfd/ospf_memory.h +++ b/ospfd/ospf_memory.h @@ -44,5 +44,7 @@ DECLARE_MTYPE(OSPF_GR_HELPER); DECLARE_MTYPE(OSPF_EXTERNAL_RT_AGGR); DECLARE_MTYPE(OSPF_P_SPACE); DECLARE_MTYPE(OSPF_Q_SPACE); +DECLARE_MTYPE(OSPF_LSA_LIST); +DECLARE_MTYPE(OSPF_LSDB_NODE); #endif /* _QUAGGA_OSPF_MEMORY_H */ diff --git a/ospfd/ospf_neighbor.c b/ospfd/ospf_neighbor.c index d47d581605..2514fc0ab3 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -68,7 +68,7 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); nbr->priority = -1; /* DD flags. */ @@ -80,8 +80,10 @@ struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi) nbr->nbr_nbma = NULL; ospf_lsdb_init(&nbr->db_sum); - ospf_lsdb_init(&nbr->ls_rxmt); + + ospf_lsdb_linked_init(&nbr->ls_rxmt); ospf_lsdb_init(&nbr->ls_req); + ospf_lsa_list_init(&nbr->ls_rxmt_list); nbr->crypt_seqnum = 0; @@ -128,7 +130,7 @@ void ospf_nbr_free(struct ospf_neighbor *nbr) EVENT_OFF(nbr->t_inactivity); EVENT_OFF(nbr->t_db_desc); EVENT_OFF(nbr->t_ls_req); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); /* Cancel all events. */ /* Thread lookup cost would be negligible. */ event_cancel_event(master, nbr); diff --git a/ospfd/ospf_neighbor.h b/ospfd/ospf_neighbor.h index 07d095f03d..0e041f9e6d 100644 --- a/ospfd/ospf_neighbor.h +++ b/ospfd/ospf_neighbor.h @@ -9,6 +9,7 @@ #include #include +#include /* Neighbor Data Structure */ struct ospf_neighbor { @@ -44,6 +45,7 @@ struct ospf_neighbor { /* LSA data. */ struct ospf_lsdb ls_rxmt; + struct ospf_lsa_list_head ls_rxmt_list; struct ospf_lsdb db_sum; struct ospf_lsdb ls_req; struct ospf_lsa *ls_req_last; @@ -54,13 +56,13 @@ struct ospf_neighbor { uint32_t v_inactivity; uint32_t v_db_desc; uint32_t v_ls_req; - uint32_t v_ls_upd; + uint32_t v_ls_rxmt; /* Threads. */ struct event *t_inactivity; struct event *t_db_desc; struct event *t_ls_req; - struct event *t_ls_upd; + struct event *t_ls_rxmt; struct event *t_hello_reply; /* NBMA configured neighbour */ @@ -71,6 +73,7 @@ struct ospf_neighbor { struct timeval ts_last_regress; /* last regressive NSM change */ const char *last_regress_str; /* Event which last regressed NSM */ uint32_t state_change; /* NSM state change counter */ + uint32_t ls_rxmt_lsa; /* Number of LSAs retransmited. */ /* BFD information */ struct bfd_session_params *bfd_session; diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index c466ddcc6f..079a1fa55e 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -112,18 +112,16 @@ static void nsm_timer_set(struct ospf_neighbor *nbr) case NSM_Init: case NSM_TwoWay: EVENT_OFF(nbr->t_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_ExStart: OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc); - EVENT_OFF(nbr->t_ls_upd); + EVENT_OFF(nbr->t_ls_rxmt); EVENT_OFF(nbr->t_ls_req); break; case NSM_Exchange: - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, - nbr->v_ls_upd); if (!IS_SET_DD_MS(nbr->dd_flags)) EVENT_OFF(nbr->t_db_desc); break; diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 87aaccad92..2d15a7ecca 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -292,54 +292,66 @@ void ospf_ls_req_event(struct ospf_neighbor *nbr) event_add_event(master, ospf_ls_req_timer, nbr, 0, &nbr->t_ls_req); } -/* Cyclic timer function. Fist registered in ospf_nbr_new () in - ospf_neighbor.c */ -void ospf_ls_upd_timer(struct event *thread) +/* + * OSPF neighbor link state retransmission timer handler. Unicast + * unacknowledged LSAs to the neigbhors. + */ +void ospf_ls_rxmt_timer(struct event *thread) { struct ospf_neighbor *nbr; + int retransmit_interval, retransmit_window, rxmt_lsa_count = 0; nbr = EVENT_ARG(thread); - nbr->t_ls_upd = NULL; + nbr->t_ls_rxmt = NULL; + retransmit_interval = nbr->v_ls_rxmt; + retransmit_window = OSPF_IF_PARAM(nbr->oi, retransmit_window); /* Send Link State Update. */ if (ospf_ls_retransmit_count(nbr) > 0) { + struct ospf_lsa_list_entry *ls_rxmt_list_entry; + struct timeval current_time, latest_rxmt_time, next_rxmt_time; + struct timeval rxmt_interval = { retransmit_interval, 0 }; + struct timeval rxmt_window; struct list *update; - struct ospf_lsdb *lsdb; - int i; - int retransmit_interval; - retransmit_interval = - OSPF_IF_PARAM(nbr->oi, retransmit_interval); + /* + * Set the retransmission window based on the configured value + * in milliseconds. + */ + rxmt_window.tv_sec = retransmit_window / 1000; + rxmt_window.tv_usec = (retransmit_window % 1000) * 1000; + + /* + * Calculate the latest retransmit time for LSAs transmited in + * this timer pass by adding the retransmission window to the + * current time. Calculate the next retransmission time by adding + * the retransmit interval to the current time. + */ + monotime(¤t_time); + timeradd(¤t_time, &rxmt_window, &latest_rxmt_time); + timeradd(¤t_time, &rxmt_interval, &next_rxmt_time); - lsdb = &nbr->ls_rxmt; update = list_new(); + while ((ls_rxmt_list_entry = + ospf_lsa_list_first(&nbr->ls_rxmt_list))) { + if (timercmp(&ls_rxmt_list_entry->list_entry_time, + &latest_rxmt_time, >)) + break; - for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) { - struct route_table *table = lsdb->type[i].db; - struct route_node *rn; - - for (rn = route_top(table); rn; rn = route_next(rn)) { - struct ospf_lsa *lsa; - - if ((lsa = rn->info) != NULL) { - /* Don't retransmit an LSA if we - received it within - the last RxmtInterval seconds - this - is to allow the - neighbour a chance to acknowledge the - LSA as it may - have ben just received before the - retransmit timer - fired. This is a small tweak to what - is in the RFC, - but it will cut out out a lot of - retransmit traffic - - MAG */ - if (monotime_since(&lsa->tv_recv, NULL) - >= retransmit_interval * 1000000LL) - listnode_add(update, rn->info); - } - } + listnode_add(update, ls_rxmt_list_entry->lsa); + rxmt_lsa_count++; + + /* + * Set the next retransmit time for the LSA and move it + * to the end of the neighbor's retransmission list. + */ + ls_rxmt_list_entry->list_entry_time = next_rxmt_time; + ospf_lsa_list_del(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + ospf_lsa_list_add_tail(&nbr->ls_rxmt_list, + ls_rxmt_list_entry); + nbr->ls_rxmt_lsa++; + nbr->oi->ls_rxmt_lsa++; } if (listcount(update) > 0) @@ -348,23 +360,25 @@ void ospf_ls_upd_timer(struct event *thread) list_delete(&update); } + if (IS_DEBUG_OSPF_EVENT) + zlog_debug("RXmtL(%lu) NBR(%pI4(%s)) timer event - sent %u LSAs", + ospf_ls_retransmit_count(nbr), &nbr->router_id, + ospf_get_name(nbr->oi->ospf), rxmt_lsa_count); + /* Set LS Update retransmission timer. */ - OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd); + ospf_ls_retransmit_set_timer(nbr); } -void ospf_ls_ack_timer(struct event *thread) +void ospf_ls_ack_delayed_timer(struct event *thread) { struct ospf_interface *oi; oi = EVENT_ARG(thread); - oi->t_ls_ack = NULL; + oi->t_ls_ack_delayed = NULL; /* Send Link State Acknowledgment. */ - if (listcount(oi->ls_ack) > 0) + if (ospf_lsa_list_count(&oi->ls_ack_delayed)) ospf_ls_ack_send_delayed(oi); - - /* Set LS Ack timer. */ - OSPF_ISM_TIMER_ON(oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack); } #ifdef WANT_OSPF_WRITE_FRAGMENT @@ -1803,7 +1817,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa) && !current && ospf_check_nbr_status(oi->ospf)) { /* (4a) Response Link State Acknowledgment. */ - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); /* (4b) Discard LSA. */ if (IS_DEBUG_OSPF(lsa, LSA)) { @@ -1828,7 +1842,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, if (IS_LSA_MAXAGE(lsa)) { zlog_info("LSA[%s]: Boomerang effect?", dump_lsa_key(lsa)); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); ospf_lsa_discard(lsa); if (current != NULL && !IS_LSA_MAXAGE(current)) @@ -1862,7 +1876,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, SET_FLAG(lsa->flags, OSPF_LSA_SELF); - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); if (!ospf->gr_info.restart_in_progress) { ospf_opaque_self_originated_lsa_received( @@ -2001,9 +2015,8 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, */ if (oi->state == ISM_Backup) if (NBR_IS_DR(nbr)) - listnode_add( - oi->ls_ack, - ospf_lsa_lock(lsa)); + ospf_ls_ack_send_direct(nbr, + lsa); DISCARD_LSA(lsa, 6); } else @@ -2012,7 +2025,7 @@ static void ospf_ls_upd(struct ospf *ospf, struct ip *iph, receiving interface. */ { - ospf_ls_ack_send(nbr, lsa); + ospf_ls_ack_send_direct(nbr, lsa); DISCARD_LSA(lsa, 7); } } @@ -3314,17 +3327,36 @@ static int ospf_make_ls_upd(struct ospf_interface *oi, struct list *update, return length; } -static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, - struct stream *s) +static int ospf_make_ls_ack(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct stream *s) { - struct listnode *node, *nnode; + struct ospf_lsa_list_entry *ls_ack_list_first; + struct ospf_lsa_list_entry *ls_ack_list_entry; uint16_t length = OSPF_LS_ACK_MIN_SIZE; - unsigned long delta = OSPF_LSA_HEADER_SIZE; struct ospf_lsa *lsa; + struct in_addr first_dst_addr; - for (ALL_LIST_ELEMENTS(ack, node, nnode, lsa)) { + /* + * For direct LS Acks, assure the destination address doesn't + * change between queued acknowledgments. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + if (ls_ack_list_first) + first_dst_addr.s_addr = + ls_ack_list_first->list_entry_dst.s_addr; + } else + first_dst_addr.s_addr = INADDR_ANY; + + frr_each_safe (ospf_lsa_list, ls_ack_list, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; assert(lsa); + if (direct_ack && (ls_ack_list_entry->list_entry_dst.s_addr != + first_dst_addr.s_addr)) + break; + /* LS Ack packet overflows interface MTU * delta is just number of bytes required for * 1 LS Ack(1 LS Hdr) ospf_packet_max will return @@ -3333,19 +3365,46 @@ static int ospf_make_ls_ack(struct ospf_interface *oi, struct list *ack, * against ospf_packet_max to check if it can fit * another ls header in the same packet. */ - if ((length + delta) > ospf_packet_max(oi)) + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) break; stream_put(s, lsa->data, OSPF_LSA_HEADER_SIZE); length += OSPF_LSA_HEADER_SIZE; - listnode_delete(ack, lsa); - ospf_lsa_unlock(&lsa); /* oi->ls_ack_direct.ls_ack */ + if (delete_ack) { + ospf_lsa_list_del(ls_ack_list, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } } return length; } +/* + * On non-braodcast networks, the same LS acks must be sent to multiple + * neighbors and deletion must be deferred until after the LS Ack packet + * is sent to all neighbors. + */ +static void ospf_delete_ls_ack_delayed(struct ospf_interface *oi) +{ + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *lsa; + uint16_t length = OSPF_LS_ACK_MIN_SIZE; + + frr_each_safe (ospf_lsa_list, &oi->ls_ack_delayed, ls_ack_list_entry) { + lsa = ls_ack_list_entry->lsa; + assert(lsa); + if ((length + OSPF_LSA_HEADER_SIZE) > ospf_packet_max(oi)) + break; + + length += OSPF_LSA_HEADER_SIZE; + ospf_lsa_list_del(&oi->ls_ack_delayed, ls_ack_list_entry); + XFREE(MTYPE_OSPF_LSA_LIST, ls_ack_list_entry); + ospf_lsa_unlock(&lsa); + } +} + static void ospf_hello_send_sub(struct ospf_interface *oi, in_addr_t addr) { struct ospf_packet *op; @@ -3917,10 +3976,13 @@ void ospf_ls_upd_send(struct ospf_neighbor *nbr, struct list *update, int flag, &oi->t_ls_upd_event); } -static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, +static void ospf_ls_ack_send_list(struct ospf_interface *oi, + struct ospf_lsa_list_head *ls_ack_list, + bool direct_ack, bool delete_ack, struct in_addr dst) { struct ospf_packet *op; + struct ospf_lsa_list_entry *ls_ack_list_first; uint16_t length = OSPF_HEADER_SIZE; op = ospf_packet_new(oi->ifp->mtu); @@ -3928,8 +3990,18 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Prepare OSPF common header. */ ospf_make_header(OSPF_MSG_LS_ACK, oi, op->s); + /* Determine the destination address - for direct acks, + * the list entries always include the distination address. + */ + if (direct_ack) { + ls_ack_list_first = ospf_lsa_list_first(ls_ack_list); + op->dst.s_addr = ls_ack_list_first->list_entry_dst.s_addr; + } else + op->dst.s_addr = dst.s_addr; + /* Prepare OSPF Link State Acknowledgment body. */ - length += ospf_make_ls_ack(oi, ack, op->s); + length += ospf_make_ls_ack(oi, ls_ack_list, direct_ack, delete_ack, + op->s); /* Fill OSPF header. */ ospf_fill_header(oi, op->s, length); @@ -3937,14 +4009,6 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, /* Set packet length. */ op->length = length; - /* Decide destination address. */ - if (oi->type == OSPF_IFTYPE_POINTOPOINT || - (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && - !oi->p2mp_non_broadcast)) - op->dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - op->dst.s_addr = dst.s_addr; - /* Add packet to the interface output queue. */ ospf_packet_add(oi, op); @@ -3952,34 +4016,96 @@ static void ospf_ls_ack_send_list(struct ospf_interface *oi, struct list *ack, OSPF_ISM_WRITE_ON(oi->ospf); } -static void ospf_ls_ack_send_event(struct event *thread) +static void ospf_ls_ack_send_direct_event(struct event *thread) { struct ospf_interface *oi = EVENT_ARG(thread); + struct in_addr dst = { INADDR_ANY }; oi->t_ls_ack_direct = NULL; - while (listcount(oi->ls_ack_direct.ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack_direct.ls_ack, - oi->ls_ack_direct.dst); + while (ospf_lsa_list_count(&oi->ls_ack_direct)) + ospf_ls_ack_send_list(oi, &(oi->ls_ack_direct), true, true, dst); } -void ospf_ls_ack_send(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) +void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, struct ospf_lsa *lsa) { + struct ospf_lsa_list_entry *ls_ack_list_entry; struct ospf_interface *oi = nbr->oi; + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:Add LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue", + __func__, lsa->data->type, &lsa->data->id, + &lsa->data->adv_router, ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), &nbr->router_id, + IF_NAME(nbr->oi)); + + /* + * On Point-to-Multipoint broadcast-capabile interfaces, + * where direct acks from are sent to the ALLSPFRouters + * address and one direct ack send event, may include LSAs + * from multiple neighbors, there is a possibility of the same + * LSA being processed more than once in the same send event. + * In this case, the instances subsequent to the first can be + * ignored. + */ + if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && !oi->p2mp_non_broadcast) { + struct ospf_lsa_list_entry *ls_ack_list_entry; + struct ospf_lsa *ack_queue_lsa; + + frr_each (ospf_lsa_list, &oi->ls_ack_direct, ls_ack_list_entry) { + ack_queue_lsa = ls_ack_list_entry->lsa; + if ((lsa == ack_queue_lsa) || + ((lsa->data->type == ack_queue_lsa->data->type) && + (lsa->data->id.s_addr == + ack_queue_lsa->data->id.s_addr) && + (lsa->data->adv_router.s_addr == + ack_queue_lsa->data->adv_router.s_addr) && + (lsa->data->ls_seqnum == + ack_queue_lsa->data->ls_seqnum))) { + if (IS_DEBUG_OSPF(lsa, LSA_FLOODING)) + zlog_debug("%s:LSA[Type%d:%pI4:%pI4]: seq 0x%x age %u NBR %pI4 (%s) ack queue duplicate", + __func__, lsa->data->type, + &lsa->data->id, + &lsa->data->adv_router, + ntohl(lsa->data->ls_seqnum), + ntohs(lsa->data->ls_age), + &nbr->router_id, + IF_NAME(nbr->oi)); + return; + } + } + } + if (IS_GRACE_LSA(lsa)) { if (IS_DEBUG_OSPF_GR) zlog_debug("%s, Sending GRACE ACK to Restarter.", __func__); } - if (listcount(oi->ls_ack_direct.ls_ack) == 0) - oi->ls_ack_direct.dst = nbr->address.u.prefix4; + ls_ack_list_entry = XCALLOC(MTYPE_OSPF_LSA_LIST, + sizeof(struct ospf_lsa_list_entry)); - listnode_add(oi->ls_ack_direct.ls_ack, ospf_lsa_lock(lsa)); + /* + * Determine the destination address - Direct LS acknowledgments + * are sent the AllSPFRouters multicast address on Point-to-Point + * and Point-to-Multipoint broadcast-capable interfaces. For all other + * interface types, they are unicast directly to the neighbor. + */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT || + (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT && + !oi->p2mp_non_broadcast)) + ls_ack_list_entry->list_entry_dst.s_addr = + htonl(OSPF_ALLSPFROUTERS); + else + ls_ack_list_entry->list_entry_dst.s_addr = + nbr->address.u.prefix4.s_addr; + + ls_ack_list_entry->lsa = ospf_lsa_lock(lsa); + ospf_lsa_list_add_tail(&nbr->oi->ls_ack_direct, ls_ack_list_entry); - event_add_event(master, ospf_ls_ack_send_event, oi, 0, - &oi->t_ls_ack_direct); + if (oi->t_ls_ack_direct == NULL) + event_add_event(master, ospf_ls_ack_send_direct_event, oi, 0, + &oi->t_ls_ack_direct); } /* Send Link State Acknowledgment delayed. */ @@ -3996,33 +4122,39 @@ void ospf_ls_ack_send_delayed(struct ospf_interface *oi) struct ospf_neighbor *nbr; struct route_node *rn; - for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { - nbr = rn->info; + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) { + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; - if (!nbr) - continue; + if (!nbr) + continue; - if (nbr != oi->nbr_self && nbr->state >= NSM_Exchange) - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list( - oi, oi->ls_ack, - nbr->address.u.prefix4); + if (nbr != oi->nbr_self && + nbr->state >= NSM_Exchange) + ospf_ls_ack_send_list(oi, + &oi->ls_ack_delayed, + false, false, + nbr->address.u + .prefix4); + } + ospf_delete_ls_ack_delayed(oi); } - return; - } - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - dst.s_addr = oi->vl_data->peer_addr.s_addr; - else if (oi->state == ISM_DR || oi->state == ISM_Backup) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) - dst.s_addr = htonl(OSPF_ALLSPFROUTERS); - else - dst.s_addr = htonl(OSPF_ALLDROUTERS); + } else { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) + dst.s_addr = oi->vl_data->peer_addr.s_addr; + else if (oi->state == ISM_DR || oi->state == ISM_Backup) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) + dst.s_addr = htonl(OSPF_ALLSPFROUTERS); + else + dst.s_addr = htonl(OSPF_ALLDROUTERS); - while (listcount(oi->ls_ack)) - ospf_ls_ack_send_list(oi, oi->ls_ack, dst); + while (ospf_lsa_list_count(&oi->ls_ack_delayed)) + ospf_ls_ack_send_list(oi, &oi->ls_ack_delayed, false, + true, dst); + } } /* diff --git a/ospfd/ospf_packet.h b/ospfd/ospf_packet.h index 234738979e..84e4b027e6 100644 --- a/ospfd/ospf_packet.h +++ b/ospfd/ospf_packet.h @@ -135,13 +135,14 @@ extern void ospf_ls_upd_send(struct ospf_neighbor *, struct list *, int, int); extern void ospf_ls_upd_queue_send(struct ospf_interface *oi, struct list *update, struct in_addr addr, int send_lsupd_now); -extern void ospf_ls_ack_send(struct ospf_neighbor *, struct ospf_lsa *); +extern void ospf_ls_ack_send_direct(struct ospf_neighbor *nbr, + struct ospf_lsa *lsa); extern void ospf_ls_ack_send_delayed(struct ospf_interface *); extern void ospf_ls_retransmit(struct ospf_interface *, struct ospf_lsa *); extern void ospf_ls_req_event(struct ospf_neighbor *); -extern void ospf_ls_upd_timer(struct event *thread); -extern void ospf_ls_ack_timer(struct event *thread); +extern void ospf_ls_rxmt_timer(struct event *thread); +extern void ospf_ls_ack_delayed_timer(struct event *thread); extern void ospf_poll_timer(struct event *thread); extern void ospf_hello_reply_timer(struct event *thread); diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 7cb51976f5..7a7a684dd6 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -815,6 +815,7 @@ struct ospf_vl_config_data { int del_keychain; int hello_interval; /* Obvious what these are... */ int retransmit_interval; + int retransmit_window; int transmit_delay; int dead_interval; }; @@ -957,6 +958,12 @@ static int ospf_vl_set_timers(struct ospf_vl_data *vl_data, vl_config->retransmit_interval; } + if (vl_config->retransmit_window) { + SET_IF_PARAM(IF_DEF_PARAMS(ifp), retransmit_window); + IF_DEF_PARAMS(ifp)->retransmit_window = + vl_config->retransmit_window; + } + if (vl_config->transmit_delay) { SET_IF_PARAM(IF_DEF_PARAMS(ifp), transmit_delay); IF_DEF_PARAMS(ifp)->transmit_delay = vl_config->transmit_delay; @@ -1012,14 +1019,16 @@ static int ospf_vl_set(struct ospf *ospf, struct ospf_vl_config_data *vl_config) "Use null authentication\n" \ "Use message-digest authentication\n" -#define VLINK_HELPSTR_TIME_PARAM \ - "Time between HELLO packets\n" \ - "Seconds\n" \ - "Time between retransmitting lost link state advertisements\n" \ - "Seconds\n" \ - "Link state transmit delay\n" \ - "Seconds\n" \ - "Interval time after which a neighbor is declared down\n" \ +#define VLINK_HELPSTR_TIME_PARAM \ + "Time between HELLO packets\n" \ + "Seconds\n" \ + "Time between retransmitting lost link state advertisements\n" \ + "Seconds\n" \ + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" \ + "Milliseconds\n" \ + "Link state transmit delay\n" \ + "Seconds\n" \ + "Interval time after which a neighbor is declared down\n" \ "Seconds\n" #define VLINK_HELPSTR_AUTH_SIMPLE \ @@ -1204,7 +1213,7 @@ DEFUN (no_ospf_area_vlink, DEFUN (ospf_area_vlink_intervals, ospf_area_vlink_intervals_cmd, - "area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-10000)|transmit-delay (1-65535)|dead-interval (1-65535)}", VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) { @@ -1236,6 +1245,9 @@ DEFUN (ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = strtol(argv[++idx]->arg, NULL, 10); + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = strtol(argv[++idx]->arg, + NULL, 10); else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = strtol(argv[++idx]->arg, NULL, 10); @@ -1250,7 +1262,7 @@ DEFUN (ospf_area_vlink_intervals, DEFUN (no_ospf_area_vlink_intervals, no_ospf_area_vlink_intervals_cmd, - "no area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|transmit-delay (1-65535)|dead-interval (1-65535)}", + "no area virtual-link A.B.C.D {hello-interval (1-65535)|retransmit-interval (1-65535)|retransmit-window (20-1000)|transmit-delay (1-65535)|dead-interval (1-65535)}", NO_STR VLINK_HELPSTR_IPADDR VLINK_HELPSTR_TIME_PARAM) @@ -1282,6 +1294,9 @@ DEFUN (no_ospf_area_vlink_intervals, else if (strmatch(argv[idx]->text, "retransmit-interval")) vl_config.retransmit_interval = OSPF_RETRANSMIT_INTERVAL_DEFAULT; + else if (strmatch(argv[idx]->text, "retransmit-window")) + vl_config.retransmit_window = + OSPF_RETRANSMIT_WINDOW_DEFAULT; else if (strmatch(argv[idx]->text, "transmit-delay")) vl_config.transmit_delay = OSPF_TRANSMIT_DELAY_DEFAULT; else if (strmatch(argv[idx]->text, "dead-interval")) @@ -3576,8 +3591,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, struct route_node *rn; uint32_t bandwidth = ifp->bandwidth ? ifp->bandwidth : ifp->speed; struct ospf_if_params *params; - json_object *json_ois = NULL; - json_object *json_oi = NULL; /* Is interface up? */ if (use_json) { @@ -3628,33 +3641,17 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, } } - if (use_json) { - json_ois = json_object_new_object(); - json_object_object_add(json_interface_sub, "interfaceIp", - json_ois); - } - for (rn = route_top(IF_OIFS(ifp)); rn; rn = route_next(rn)) { struct ospf_interface *oi = rn->info; if (oi == NULL) continue; -#if CONFDATE > 20240601 - CPP_NOTICE( - "Use all fields following ospfEnabled from interfaceIp hierarchy") -#endif - - if (use_json) - json_oi = json_object_new_object(); - if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) { - if (use_json) { + if (use_json) json_object_boolean_true_add(json_interface_sub, "ifUnnumbered"); - json_object_boolean_true_add(json_oi, - "ifUnnumbered"); - } else + else vty_out(vty, " This interface is UNNUMBERED,"); } else { struct in_addr dest; @@ -3668,13 +3665,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "ipAddressPrefixlen", oi->address->prefixlen); - - json_object_string_addf( - json_oi, "ipAddress", "%pI4", - &oi->address->u.prefix4); - json_object_int_add(json_oi, - "ipAddressPrefixlen", - oi->address->prefixlen); } else vty_out(vty, " Internet Address %pFX,", oi->address); @@ -3700,26 +3690,14 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_string_add(json_interface_sub, "ospfIfType", dstr); - json_object_string_add(json_oi, "ospfIfType", - dstr); - - if (oi->type == OSPF_IFTYPE_VIRTUALLINK) { + if (oi->type == OSPF_IFTYPE_VIRTUALLINK) json_object_string_addf( json_interface_sub, "vlinkPeer", "%pI4", &dest); - - json_object_string_addf(json_oi, - "vlinkPeer", - "%pI4", &dest); - } else { + else json_object_string_addf( json_interface_sub, "localIfUsed", "%pI4", &dest); - - json_object_string_addf(json_oi, - "localIfUsed", - "%pI4", &dest); - } } else vty_out(vty, " %s %pI4,", dstr, &dest); @@ -3728,16 +3706,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_string_add(json_interface_sub, "area", ospf_area_desc_string(oi->area)); - json_object_string_add(json_oi, "area", - ospf_area_desc_string(oi->area)); - - if (OSPF_IF_PARAM(oi, mtu_ignore)) { - json_object_boolean_true_add( - json_oi, "mtuMismatchDetect"); + if (OSPF_IF_PARAM(oi, mtu_ignore)) json_object_boolean_true_add( json_interface_sub, "mtuMismatchDetect"); - } json_object_string_addf(json_interface_sub, "routerId", "%pI4", &ospf->router_id); @@ -3754,18 +3726,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, oi->state, NULL)); json_object_int_add(json_interface_sub, "priority", PRIORITY(oi)); - - json_object_string_addf(json_oi, "routerId", "%pI4", - &ospf->router_id); - json_object_string_add(json_oi, "networkType", - ospf_network_type_str[oi->type]); - json_object_int_add(json_oi, "cost", oi->output_cost); - json_object_int_add(json_oi, "transmitDelaySecs", - OSPF_IF_PARAM(oi, transmit_delay)); - json_object_string_add(json_oi, "state", - lookup_msg(ospf_ism_state_msg, - oi->state, NULL)); - json_object_int_add(json_oi, "priority", PRIORITY(oi)); json_object_boolean_add( json_interface_sub, "opaqueCapable", OSPF_IF_PARAM(oi, opaque_capable)); @@ -3809,13 +3769,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_interface_sub, "drAddress", "%pI4", &nbr->address.u.prefix4); - - json_object_string_addf( - json_oi, "drId", "%pI4", - &nbr->router_id); - json_object_string_addf( - json_oi, "drAddress", "%pI4", - &nbr->address.u.prefix4); } else { vty_out(vty, " Designated Router (ID) %pI4", @@ -3841,13 +3794,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_interface_sub, "bdrAddress", "%pI4", &nbr->address.u.prefix4); - - json_object_string_addf( - json_oi, "bdrId", "%pI4", - &nbr->router_id); - json_object_string_addf( - json_oi, "bdrAddress", "%pI4", - &nbr->address.u.prefix4); } else { vty_out(vty, " Backup Designated Router (ID) %pI4,", @@ -3863,43 +3809,28 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, if (oi->params && ntohl(oi->params->network_lsa_seqnum) != OSPF_INITIAL_SEQUENCE_NUMBER) { - if (use_json) { + if (use_json) json_object_int_add( json_interface_sub, "networkLsaSequence", ntohl(oi->params->network_lsa_seqnum)); - - json_object_int_add( - json_oi, "networkLsaSequence", - ntohl(oi->params->network_lsa_seqnum)); - } else { + else vty_out(vty, " Saved Network-LSA sequence number 0x%x\n", ntohl(oi->params->network_lsa_seqnum)); - } } if (use_json) { if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS) || OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { - if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) { + if (OI_MEMBER_CHECK(oi, MEMBER_ALLROUTERS)) json_object_boolean_true_add( json_interface_sub, "mcastMemberOspfAllRouters"); - - json_object_boolean_true_add( - json_oi, - "mcastMemberOspfAllRouters"); - } - if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) { + if (OI_MEMBER_CHECK(oi, MEMBER_DROUTERS)) json_object_boolean_true_add( json_interface_sub, "mcastMemberOspfDesignatedRouters"); - - json_object_boolean_true_add( - json_oi, - "mcastMemberOspfDesignatedRouters"); - } } } else { vty_out(vty, " Multicast group memberships:"); @@ -3915,23 +3846,14 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, } if (use_json) { - if (OSPF_IF_PARAM(oi, fast_hello) == 0) { + if (OSPF_IF_PARAM(oi, fast_hello) == 0) json_object_int_add( json_interface_sub, "timerMsecs", OSPF_IF_PARAM(oi, v_hello) * 1000); - - json_object_int_add(json_oi, "timerMsecs", - OSPF_IF_PARAM(oi, v_hello) * - 1000); - } else { + else json_object_int_add( json_interface_sub, "timerMsecs", 1000 / OSPF_IF_PARAM(oi, fast_hello)); - - json_object_int_add( - json_oi, "timerMsecs", - 1000 / OSPF_IF_PARAM(oi, fast_hello)); - } json_object_int_add(json_interface_sub, "timerDeadSecs", OSPF_IF_PARAM(oi, v_wait)); json_object_int_add(json_interface_sub, "timerWaitSecs", @@ -3939,14 +3861,10 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add( json_interface_sub, "timerRetransmitSecs", OSPF_IF_PARAM(oi, retransmit_interval)); - - json_object_int_add(json_oi, "timerDeadSecs", - OSPF_IF_PARAM(oi, v_wait)); - json_object_int_add(json_oi, "timerWaitSecs", - OSPF_IF_PARAM(oi, v_wait)); - json_object_int_add( - json_oi, "timerRetransmitSecs", - OSPF_IF_PARAM(oi, retransmit_interval)); + json_object_int_add(json_interface_sub, + "timerRetransmitWindowMsecs", + OSPF_IF_PARAM(oi, + retransmit_window)); } else { vty_out(vty, " Timer intervals configured,"); vty_out(vty, " Hello "); @@ -3975,23 +3893,17 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "timerHelloInMsecs", time_store); - json_object_int_add(json_oi, - "timerHelloInMsecs", - time_store); } else vty_out(vty, " Hello due in %s\n", ospf_timer_dump(oi->t_hello, timebuf, sizeof(timebuf))); } else /* passive-interface is set */ { - if (use_json) { + if (use_json) json_object_boolean_true_add( json_interface_sub, "timerPassiveIface"); - - json_object_boolean_true_add( - json_oi, "timerPassiveIface"); - } else + else vty_out(vty, " No Hellos (Passive interface)\n"); } @@ -4002,11 +3914,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_int_add(json_interface_sub, "nbrAdjacentCount", ospf_nbr_count(oi, NSM_Full)); - - json_object_int_add(json_oi, "nbrCount", - ospf_nbr_count(oi, 0)); - json_object_int_add(json_oi, "nbrAdjacentCount", - ospf_nbr_count(oi, NSM_Full)); } else vty_out(vty, " Neighbor Count is %d, Adjacent neighbor count is %d\n", @@ -4016,14 +3923,11 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, params = IF_DEF_PARAMS(ifp); if (params && OSPF_IF_PARAM_CONFIGURED(params, v_gr_hello_delay)) { - if (use_json) { + if (use_json) json_object_int_add(json_interface_sub, "grHelloDelaySecs", params->v_gr_hello_delay); - - json_object_int_add(json_oi, "grHelloDelaySecs", - params->v_gr_hello_delay); - } else + else vty_out(vty, " Graceful Restart hello delay: %us\n", params->v_gr_hello_delay); @@ -4031,85 +3935,64 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, ospf_interface_bfd_show(vty, ifp, json_interface_sub); - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "prefixSuppression", OSPF_IF_PARAM(oi, prefix_suppression)); - json_object_boolean_add(json_oi, "prefixSuppression", - OSPF_IF_PARAM(oi, - prefix_suppression)); - } else { - if (OSPF_IF_PARAM(oi, prefix_suppression)) - vty_out(vty, - " Suppress advertisement of interface IP prefix\n"); - } + else if (OSPF_IF_PARAM(oi, prefix_suppression)) + vty_out(vty, + " Suppress advertisement of interface IP prefix\n"); /* OSPF Authentication information */ ospf_interface_auth_show(vty, oi, json_interface_sub, use_json); - ospf_interface_auth_show(vty, oi, json_oi, use_json); - /* Point-to-Multipoint Interface options. */ if (oi->type == OSPF_IFTYPE_POINTOMULTIPOINT) { - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "p2mpDelayReflood", oi->p2mp_delay_reflood); - - json_object_boolean_add(json_oi, - "p2mpDelayReflood", - oi->p2mp_delay_reflood); - } else { + else vty_out(vty, " %sDelay reflooding LSAs received on P2MP interface\n", oi->p2mp_delay_reflood ? "" : "Don't "); - } - if (use_json) { + if (use_json) json_object_boolean_add(json_interface_sub, "p2mpNonBroadcast", oi->p2mp_non_broadcast); - - json_object_boolean_add(json_oi, - "p2mpNonBroadcast", - oi->p2mp_non_broadcast); - } else { + else vty_out(vty, " P2MP interface does %ssupport broadcast\n", oi->p2mp_non_broadcast ? "not " : ""); - } } - /* Add ospf_interface object to main json blob using SIP as key - */ - if (use_json) - json_object_object_addf(json_ois, json_oi, "%pI4", - &oi->address->u.prefix4); - if (oi->nbr_filter) { - if (use_json) { + if (use_json) json_object_string_add(json_interface_sub, "nbrFilterPrefixList", prefix_list_name( oi->nbr_filter)); - json_object_string_add(json_oi, - "nbrFilterPrefixList", - prefix_list_name( - oi->nbr_filter)); - } else + else vty_out(vty, " Neighbor filter prefix-list: %s\n", prefix_list_name(oi->nbr_filter)); } else { - if (use_json) { + if (use_json) json_object_string_add(json_interface_sub, "nbrFilterPrefixList", "N/A"); - json_object_string_add(json_oi, - "nbrFilterPrefixList", - "N/A"); - } } + + /* Non-Traffic interface counters + */ + if (use_json) + json_object_int_add(json_interface_sub, + "lsaRetransmissions", + oi->ls_rxmt_lsa); + else + vty_out(vty, " LSA retransmissions: %u\n", + oi->ls_rxmt_lsa); } } @@ -5323,12 +5206,20 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, lookup_msg(ospf_ism_state_msg, ospf_nbr_ism_state(nbr), NULL)); } + /* Show state changes. */ if (use_json) json_object_int_add(json_neigh, "stateChangeCounter", nbr->state_change); else - vty_out(vty, " %d state changes\n", nbr->state_change); + vty_out(vty, " %d state changes\n", nbr->state_change); + + /* Show LSA retransmissions. */ + if (use_json) + json_object_int_add(json_neigh, "lsaRetransmissions", + nbr->ls_rxmt_lsa); + else + vty_out(vty, " %u LSA retransmissions\n", nbr->ls_rxmt_lsa); if (nbr->ts_last_progress.tv_sec || nbr->ts_last_progress.tv_usec) { struct timeval res; @@ -5377,7 +5268,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (DR(oi).s_addr == INADDR_ANY) { if (!use_json) vty_out(vty, - " No designated router on this network\n"); + " No designated router on this network\n"); } else { nbr_dr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi)); if (nbr_dr) { @@ -5396,14 +5287,14 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, if (nbr_bdr == NULL) { if (!use_json) vty_out(vty, - " No backup designated router on this network\n"); + " No backup designated router on this network\n"); } else { if (use_json) json_object_string_addf(json_neigh, "routerDesignatedBackupId", "%pI4", &nbr_bdr->router_id); else - vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); + vty_out(vty, " BDR is %pI4\n", &nbr_bdr->router_id); } /* Show options. */ @@ -5493,7 +5384,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, /* Show Link State Update Retransmission thread. */ if (use_json) { - if (nbr->t_ls_upd != NULL) + if (nbr->t_ls_rxmt != NULL) json_object_string_add( json_neigh, "threadLinkStateUpdateRetransmission", @@ -5501,7 +5392,7 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, } else vty_out(vty, " Thread Link State Update Retransmission %s\n\n", - nbr->t_ls_upd != NULL ? "on" : "off"); + nbr->t_ls_rxmt != NULL ? "on" : "off"); if (!use_json) { vty_out(vty, " Graceful restart Helper info:\n"); @@ -8139,7 +8030,7 @@ static void ospf_nbr_timer_update(struct ospf_interface *oi) nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait); nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval); nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval); - nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval); + nbr->v_ls_rxmt = OSPF_IF_PARAM(oi, retransmit_interval); } } @@ -8874,6 +8765,40 @@ DEFUN_HIDDEN (no_ospf_retransmit_interval, return no_ip_ospf_retransmit_interval(self, vty, argc, argv); } +DEFPY(ip_ospf_retransmit_window, ip_ospf_retransmit_window_addr_cmd, + "[no] ip ospf retransmit-window ![(20-1000)]$retransmit-window [A.B.C.D]$ip_addr", NO_STR + "IP Information\n" + "OSPF interface commands\n" + "Window for LSA retransmit - Retransmit LSAs expiring in this window\n" + "Milliseconds\n" + "Address of interface\n") +{ + VTY_DECLVAR_CONTEXT(interface, ifp); + struct ospf_if_params *params; + + params = IF_DEF_PARAMS(ifp); + + if (ip_addr.s_addr != INADDR_ANY) { + params = ospf_get_if_params(ifp, ip_addr); + ospf_if_update_params(ifp, ip_addr); + } + + if (no) { + UNSET_IF_PARAM(params, retransmit_window); + params->retransmit_window = OSPF_RETRANSMIT_WINDOW_DEFAULT; + } else { + SET_IF_PARAM(params, retransmit_window); + params->retransmit_window = retransmit_window; + } + + /* + * There is nothing to do when the retransmit-window changes, any + * change will take effect the next time the interface LSA retransmision + * timer expires. + */ + return CMD_SUCCESS; +} + DEFPY (ip_ospf_gr_hdelay, ip_ospf_gr_hdelay_cmd, "ip ospf graceful-restart hello-delay (1-1800)", @@ -12356,6 +12281,17 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) vty_out(vty, "\n"); } + /* Retransmit Window print. */ + if (OSPF_IF_PARAM_CONFIGURED(params, retransmit_window) && + params->retransmit_window != + OSPF_RETRANSMIT_WINDOW_DEFAULT) { + vty_out(vty, " ip ospf retransmit-window %u", + params->retransmit_window); + if (params != IF_DEF_PARAMS(ifp) && rn) + vty_out(vty, " %pI4", &rn->p.u.prefix4); + vty_out(vty, "\n"); + } + /* Transmit Delay print. */ if (OSPF_IF_PARAM_CONFIGURED(params, transmit_delay) && params->transmit_delay @@ -12713,19 +12649,22 @@ static int config_write_virtual_link(struct vty *vty, struct ospf *ospf) oi = vl_data->vl_oi; /* timers */ - if (OSPF_IF_PARAM(oi, v_hello) - != OSPF_HELLO_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, v_wait) - != OSPF_ROUTER_DEAD_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, retransmit_interval) - != OSPF_RETRANSMIT_INTERVAL_DEFAULT - || OSPF_IF_PARAM(oi, transmit_delay) - != OSPF_TRANSMIT_DELAY_DEFAULT) + if (OSPF_IF_PARAM(oi, v_hello) != + OSPF_HELLO_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, v_wait) != + OSPF_ROUTER_DEAD_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_interval) != + OSPF_RETRANSMIT_INTERVAL_DEFAULT || + OSPF_IF_PARAM(oi, retransmit_window) != + OSPF_RETRANSMIT_WINDOW_DEFAULT || + OSPF_IF_PARAM(oi, transmit_delay) != + OSPF_TRANSMIT_DELAY_DEFAULT) vty_out(vty, - " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d transmit-delay %d dead-interval %d\n", + " area %s virtual-link %pI4 hello-interval %d retransmit-interval %d retransmit-window %d transmit-delay %d dead-interval %d\n", buf, &vl_data->vl_peer, OSPF_IF_PARAM(oi, v_hello), OSPF_IF_PARAM(oi, retransmit_interval), + OSPF_IF_PARAM(oi, retransmit_window), OSPF_IF_PARAM(oi, transmit_delay), OSPF_IF_PARAM(oi, v_wait)); else @@ -13258,6 +13197,9 @@ static void ospf_vty_if_init(void) install_element(INTERFACE_NODE, &no_ip_ospf_retransmit_interval_addr_cmd); + /* "ip ospf retransmit-window" commands. */ + install_element(INTERFACE_NODE, &ip_ospf_retransmit_window_addr_cmd); + /* "ip ospf transmit-delay" commands. */ install_element(INTERFACE_NODE, &ip_ospf_transmit_delay_addr_cmd); install_element(INTERFACE_NODE, &no_ip_ospf_transmit_delay_addr_cmd); diff --git a/pathd/pathd.c b/pathd/pathd.c index 6c13503c7d..9bb7dbae84 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -148,6 +148,16 @@ void srte_segment_list_del(struct srte_segment_list *segment_list) XFREE(MTYPE_PATH_SEGMENT_LIST, segment_list); } +static void srte_segment_list_terminate(void) +{ + while (!RB_EMPTY(srte_segment_list_head, &srte_segment_lists)) { + struct srte_segment_list *sl = RB_ROOT(srte_segment_list_head, + &srte_segment_lists); + + srte_segment_list_del(sl); + } +} + /** * Search for a segment list by name. * @@ -1281,6 +1291,11 @@ void pathd_shutdown(void) { path_ted_teardown(); srte_clean_zebra(); + + srte_segment_list_terminate(); + + vrf_terminate(); + frr_fini(); } diff --git a/pimd/pim6_cmd.c b/pimd/pim6_cmd.c index ec912700d1..99f1474712 100644 --- a/pimd/pim6_cmd.c +++ b/pimd/pim6_cmd.c @@ -41,45 +41,207 @@ static struct cmd_node debug_node = { .config_write = pim_debug_config_write, }; -DEFPY (ipv6_pim_joinprune_time, - ipv6_pim_joinprune_time_cmd, - "ipv6 pim join-prune-interval (1-65535)$jpi", - IPV6_STR - PIM_STR +DEFPY_NOSH (router_pim6, + router_pim6_cmd, + "router pim6 [vrf NAME]", + "Enable a routing process\n" + "Start PIM6 configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) + return CMD_WARNING_CONFIG_FAILED; + + VTY_PUSH_XPATH(PIM6_NODE, xpath); + + return CMD_SUCCESS; +} + +DEFPY (no_router_pim6, + no_router_pim6_cmd, + "no router pim6 [vrf NAME]", + NO_STR + "Enable a routing process\n" + "Start PIM6 configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY (pim6_joinprune_time, + pim6_joinprune_time_cmd, + "join-prune-interval (1-65535)$jpi", "Join Prune Send Interval\n" "Seconds\n") { return pim_process_join_prune_cmd(vty, jpi_str); } +DEFPY_ATTR(ipv6_joinprune_time, + ipv6_pim_joinprune_time_cmd, + "ipv6 pim join-prune-interval (1-65535)$jpi", + IPV6_STR PIM_STR + "Join Prune Send Interval\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_join_prune_cmd(vty, jpi_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_joinprune_time, - no_ipv6_pim_joinprune_time_cmd, - "no ipv6 pim join-prune-interval [(1-65535)]", +DEFPY (no_pim6_joinprune_time, + no_pim6_joinprune_time_cmd, + "no join-prune-interval [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { return pim_process_no_join_prune_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_joinprune_time, + no_ipv6_pim_joinprune_time_cmd, + "no ipv6 pim join-prune-interval [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_join_prune_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_spt_switchover_infinity, - ipv6_pim_spt_switchover_infinity_cmd, - "ipv6 pim spt-switchover infinity-and-beyond", - IPV6_STR - PIM_STR +DEFPY (pim6_spt_switchover_infinity, + pim6_spt_switchover_infinity_cmd, + "spt-switchover infinity-and-beyond", "SPT-Switchover\n" "Never switch to SPT Tree\n") { return pim_process_spt_switchover_infinity_cmd(vty); } +DEFPY_ATTR(ipv6_spt_switchover_infinity, + ipv6_pim_spt_switchover_infinity_cmd, + "ipv6 pim spt-switchover infinity-and-beyond", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_infinity_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_spt_switchover_infinity_plist, - ipv6_pim_spt_switchover_infinity_plist_cmd, - "ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", - IPV6_STR - PIM_STR +DEFPY (pim6_spt_switchover_infinity_plist, + pim6_spt_switchover_infinity_plist_cmd, + "spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", "SPT-Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -87,25 +249,104 @@ DEFPY (ipv6_pim_spt_switchover_infinity_plist, { return pim_process_spt_switchover_prefixlist_cmd(vty, plist); } +DEFPY_ATTR(ipv6_spt_switchover_infinity_plist, + ipv6_pim_spt_switchover_infinity_plist_cmd, + "ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME$plist", + IPV6_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_spt_switchover_infinity, - no_ipv6_pim_spt_switchover_infinity_cmd, - "no ipv6 pim spt-switchover infinity-and-beyond", +DEFPY (no_pim6_spt_switchover_infinity, + no_pim6_spt_switchover_infinity_cmd, + "no spt-switchover infinity-and-beyond", NO_STR - IPV6_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n") { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity, + no_ipv6_pim_spt_switchover_infinity_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, - no_ipv6_pim_spt_switchover_infinity_plist_cmd, - "no ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", +DEFPY (no_pim6_spt_switchover_infinity_plist, + no_pim6_spt_switchover_infinity_plist_cmd, + "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", NO_STR - IPV6_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -113,100 +354,453 @@ DEFPY (no_ipv6_pim_spt_switchover_infinity_plist, { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_spt_switchover_infinity_plist, + no_ipv6_pim_spt_switchover_infinity_plist_cmd, + "no ipv6 pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST6_NAME", + NO_STR + IPV6_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_packets, - ipv6_pim_packets_cmd, - "ipv6 pim packets (1-255)", - IPV6_STR - PIM_STR +DEFPY (pim6_packets, + pim6_packets_cmd, + "packets (1-255)", "packets to process at one time per fd\n" "Number of packets\n") { return pim_process_pim_packet_cmd(vty, packets_str); } +DEFPY_ATTR(ipv6_pim_packets, + ipv6_pim_packets_cmd, + "ipv6 pim packets (1-255)", + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + "Number of packets\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_pim_packet_cmd(vty, packets_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_packets, - no_ipv6_pim_packets_cmd, - "no ipv6 pim packets [(1-255)]", +DEFPY (no_pim6_packets, + no_pim6_packets_cmd, + "no packets [(1-255)]", NO_STR - IPV6_STR - PIM_STR "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { return pim_process_no_pim_packet_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_packets, + no_ipv6_pim_packets_cmd, + "no ipv6 pim packets [(1-255)]", + NO_STR + IPV6_STR + PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_keep_alive, - ipv6_pim_keep_alive_cmd, - "ipv6 pim keep-alive-timer (1-65535)$kat", - IPV6_STR - PIM_STR + ret = pim_process_no_pim_packet_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_keep_alive, + pim6_keep_alive_cmd, + "keep-alive-timer (1-65535)$kat", "Keep alive Timer\n" "Seconds\n") { return pim_process_keepalivetimer_cmd(vty, kat_str); } +DEFPY_ATTR(ipv6_pim_keep_alive, + ipv6_pim_keep_alive_cmd, + "ipv6 pim keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_keepalivetimer_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_keep_alive, - no_ipv6_pim_keep_alive_cmd, - "no ipv6 pim keep-alive-timer [(1-65535)]", +DEFPY (no_pim6_keep_alive, + no_pim6_keep_alive_cmd, + "no keep-alive-timer [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_keepalivetimer_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_keep_alive, + no_ipv6_pim_keep_alive_cmd, + "no ipv6 pim keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_keepalivetimer_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ipv6_pim_rp_keep_alive, - ipv6_pim_rp_keep_alive_cmd, - "ipv6 pim rp keep-alive-timer (1-65535)$kat", - IPV6_STR - PIM_STR +DEFPY (pim6_rp_keep_alive, + pim6_rp_keep_alive_cmd, + "rp keep-alive-timer (1-65535)$kat", "Rendezvous Point\n" "Keep alive Timer\n" "Seconds\n") { return pim_process_rp_kat_cmd(vty, kat_str); } +DEFPY_ATTR(ipv6_pim_rp_keep_alive, + ipv6_pim_rp_keep_alive_cmd, + "ipv6 pim rp keep-alive-timer (1-65535)$kat", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_kat_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp_keep_alive, - no_ipv6_pim_rp_keep_alive_cmd, - "no ipv6 pim rp keep-alive-timer [(1-65535)]", +DEFPY (no_pim6_rp_keep_alive, + no_pim6_rp_keep_alive_cmd, + "no rp keep-alive-timer [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_rp_kat_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_rp_keep_alive, + no_ipv6_pim_rp_keep_alive_cmd, + "no ipv6 pim rp keep-alive-timer [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_register_suppress, - ipv6_pim_register_suppress_cmd, - "ipv6 pim register-suppress-time (1-65535)$rst", - IPV6_STR - PIM_STR + ret = pim_process_no_rp_kat_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_register_suppress, + pim6_register_suppress_cmd, + "register-suppress-time (1-65535)$rst", "Register Suppress Timer\n" "Seconds\n") { return pim_process_register_suppress_cmd(vty, rst_str); } +DEFPY_ATTR(ipv6_pim_register_suppress, + ipv6_pim_register_suppress_cmd, + "ipv6 pim register-suppress-time (1-65535)$rst", + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_register_suppress_cmd(vty, rst_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_register_suppress, - no_ipv6_pim_register_suppress_cmd, - "no ipv6 pim register-suppress-time [(1-65535)]", +DEFPY (no_pim6_register_suppress, + no_pim6_register_suppress_cmd, + "no register-suppress-time [(1-65535)]", NO_STR - IPV6_STR - PIM_STR "Register Suppress Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_register_suppress_cmd(vty); } +DEFPY_ATTR(no_ipv6_pim_register_suppress, + no_ipv6_pim_register_suppress_cmd, + "no ipv6 pim register-suppress-time [(1-65535)]", + NO_STR + IPV6_STR + PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_register_suppress_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (interface_ipv6_pim, interface_ipv6_pim_cmd, @@ -405,11 +999,9 @@ DEFPY (interface_no_ipv6_mroute, source_str); } -DEFPY (ipv6_pim_rp, - ipv6_pim_rp_cmd, - "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", - IPV6_STR - PIM_STR +DEFPY (pim6_rp, + pim6_rp_cmd, + "rp X:X::X:X$rp [X:X::X:X/M]$gp", "Rendezvous Point\n" "ipv6 address of RP\n" "Group Address range to cover\n") @@ -418,13 +1010,53 @@ DEFPY (ipv6_pim_rp, return pim_process_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(ipv6_pim_rp, + ipv6_pim_rp_cmd, + "ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp, - no_ipv6_pim_rp_cmd, - "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", +DEFPY (no_pim6_rp, + no_pim6_rp_cmd, + "no rp X:X::X:X$rp [X:X::X:X/M]$gp", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "ipv6 address of RP\n" "Group Address range to cover\n") @@ -433,12 +1065,53 @@ DEFPY (no_ipv6_pim_rp, return pim_process_no_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(no_ipv6_pim_rp, + no_ipv6_pim_rp_cmd, + "no ipv6 pim rp X:X::X:X$rp [X:X::X:X/M]$gp", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *group_str = (gp_str) ? gp_str : "FF00::0/8"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } -DEFPY (ipv6_pim_rp_prefix_list, - ipv6_pim_rp_prefix_list_cmd, - "ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", - IPV6_STR - PIM_STR + ret = pim_process_no_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim6_rp_prefix_list, + pim6_rp_prefix_list_cmd, + "rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", "Rendezvous Point\n" "ipv6 address of RP\n" "group prefix-list filter\n" @@ -446,13 +1119,53 @@ DEFPY (ipv6_pim_rp_prefix_list, { return pim_process_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(ipv6_pim_rp_prefix_list, + ipv6_pim_rp_prefix_list_cmd, + "ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ipv6_pim_rp_prefix_list, - no_ipv6_pim_rp_prefix_list_cmd, - "no ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", +DEFPY (no_pim6_rp_prefix_list, + no_pim6_rp_prefix_list_cmd, + "no rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", NO_STR - IPV6_STR - PIM_STR "Rendezvous Point\n" "ipv6 address of RP\n" "group prefix-list filter\n" @@ -460,6 +1173,49 @@ DEFPY (no_ipv6_pim_rp_prefix_list, { return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(no_ipv6_pim_rp_prefix_list, + no_ipv6_pim_rp_prefix_list_cmd, + "no ipv6 pim rp X:X::X:X$rp prefix-list PREFIXLIST6_NAME$plist", + NO_STR + IPV6_STR + PIM_STR + "Rendezvous Point\n" + "ipv6 address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (ipv6_pim_bsm, ipv6_pim_bsm_cmd, @@ -503,10 +1259,9 @@ DEFPY (no_ipv6_pim_ucast_bsm, return pim_process_no_unicast_bsm_cmd(vty); } -DEFPY (ipv6_ssmpingd, - ipv6_ssmpingd_cmd, - "ipv6 ssmpingd [X:X::X:X]$source", - IPV6_STR +DEFPY (pim6_ssmpingd, + pim6_ssmpingd_cmd, + "ssmpingd [X:X::X:X]$source", CONF_SSMPINGD_STR "Source address\n") { @@ -514,20 +1269,99 @@ DEFPY (ipv6_ssmpingd, return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); } +DEFPY_ATTR(ipv6_ssmpingd, + ipv6_ssmpingd_cmd, + "ipv6 ssmpingd [X:X::X:X]$source", + IPV6_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *src_str = (source_str) ? source_str : "::"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); -DEFPY (no_ipv6_ssmpingd, - no_ipv6_ssmpingd_cmd, - "no ipv6 ssmpingd [X:X::X:X]$source", - NO_STR - IPV6_STR - CONF_SSMPINGD_STR - "Source address\n") + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim6_ssmpingd, + no_pim6_ssmpingd_cmd, + "no ssmpingd [X:X::X:X]$source", + NO_STR + CONF_SSMPINGD_STR + "Source address\n") { const char *src_str = (source_str) ? source_str : "::"; return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); } +DEFPY_ATTR(no_ipv6_ssmpingd, + no_ipv6_ssmpingd_cmd, + "no ipv6 ssmpingd [X:X::X:X]$source", + NO_STR + IPV6_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *src_str = (source_str) ? source_str : "::"; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM6_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (interface_ipv6_mld_join, interface_ipv6_mld_join_cmd, @@ -1733,12 +2567,16 @@ DEFPY (debug_pimv6_bsm, return CMD_SUCCESS; } -void pim_cmd_init(void) -{ - if_cmd_init(pim_interface_config_write); - - install_node(&debug_node); +struct cmd_node pim6_node = { + .name = "pim6", + .node = PIM6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim6)# ", + .config_write = pim_router_config_write, +}; +static void pim_install_deprecated(void) +{ install_element(CONFIG_NODE, &ipv6_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ipv6_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &ipv6_pim_spt_switchover_infinity_cmd); @@ -1753,6 +2591,60 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ipv6_pim_rp_keep_alive_cmd); install_element(CONFIG_NODE, &ipv6_pim_register_suppress_cmd); install_element(CONFIG_NODE, &no_ipv6_pim_register_suppress_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); + install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); + install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); + install_element(VRF_NODE, &ipv6_ssmpingd_cmd); + install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); + install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); +} + +void pim_cmd_init(void) +{ + if_cmd_init(pim_interface_config_write); + + install_node(&debug_node); + + pim_install_deprecated(); + + install_element(CONFIG_NODE, &router_pim6_cmd); + install_element(CONFIG_NODE, &no_router_pim6_cmd); + + install_node(&pim6_node); + install_default(PIM6_NODE); + + install_element(PIM6_NODE, &pim6_joinprune_time_cmd); + install_element(PIM6_NODE, &no_pim6_joinprune_time_cmd); + install_element(PIM6_NODE, &pim6_spt_switchover_infinity_cmd); + install_element(PIM6_NODE, &pim6_spt_switchover_infinity_plist_cmd); + install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_cmd); + install_element(PIM6_NODE, &no_pim6_spt_switchover_infinity_plist_cmd); + install_element(PIM6_NODE, &pim6_packets_cmd); + install_element(PIM6_NODE, &no_pim6_packets_cmd); + install_element(PIM6_NODE, &pim6_keep_alive_cmd); + install_element(PIM6_NODE, &no_pim6_keep_alive_cmd); + install_element(PIM6_NODE, &pim6_rp_keep_alive_cmd); + install_element(PIM6_NODE, &no_pim6_rp_keep_alive_cmd); + install_element(PIM6_NODE, &pim6_register_suppress_cmd); + install_element(PIM6_NODE, &no_pim6_register_suppress_cmd); + install_element(PIM6_NODE, &pim6_rp_cmd); + install_element(PIM6_NODE, &no_pim6_rp_cmd); + install_element(PIM6_NODE, &pim6_rp_prefix_list_cmd); + install_element(PIM6_NODE, &no_pim6_rp_prefix_list_cmd); + install_element(PIM6_NODE, &pim6_ssmpingd_cmd); + install_element(PIM6_NODE, &no_pim6_ssmpingd_cmd); + + install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); + install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); + install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); + install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_pim_cmd); install_element(INTERFACE_NODE, &interface_ipv6_pim_drprio_cmd); @@ -1764,10 +2656,8 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_no_ipv6_pim_ssm_cmd); install_element(INTERFACE_NODE, &interface_ipv6_pim_sm_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_pim_sm_cmd); - install_element(INTERFACE_NODE, - &interface_ipv6_pim_boundary_oil_cmd); - install_element(INTERFACE_NODE, - &interface_no_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_pim_boundary_oil_cmd); + install_element(INTERFACE_NODE, &interface_no_ipv6_pim_boundary_oil_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mroute_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mroute_cmd); /* Install BSM command */ @@ -1775,18 +2665,7 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &no_ipv6_pim_bsm_cmd); install_element(INTERFACE_NODE, &ipv6_pim_ucast_bsm_cmd); install_element(INTERFACE_NODE, &no_ipv6_pim_ucast_bsm_cmd); - install_element(CONFIG_NODE, &ipv6_pim_rp_cmd); - install_element(VRF_NODE, &ipv6_pim_rp_cmd); - install_element(CONFIG_NODE, &no_ipv6_pim_rp_cmd); - install_element(VRF_NODE, &no_ipv6_pim_rp_cmd); - install_element(CONFIG_NODE, &ipv6_pim_rp_prefix_list_cmd); - install_element(VRF_NODE, &ipv6_pim_rp_prefix_list_cmd); - install_element(CONFIG_NODE, &no_ipv6_pim_rp_prefix_list_cmd); - install_element(VRF_NODE, &no_ipv6_pim_rp_prefix_list_cmd); - install_element(CONFIG_NODE, &ipv6_ssmpingd_cmd); - install_element(VRF_NODE, &ipv6_ssmpingd_cmd); - install_element(CONFIG_NODE, &no_ipv6_ssmpingd_cmd); - install_element(VRF_NODE, &no_ipv6_ssmpingd_cmd); + install_element(INTERFACE_NODE, &interface_ipv6_mld_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mld_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mld_join_cmd); @@ -1796,10 +2675,6 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_ipv6_mld_query_interval_cmd); install_element(INTERFACE_NODE, &interface_no_ipv6_mld_query_interval_cmd); - install_element(CONFIG_NODE, &ipv6_mld_group_watermark_cmd); - install_element(VRF_NODE, &ipv6_mld_group_watermark_cmd); - install_element(CONFIG_NODE, &no_ipv6_mld_group_watermark_cmd); - install_element(VRF_NODE, &no_ipv6_mld_group_watermark_cmd); install_element(INTERFACE_NODE, &interface_ipv6_mld_query_max_response_time_cmd); install_element(INTERFACE_NODE, diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c index 5ce6985c45..24443404eb 100644 --- a/pimd/pim6_main.c +++ b/pimd/pim6_main.c @@ -94,6 +94,7 @@ struct frr_signal_t pim6d_signals[] = { }, }; +/* clang-format off */ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -105,7 +106,6 @@ static const struct frr_yang_module_info *const pim6d_yang_modules[] = { &frr_gmp_info, }; -/* clang-format off */ FRR_DAEMON_INFO(pim6d, PIM6, .vty_port = PIM6D_VTY_PORT, .proghelp = "Protocol Independent Multicast (RFC7761) for IPv6", diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h index ecba739a5a..c1416e1dd0 100644 --- a/pimd/pim_addr.h +++ b/pimd/pim_addr.h @@ -14,16 +14,19 @@ #if PIM_IPV == 4 typedef struct in_addr pim_addr; +typedef struct prefix_ipv4 prefix_pim; #define PIM_ADDRSTRLEN INET_ADDRSTRLEN #define PIM_AF AF_INET #define PIM_AFI AFI_IP #define PIM_PROTO_REG IPPROTO_RAW +#define PIM_IANA_AFI IANA_AFI_IPV4 #define PIM_IPADDR IPADDR_V4 #define ipaddr_pim ipaddr_v4 #define PIM_MAX_BITLEN IPV4_MAX_BITLEN #define PIM_AF_NAME "ip" #define PIM_AF_DBG "pim" +#define PIM_AF_ROUTER "pim" #define GM_AF_DBG "igmp" #define PIM_MROUTE_DBG "mroute" #define PIMREG "pimreg" @@ -44,16 +47,19 @@ union pimprefixconstptr { #else typedef struct in6_addr pim_addr; +typedef struct prefix_ipv6 prefix_pim; #define PIM_ADDRSTRLEN INET6_ADDRSTRLEN #define PIM_AF AF_INET6 #define PIM_AFI AFI_IP6 #define PIM_PROTO_REG IPPROTO_PIM +#define PIM_IANA_AFI IANA_AFI_IPV6 #define PIM_IPADDR IPADDR_V6 #define ipaddr_pim ipaddr_v6 #define PIM_MAX_BITLEN IPV6_MAX_BITLEN #define PIM_AF_NAME "ipv6" #define PIM_AF_DBG "pimv6" +#define PIM_AF_ROUTER "pim6" #define GM_AF_DBG "mld" #define PIM_MROUTE_DBG "mroute6" #define PIMREG "pim6reg" diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index df9161943d..2d451718a9 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -1451,3 +1451,8 @@ int pim_bsm_process(struct interface *ifp, pim_sgaddr *sg, uint8_t *buf, return 0; } + +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc) +{ + /* stub for Candidate-RP */ +} diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index a2d756a96a..f57048c703 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -1457,19 +1457,13 @@ static void clear_interfaces(struct pim_instance *pim) static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, const char *gname) { - const char *vrfname; - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; char xpath_member_value[XPATH_MAXLEN]; const struct lyd_node *member_dnode; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return; - /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); /* Group must exists, otherwise just quit. */ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) return; @@ -1477,8 +1471,7 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, /* Group members check: */ strlcpy(xpath_member_value, xpath_value, sizeof(xpath_member_value)); strlcat(xpath_member_value, "/members", sizeof(xpath_member_value)); - if (yang_dnode_exists(vty->candidate_config->dnode, - xpath_member_value)) { + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_member_value)) { member_dnode = yang_dnode_get(vty->candidate_config->dnode, xpath_member_value); if (!member_dnode || !yang_is_last_list_dnode(member_dnode)) @@ -2830,6 +2823,40 @@ DEFPY (clear_ip_mroute_count, return clear_ip_mroute_count_command(vty, name); } +DEFPY(clear_ip_msdp_peer, clear_ip_msdp_peer_cmd, + "clear ip msdp peer A.B.C.D$peer [vrf WORD$vrfname]", + CLEAR_STR + IP_STR + MSDP_STR + "Restart MSDP peer\n" + "MSDP peer address\n" + VRF_CMD_HELP_STR) +{ + const struct pim_instance *pim; + const struct listnode *node; + const struct vrf *vrf; + struct pim_msdp_peer *mp; + + if (vrfname) + vrf = vrf_lookup_by_name(vrfname); + else + vrf = vrf_lookup_by_id(VRF_DEFAULT); + + if (vrf == NULL || vrf->info == NULL) + return CMD_WARNING; + + pim = vrf->info; + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) { + if (mp->peer.s_addr != peer.s_addr) + continue; + + pim_msdp_peer_restart(mp); + break; + } + + return CMD_SUCCESS; +} + DEFPY (show_ip_mroute_count, show_ip_mroute_count_cmd, "show ip mroute [vrf NAME] count [json$json]", @@ -2989,22 +3016,108 @@ DEFUN (show_ip_ssmpingd, return CMD_SUCCESS; } -DEFUN (ip_pim_spt_switchover_infinity, - ip_pim_spt_switchover_infinity_cmd, - "ip pim spt-switchover infinity-and-beyond", - IP_STR - PIM_STR +DEFPY_NOSH (router_pim, + router_pim_cmd, + "router pim [vrf NAME]", + "Enable a routing process\n" + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) != CMD_SUCCESS) + return CMD_WARNING_CONFIG_FAILED; + + VTY_PUSH_XPATH(PIM_NODE, xpath); + return CMD_SUCCESS; +} + +DEFPY (no_router_pim, + no_router_pim_cmd, + "no router pim [vrf NAME]", + NO_STR + "Enable a routing process\n" + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + char xpath[XPATH_MAXLEN]; + const char *vrf_name; + + if (vrf) + vrf_name = vrf; + else + vrf_name = VRF_DEFAULT_NAME; + + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", + vrf_name, FRR_PIM_AF_XPATH_VAL); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} + + +DEFPY (pim_spt_switchover_infinity, + pim_spt_switchover_infinity_cmd, + "spt-switchover infinity-and-beyond", "SPT-Switchover\n" "Never switch to SPT Tree\n") { return pim_process_spt_switchover_infinity_cmd(vty); } +DEFPY_ATTR(ip_pim_spt_switchover_infinity, + ip_pim_spt_switchover_infinity_cmd, + "ip pim spt-switchover infinity-and-beyond", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_spt_switchover_infinity_plist, - ip_pim_spt_switchover_infinity_plist_cmd, - "ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", - IP_STR - PIM_STR + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_infinity_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_spt_switchover_infinity_plist, + pim_spt_switchover_infinity_plist_cmd, + "spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", "SPT-Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -3012,25 +3125,104 @@ DEFPY (ip_pim_spt_switchover_infinity_plist, { return pim_process_spt_switchover_prefixlist_cmd(vty, plist); } +DEFPY_ATTR(ip_pim_spt_switchover_infinity_plist, + ip_pim_spt_switchover_infinity_plist_cmd, + "ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "SPT-Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_spt_switchover_prefixlist_cmd(vty, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_spt_switchover_infinity, - no_ip_pim_spt_switchover_infinity_cmd, - "no ip pim spt-switchover infinity-and-beyond", +DEFPY (no_pim_spt_switchover_infinity, + no_pim_spt_switchover_infinity_cmd, + "no spt-switchover infinity-and-beyond", NO_STR - IP_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n") { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ip_pim_spt_switchover_infinity, + no_ip_pim_spt_switchover_infinity_cmd, + "no ip pim spt-switchover infinity-and-beyond", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_spt_switchover_infinity_plist, - no_ip_pim_spt_switchover_infinity_plist_cmd, - "no ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", +DEFPY (no_pim_spt_switchover_infinity_plist, + no_pim_spt_switchover_infinity_plist_cmd, + "no spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", NO_STR - IP_STR - PIM_STR "SPT_Switchover\n" "Never switch to SPT Tree\n" "Prefix-List to control which groups to switch\n" @@ -3038,28 +3230,61 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, { return pim_process_no_spt_switchover_cmd(vty); } +DEFPY_ATTR(no_ip_pim_spt_switchover_infinity_plist, + no_ip_pim_spt_switchover_infinity_plist_cmd, + "no ip pim spt-switchover infinity-and-beyond prefix-list PREFIXLIST4_NAME", + NO_STR + IP_STR + PIM_STR + "SPT_Switchover\n" + "Never switch to SPT Tree\n" + "Prefix-List to control which groups to switch\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_spt_switchover_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (pim_register_accept_list, pim_register_accept_list_cmd, - "[no] ip pim register-accept-list PREFIXLIST4_NAME$word", + "[no] register-accept-list PREFIXLIST4_NAME$word", NO_STR - IP_STR - PIM_STR "Only accept registers from a specific source prefix list\n" "Prefix-List name\n") { - const char *vrfname; char reg_alist_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - strlcat(reg_alist_xpath, "/register-accept-list", - sizeof(reg_alist_xpath)); + "./register-accept-list"); if (no) nb_cli_enqueue_change(vty, reg_alist_xpath, @@ -3070,123 +3295,560 @@ DEFPY (pim_register_accept_list, return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(ip_pim_register_accept_list, + ip_pim_register_accept_list_cmd, + "[no] ip pim register-accept-list PREFIXLIST4_NAME$word", + NO_STR + IP_STR + PIM_STR + "Only accept registers from a specific source prefix list\n" + "Prefix-List name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char reg_alist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_joinprune_time, - ip_pim_joinprune_time_cmd, - "ip pim join-prune-interval (1-65535)$jpi", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), + "./register-accept-list"); + + if (no) + nb_cli_enqueue_change(vty, reg_alist_xpath, NB_OP_DESTROY, NULL); + else + nb_cli_enqueue_change(vty, reg_alist_xpath, NB_OP_MODIFY, word); + + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_joinprune_time, + pim_joinprune_time_cmd, + "join-prune-interval (1-65535)$jpi", "Join Prune Send Interval\n" "Seconds\n") { return pim_process_join_prune_cmd(vty, jpi_str); } +DEFPY_ATTR(ip_pim_joinprune_time, + ip_pim_joinprune_time_cmd, + "ip pim join-prune-interval (1-65535)$jpi", + IP_STR + PIM_STR + "Join Prune Send Interval\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_join_prune_cmd(vty, jpi_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_joinprune_time, - no_ip_pim_joinprune_time_cmd, - "no ip pim join-prune-interval [(1-65535)]", +DEFPY (no_pim_joinprune_time, + no_pim_joinprune_time_cmd, + "no join-prune-interval [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { return pim_process_no_join_prune_cmd(vty); } +DEFPY_ATTR(no_ip_pim_joinprune_time, + no_ip_pim_joinprune_time_cmd, + "no ip pim join-prune-interval [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Join Prune Send Interval\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_register_suppress, - ip_pim_register_suppress_cmd, - "ip pim register-suppress-time (1-65535)$rst", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_join_prune_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_register_suppress, + pim_register_suppress_cmd, + "register-suppress-time (1-65535)$rst", "Register Suppress Timer\n" "Seconds\n") { return pim_process_register_suppress_cmd(vty, rst_str); } +DEFPY_ATTR(ip_pim_register_suppress, + ip_pim_register_suppress_cmd, + "ip pim register-suppress-time (1-65535)$rst", + IP_STR + PIM_STR + "Register Suppress Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_register_suppress_cmd(vty, rst_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_register_suppress, - no_ip_pim_register_suppress_cmd, - "no ip pim register-suppress-time [(1-65535)]", +DEFPY (no_pim_register_suppress, + no_pim_register_suppress_cmd, + "no register-suppress-time [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Register Suppress Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_register_suppress_cmd(vty); } +DEFPY_ATTR(no_ip_pim_register_suppress, + no_ip_pim_register_suppress_cmd, + "no ip pim register-suppress-time [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Register Suppress Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_register_suppress_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (ip_pim_rp_keep_alive, - ip_pim_rp_keep_alive_cmd, - "ip pim rp keep-alive-timer (1-65535)$kat", - IP_STR - "pim multicast routing\n" +DEFPY (pim_rp_keep_alive, + pim_rp_keep_alive_cmd, + "rp keep-alive-timer (1-65535)$kat", "Rendezvous Point\n" "Keep alive Timer\n" "Seconds\n") { return pim_process_rp_kat_cmd(vty, kat_str); } +DEFPY_ATTR(ip_pim_rp_keep_alive, + ip_pim_rp_keep_alive_cmd, + "ip pim rp keep-alive-timer (1-65535)$kat", + IP_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_kat_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFUN (no_ip_pim_rp_keep_alive, - no_ip_pim_rp_keep_alive_cmd, - "no ip pim rp keep-alive-timer [(1-65535)]", +DEFPY (no_pim_rp_keep_alive, + no_pim_rp_keep_alive_cmd, + "no rp keep-alive-timer [(1-65535)]", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "Keep alive Timer\n" IGNORED_IN_NO_STR) { return pim_process_no_rp_kat_cmd(vty); } - -DEFPY (ip_pim_keep_alive, - ip_pim_keep_alive_cmd, - "ip pim keep-alive-timer (1-65535)$kat", - IP_STR - "pim multicast routing\n" - "Keep alive Timer\n" - "Seconds\n") +DEFPY_ATTR(no_ip_pim_rp_keep_alive, + no_ip_pim_rp_keep_alive_cmd, + "no ip pim rp keep-alive-timer [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - return pim_process_keepalivetimer_cmd(vty, kat_str); -} + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFUN (no_ip_pim_keep_alive, - no_ip_pim_keep_alive_cmd, - "no ip pim keep-alive-timer [(1-65535)]", - NO_STR - IP_STR - "pim multicast routing\n" - "Keep alive Timer\n" - IGNORED_IN_NO_STR) -{ + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_kat_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_keep_alive, + pim_keep_alive_cmd, + "keep-alive-timer (1-65535)$kat", + "Keep alive Timer\n" + "Seconds\n") +{ + return pim_process_keepalivetimer_cmd(vty, kat_str); +} +DEFPY_ATTR(ip_pim_keep_alive, + ip_pim_keep_alive_cmd, + "ip pim keep-alive-timer (1-65535)$kat", + IP_STR + PIM_STR + "Keep alive Timer\n" + "Seconds\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_keepalivetimer_cmd(vty, kat_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_keep_alive, + no_pim_keep_alive_cmd, + "no keep-alive-timer [(1-65535)]", + NO_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR) +{ return pim_process_no_keepalivetimer_cmd(vty); } +DEFPY_ATTR(no_ip_pim_keep_alive, + no_ip_pim_keep_alive_cmd, + "no ip pim keep-alive-timer [(1-65535)]", + NO_STR + IP_STR + PIM_STR + "Keep alive Timer\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_packets, - ip_pim_packets_cmd, - "ip pim packets (1-255)", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_keepalivetimer_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_packets, + pim_packets_cmd, + "packets (1-255)", "packets to process at one time per fd\n" "Number of packets\n") { return pim_process_pim_packet_cmd(vty, packets_str); } +DEFPY_ATTR(ip_pim_packets, + ip_pim_packets_cmd, + "ip pim packets (1-255)", + IP_STR + PIM_STR + "packets to process at one time per fd\n" + "Number of packets\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFUN (no_ip_pim_packets, - no_ip_pim_packets_cmd, - "no ip pim packets [(1-255)]", + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_pim_packet_cmd(vty, packets_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (no_pim_packets, + no_pim_packets_cmd, + "no packets [(1-255)]", NO_STR - IP_STR - "pim multicast routing\n" "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { return pim_process_no_pim_packet_cmd(vty); } +DEFPY_ATTR(no_ip_pim_packets, + no_ip_pim_packets_cmd, + "no ip pim packets [(1-255)]", + NO_STR + IP_STR + PIM_STR + "packets to process at one time per fd\n" + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_pim_packet_cmd(vty); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFPY (ip_igmp_group_watermark, ip_igmp_group_watermark_cmd, @@ -3217,64 +3879,131 @@ DEFPY (no_ip_igmp_group_watermark, return CMD_SUCCESS; } -DEFUN (ip_pim_v6_secondary, - ip_pim_v6_secondary_cmd, - "ip pim send-v6-secondary", - IP_STR - "pim multicast routing\n" +DEFPY (pim_v6_secondary, + pim_v6_secondary_cmd, + "send-v6-secondary", "Send v6 secondary addresses\n") { - const char *vrfname; char send_v6_secondary_xpath[XPATH_MAXLEN]; + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + "./send-v6-secondary"); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_v6_secondary, + ip_pim_v6_secondary_cmd, + "ip pim send-v6-secondary", + IP_STR + PIM_STR + "Send v6 secondary addresses\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char send_v6_secondary_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(send_v6_secondary_xpath, "/send-v6-secondary", - sizeof(send_v6_secondary_xpath)); - + "./send-v6-secondary"); nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, "true"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_v6_secondary, - no_ip_pim_v6_secondary_cmd, - "no ip pim send-v6-secondary", +DEFPY (no_pim_v6_secondary, + no_pim_v6_secondary_cmd, + "no send-v6-secondary", NO_STR - IP_STR - "pim multicast routing\n" "Send v6 secondary addresses\n") { - const char *vrfname; char send_v6_secondary_xpath[XPATH_MAXLEN]; + snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), + "./send-v6-secondary"); + + nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, + "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_v6_secondary, + no_ip_pim_v6_secondary_cmd, + "no ip pim send-v6-secondary", + NO_STR + IP_STR + PIM_STR + "Send v6 secondary addresses\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char send_v6_secondary_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(send_v6_secondary_xpath, "/send-v6-secondary", - sizeof(send_v6_secondary_xpath)); - + "./send-v6-secondary"); nb_cli_enqueue_change(vty, send_v6_secondary_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY (ip_pim_rp, - ip_pim_rp_cmd, - "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", - IP_STR - "pim multicast routing\n" +DEFPY (pim_rp, + pim_rp_cmd, + "rp A.B.C.D$rp [A.B.C.D/M]$gp", "Rendezvous Point\n" "ip address of RP\n" "Group Address range to cover\n") @@ -3283,12 +4012,52 @@ DEFPY (ip_pim_rp, return pim_process_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(ip_pim_rp, + ip_pim_rp_cmd, + "ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY (ip_pim_rp_prefix_list, - ip_pim_rp_prefix_list_cmd, - "ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_rp_prefix_list, + pim_rp_prefix_list_cmd, + "rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" @@ -3296,13 +4065,53 @@ DEFPY (ip_pim_rp_prefix_list, { return pim_process_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(ip_pim_rp_prefix_list, + ip_pim_rp_prefix_list_cmd, + "ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ip_pim_rp, - no_ip_pim_rp_cmd, - "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", +DEFPY (no_pim_rp, + no_pim_rp_cmd, + "no rp A.B.C.D$rp [A.B.C.D/M]$gp", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "ip address of RP\n" "Group Address range to cover\n") @@ -3311,13 +4120,54 @@ DEFPY (no_ip_pim_rp, return pim_process_no_rp_cmd(vty, rp_str, group_str); } +DEFPY_ATTR(no_ip_pim_rp, + no_ip_pim_rp_cmd, + "no ip pim rp A.B.C.D$rp [A.B.C.D/M]$gp", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "Group Address range to cover\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const char *group_str = (gp_str) ? gp_str : "224.0.0.0/4"; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_cmd(vty, rp_str, group_str); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} -DEFPY (no_ip_pim_rp_prefix_list, - no_ip_pim_rp_prefix_list_cmd, - "no ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", +DEFPY (no_pim_rp_prefix_list, + no_pim_rp_prefix_list_cmd, + "no rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", NO_STR - IP_STR - "pim multicast routing\n" "Rendezvous Point\n" "ip address of RP\n" "group prefix-list filter\n" @@ -3325,104 +4175,264 @@ DEFPY (no_ip_pim_rp_prefix_list, { return pim_process_no_rp_plist_cmd(vty, rp_str, plist); } +DEFPY_ATTR(no_ip_pim_rp_prefix_list, + no_ip_pim_rp_prefix_list_cmd, + "no ip pim rp A.B.C.D$rp prefix-list PREFIXLIST4_NAME$plist", + NO_STR + IP_STR + PIM_STR + "Rendezvous Point\n" + "ip address of RP\n" + "group prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFUN (ip_pim_ssm_prefix_list, - ip_pim_ssm_prefix_list_cmd, - "ip pim ssm prefix-list PREFIXLIST4_NAME", - IP_STR - "pim multicast routing\n" + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ret = pim_process_no_rp_plist_cmd(vty, rp_str, plist); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY (pim_ssm_prefix_list, + pim_ssm_prefix_list_cmd, + "ssm prefix-list PREFIXLIST4_NAME$plist", "Source Specific Multicast\n" "group range prefix-list filter\n" "Name of a prefix-list\n") { - const char *vrfname; char ssm_plist_xpath[XPATH_MAXLEN]; + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ssm_prefix_list, + ip_pim_ssm_prefix_list_cmd, + "ip pim ssm prefix-list PREFIXLIST4_NAME$plist", + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ssm_plist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, plist); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_MODIFY, argv[4]->arg); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return nb_cli_apply_changes(vty, NULL); + return ret; } -DEFUN (no_ip_pim_ssm_prefix_list, - no_ip_pim_ssm_prefix_list_cmd, - "no ip pim ssm prefix-list", +DEFPY (no_pim_ssm_prefix_list, + no_pim_ssm_prefix_list_cmd, + "no ssm prefix-list", NO_STR - IP_STR - "pim multicast routing\n" "Source Specific Multicast\n" "group range prefix-list filter\n") { - const char *vrfname; char ssm_plist_xpath[XPATH_MAXLEN]; + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); + + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ssm_prefix_list, + no_ip_pim_ssm_prefix_list_cmd, + "no ip pim ssm prefix-list", + NO_STR + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ssm_plist_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); - + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "./ssm-prefix-list"); nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ssm_prefix_list_name, - no_ip_pim_ssm_prefix_list_name_cmd, - "no ip pim ssm prefix-list PREFIXLIST4_NAME", +DEFPY (no_pim_ssm_prefix_list_name, + no_pim_ssm_prefix_list_name_cmd, + "no ssm prefix-list PREFIXLIST4_NAME$plist", NO_STR - IP_STR - "pim multicast routing\n" "Source Specific Multicast\n" "group range prefix-list filter\n" "Name of a prefix-list\n") { - const char *vrfname; const struct lyd_node *ssm_plist_dnode; - char ssm_plist_xpath[XPATH_MAXLEN]; + char ssm_plist_xpath[XPATH_MAXLEN + 16]; const char *ssm_plist_name; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", + VTY_CURR_XPATH); ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, ssm_plist_xpath); if (!ssm_plist_dnode) { - vty_out(vty, - "%% pim ssm prefix-list %s doesn't exist\n", - argv[5]->arg); + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); return CMD_WARNING_CONFIG_FAILED; } ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); - if (ssm_plist_name && !strcmp(ssm_plist_name, argv[5]->arg)) { - nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, - NULL); - + if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { + nb_cli_enqueue_change(vty, ssm_plist_xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } - vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", argv[5]->arg); + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); return CMD_WARNING_CONFIG_FAILED; } +DEFPY_ATTR(no_ip_pim_ssm_prefix_list_name, + no_ip_pim_ssm_prefix_list_name_cmd, + "no ip pim ssm prefix-list PREFIXLIST4_NAME$plist", + NO_STR + IP_STR + PIM_STR + "Source Specific Multicast\n" + "group range prefix-list filter\n" + "Name of a prefix-list\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + const struct lyd_node *ssm_plist_dnode; + char ssm_plist_xpath[XPATH_MAXLEN + 16]; + const char *ssm_plist_name; + int ret = CMD_WARNING_CONFIG_FAILED; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), "%s/ssm-prefix-list", + VTY_CURR_XPATH); + ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, + ssm_plist_xpath); + if (ssm_plist_dnode) { + ssm_plist_name = yang_dnode_get_string(ssm_plist_dnode, "."); + if (ssm_plist_name && !strcmp(ssm_plist_name, plist)) { + nb_cli_enqueue_change(vty, ssm_plist_xpath, + NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + } else { + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", + plist); + } + } else { + vty_out(vty, "%% pim ssm prefix-list %s doesn't exist\n", plist); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} DEFUN (show_ip_pim_ssm_range, show_ip_pim_ssm_range_cmd, @@ -3511,135 +4521,354 @@ DEFPY (show_ip_pim_bsr, return pim_show_bsr_helper(vrf, vty, !!json); } -DEFUN (ip_ssmpingd, - ip_ssmpingd_cmd, - "ip ssmpingd [A.B.C.D]", - IP_STR +DEFPY (pim_ssmpingd, + pim_ssmpingd_cmd, + "ssmpingd [A.B.C.D]$src", CONF_SSMPINGD_STR "Source address\n") { - int idx_ipv4 = 2; - const char *src_str = (argc == 3) ? argv[idx_ipv4]->arg : "0.0.0.0"; + if (src_str) + return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + else + return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); +} +DEFPY_ATTR(ip_pim_ssmpingd, + ip_ssmpingd_cmd, + "ip ssmpingd [A.B.C.D]$src", + IP_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (src_str) + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + else + ret = pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, "0.0.0.0"); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return pim_process_ssmpingd_cmd(vty, NB_OP_CREATE, src_str); + return ret; } -DEFUN (no_ip_ssmpingd, - no_ip_ssmpingd_cmd, - "no ip ssmpingd [A.B.C.D]", +DEFPY (no_pim_ssmpingd, + no_pim_ssmpingd_cmd, + "no ssmpingd [A.B.C.D]$src", NO_STR - IP_STR CONF_SSMPINGD_STR "Source address\n") { - int idx_ipv4 = 3; - const char *src_str = (argc == 4) ? argv[idx_ipv4]->arg : "0.0.0.0"; + if (src_str) + return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + else + return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); +} +DEFPY_ATTR(no_ip_pim_ssmpingd, + no_ip_ssmpingd_cmd, + "no ip ssmpingd [A.B.C.D]$src", + NO_STR + IP_STR + CONF_SSMPINGD_STR + "Source address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; - return pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (src_str) + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, src_str); + else + ret = pim_process_ssmpingd_cmd(vty, NB_OP_DESTROY, "0.0.0.0"); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (ip_pim_ecmp, - ip_pim_ecmp_cmd, - "ip pim ecmp", - IP_STR - "pim multicast routing\n" +DEFPY (pim_ecmp, + pim_ecmp_cmd, + "ecmp", "Enable PIM ECMP \n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ecmp, + ip_pim_ecmp_cmd, + "ip pim ecmp", + IP_STR + PIM_STR + "Enable PIM ECMP \n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); - + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); - return nb_cli_apply_changes(vty, NULL); + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ecmp, - no_ip_pim_ecmp_cmd, - "no ip pim ecmp", +DEFPY (no_pim_ecmp, + no_pim_ecmp_cmd, + "no ecmp", NO_STR - IP_STR - "pim multicast routing\n" "Disable PIM ECMP \n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ecmp, + no_ip_pim_ecmp_cmd, + "no ip pim ecmp", + NO_STR + IP_STR + PIM_STR + "Disable PIM ECMP \n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); - + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (ip_pim_ecmp_rebalance, - ip_pim_ecmp_rebalance_cmd, - "ip pim ecmp rebalance", - IP_STR - "pim multicast routing\n" +DEFPY (pim_ecmp_rebalance, + pim_ecmp_rebalance_cmd, + "ecmp rebalance", "Enable PIM ECMP \n" "Enable PIM ECMP Rebalance\n") { - const char *vrfname; char ecmp_xpath[XPATH_MAXLEN]; char ecmp_rebalance_xpath[XPATH_MAXLEN]; + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + "./ecmp-rebalance"); + + nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_ecmp_rebalance, + ip_pim_ecmp_rebalance_cmd, + "ip pim ecmp rebalance", + IP_STR + PIM_STR + "Enable PIM ECMP \n" + "Enable PIM ECMP Rebalance\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_xpath[XPATH_MAXLEN]; + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); + snprintf(ecmp_xpath, sizeof(ecmp_xpath), "./ecmp"); snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", - sizeof(ecmp_rebalance_xpath)); - + "./ecmp-rebalance"); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "true"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFUN (no_ip_pim_ecmp_rebalance, - no_ip_pim_ecmp_rebalance_cmd, - "no ip pim ecmp rebalance", +DEFPY (no_pim_ecmp_rebalance, + no_pim_ecmp_rebalance_cmd, + "no ecmp rebalance", NO_STR - IP_STR - "pim multicast routing\n" "Disable PIM ECMP \n" "Disable PIM ECMP Rebalance\n") { - const char *vrfname; char ecmp_rebalance_xpath[XPATH_MAXLEN]; + snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), + "./ecmp-rebalance"); + + nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_ecmp_rebalance, + no_ip_pim_ecmp_rebalance_cmd, + "no ip pim ecmp rebalance", + NO_STR + IP_STR + PIM_STR + "Disable PIM ECMP \n" + "Disable PIM ECMP Rebalance\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char ecmp_rebalance_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", - sizeof(ecmp_rebalance_xpath)); - + "./ecmp-rebalance"); nb_cli_enqueue_change(vty, ecmp_rebalance_xpath, NB_OP_MODIFY, "false"); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } DEFUN (interface_ip_igmp, @@ -4648,15 +5877,24 @@ DEFPY (debug_pim_zebra, return CMD_SUCCESS; } -DEFUN(debug_pim_mlag, debug_pim_mlag_cmd, "debug pim mlag", - DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +DEFUN(debug_pim_mlag, + debug_pim_mlag_cmd, + "debug pim mlag", + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_MLAG_STR) { PIM_DO_DEBUG_MLAG; return CMD_SUCCESS; } -DEFUN(no_debug_pim_mlag, no_debug_pim_mlag_cmd, "no debug pim mlag", - NO_STR DEBUG_STR DEBUG_PIM_STR DEBUG_PIM_MLAG_STR) +DEFUN(no_debug_pim_mlag, + no_debug_pim_mlag_cmd, + "no debug pim mlag", + NO_STR + DEBUG_STR + DEBUG_PIM_STR + DEBUG_PIM_MLAG_STR) { PIM_DONT_DEBUG_MLAG; return CMD_SUCCESS; @@ -5016,145 +6254,447 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, "Desired min transmit interval\n") #endif /* !HAVE_BFDD */ -DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, - "ip msdp peer A.B.C.D$peer source A.B.C.D$source", - IP_STR +DEFPY(pim_msdp_peer, pim_msdp_peer_cmd, + "msdp peer A.B.C.D$peer source A.B.C.D$source", CFG_MSDP_STR "Configure MSDP peer\n" "Peer IP address\n" "Source address for TCP connection\n" "Local IP address\n") { - const char *vrfname; - char temp_xpath[XPATH_MAXLEN]; char msdp_peer_source_xpath[XPATH_MAXLEN]; + snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), + "./msdp-peer[peer-ip='%s']/source-ip", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, + source_str); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_peer, + ip_msdp_peer_cmd, + "ip msdp peer A.B.C.D$peer source A.B.C.D$source", + IP_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "Peer IP address\n" + "Source address for TCP connection\n" + "Local IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char msdp_peer_source_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - "frr-routing:ipv4"); - snprintf(temp_xpath, sizeof(temp_xpath), - "/msdp-peer[peer-ip='%s']/source-ip", peer_str); - strlcat(msdp_peer_source_xpath, temp_xpath, - sizeof(msdp_peer_source_xpath)); - + "./msdp-peer[peer-ip='%s']/source-ip", peer_str); nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, source_str); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, - FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(ip_msdp_timers, ip_msdp_timers_cmd, - "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", - IP_STR +DEFPY(msdp_peer_md5, msdp_peer_md5_cmd, + "msdp peer A.B.C.D$peer password WORD$psk", + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "Use MD5 authentication\n" + "MD5 pre shared key\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, "MD5"); + nb_cli_enqueue_change(vty, "./authentication-key", NB_OP_MODIFY, psk); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(no_msdp_peer_md5, no_msdp_peer_md5_cmd, + "no msdp peer A.B.C.D$peer password [WORD]", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "Use MD5 authentication\n" + "MD5 pre shared key\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + nb_cli_enqueue_change(vty, "./authentication-type", NB_OP_MODIFY, + "None"); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(pim_msdp_timers, pim_msdp_timers_cmd, + "msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", CFG_MSDP_STR "MSDP timers configuration\n" "Keep alive period (in seconds)\n" "Hold time period (in seconds)\n" "Connection retry period (in seconds)\n") { + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, + holdtime_str); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, + keepalive_str); + if (connretry_str) + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_MODIFY, connretry_str); + else + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_DESTROY, NULL); + + nb_cli_apply_changes(vty, NULL); + return CMD_SUCCESS; +} +DEFPY_ATTR(ip_pim_msdp_timers, + ip_msdp_timers_cmd, + "ip msdp timers (1-65535)$keepalive (1-65535)$holdtime [(1-65535)$connretry]", + IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + "Keep alive period (in seconds)\n" + "Hold time period (in seconds)\n" + "Connection retry period (in seconds)\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, "./hold-time", NB_OP_MODIFY, holdtime_str); - nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_MODIFY, keepalive_str); + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_MODIFY, + holdtime_str); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_MODIFY, + keepalive_str); if (connretry_str) - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_MODIFY, - connretry_str); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_MODIFY, connretry_str); else - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, - NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", + NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", - vrfname, "frr-routing:ipv4"); - return CMD_SUCCESS; + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_timers, no_ip_msdp_timers_cmd, - "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", +DEFPY(no_pim_msdp_timers, no_pim_msdp_timers_cmd, + "no msdp timers [(1-65535) (1-65535) [(1-65535)]]", NO_STR - IP_STR CFG_MSDP_STR "MSDP timers configuration\n" IGNORED_IN_NO_STR IGNORED_IN_NO_STR IGNORED_IN_NO_STR) { + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, + NULL); + nb_cli_apply_changes(vty, NULL); + return CMD_SUCCESS; +} +DEFPY_ATTR(no_ip_pim_msdp_timers, + no_ip_msdp_timers_cmd, + "no ip msdp timers [(1-65535) (1-65535) [(1-65535)]]", + NO_STR + IP_STR + CFG_MSDP_STR + "MSDP timers configuration\n" + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR + IGNORED_IN_NO_STR, + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + int ret; const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } - nb_cli_enqueue_change(vty, "./hold-time", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./keep-alive", NB_OP_DESTROY, NULL); - nb_cli_enqueue_change(vty, "./connection-retry", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/hold-time", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/keep-alive", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./msdp/connection-retry", NB_OP_DESTROY, + NULL); + ret = nb_cli_apply_changes(vty, NULL); - nb_cli_apply_changes(vty, FRR_PIM_MSDP_XPATH, "frr-pim:pimd", "pim", - vrfname, "frr-routing:ipv4"); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - return CMD_SUCCESS; + return ret; } -DEFUN (no_ip_msdp_peer, - no_ip_msdp_peer_cmd, - "no ip msdp peer A.B.C.D", +DEFPY (no_pim_msdp_peer, + no_pim_msdp_peer_cmd, + "no msdp peer A.B.C.D", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP peer\n" "peer ip address\n") { - const char *vrfname; char msdp_peer_xpath[XPATH_MAXLEN]; - char temp_xpath[XPATH_MAXLEN]; + + snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), + "./msdp-peer[peer-ip='%s']", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_msdp_peer, + no_ip_msdp_peer_cmd, + "no ip msdp peer A.B.C.D", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP peer\n" + "peer ip address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char msdp_peer_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); - snprintf(temp_xpath, sizeof(temp_xpath), - "/msdp-peer[peer-ip='%s']", - argv[4]->arg); + "./msdp-peer[peer-ip='%s']", peer_str); + nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); - strlcat(msdp_peer_xpath, temp_xpath, sizeof(msdp_peer_xpath)); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - nb_cli_enqueue_change(vty, msdp_peer_xpath, NB_OP_DESTROY, NULL); + return ret; +} - return nb_cli_apply_changes(vty, NULL); +DEFPY(msdp_peer_sa_filter, msdp_peer_sa_filter_cmd, + "msdp peer A.B.C.D$peer sa-filter ACL_NAME$acl_name $dir", + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "SA access-list filter\n" + "SA access-list name\n" + "Filter incoming SAs\n" + "Filter outgoing SAs\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + if (strcmp(dir, "in") == 0) + nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_MODIFY, + acl_name); + else + nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_MODIFY, + acl_name); + + return nb_cli_apply_changes(vty, "%s", xpath); } -DEFPY(ip_msdp_mesh_group_member, - ip_msdp_mesh_group_member_cmd, - "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", - IP_STR +DEFPY(no_msdp_peer_sa_filter, no_ip_msdp_peer_sa_filter_cmd, + "no msdp peer A.B.C.D$peer sa-filter ACL_NAME $dir", + NO_STR + CFG_MSDP_STR + "Configure MSDP peer\n" + "MSDP Peer address\n" + "SA access-list filter\n" + "SA access-list name\n" + "Filter incoming SAs\n" + "Filter outgoing SAs\n") +{ + const struct lyd_node *peer_node; + char xpath[XPATH_MAXLEN + 24]; + + snprintf(xpath, sizeof(xpath), "%s/msdp-peer[peer-ip='%s']", + VTY_CURR_XPATH, peer_str); + peer_node = yang_dnode_get(vty->candidate_config->dnode, xpath); + if (peer_node == NULL) { + vty_out(vty, "%% MSDP peer %s not yet configured\n", peer_str); + return CMD_SUCCESS; + } + + if (strcmp(dir, "in") == 0) + nb_cli_enqueue_change(vty, "./sa-filter-in", NB_OP_DESTROY, + NULL); + else + nb_cli_enqueue_change(vty, "./sa-filter-out", NB_OP_DESTROY, + NULL); + + return nb_cli_apply_changes(vty, "%s", xpath); +} + +DEFPY(pim_msdp_mesh_group_member, + pim_msdp_mesh_group_member_cmd, + "msdp mesh-group WORD$gname member A.B.C.D$maddr", CFG_MSDP_STR "Configure MSDP mesh-group\n" "Mesh group name\n" "Mesh group member\n" "Peer IP address\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group member. */ + strlcat(xpath_value, "/members[address='", sizeof(xpath_value)); + strlcat(xpath_value, maddr_str, sizeof(xpath_value)); + strlcat(xpath_value, "']", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_mesh_group_member, + ip_msdp_mesh_group_member_cmd, + "ip msdp mesh-group WORD$gname member A.B.C.D$maddr", + IP_STR + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); /* Create mesh group member. */ @@ -5162,33 +6702,32 @@ DEFPY(ip_msdp_mesh_group_member, strlcat(xpath_value, maddr_str, sizeof(xpath_value)); strlcat(xpath_value, "']", sizeof(xpath_value)); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group_member, - no_ip_msdp_mesh_group_member_cmd, - "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", +DEFPY(no_pim_msdp_mesh_group_member, + no_pim_msdp_mesh_group_member_cmd, + "no msdp mesh-group WORD$gname member A.B.C.D$maddr", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group member\n" "Mesh group name\n" "Mesh group member\n" "Peer IP address\n") { - const char *vrfname; - char xpath_value[XPATH_MAXLEN]; + char xpath_value[XPATH_MAXLEN + 26]; char xpath_member_value[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { vty_out(vty, "%% mesh-group does not exist\n"); @@ -5217,59 +6756,221 @@ DEFPY(no_ip_msdp_mesh_group_member, return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(no_ip_pim_msdp_mesh_group_member, + no_ip_msdp_mesh_group_member_cmd, + "no ip msdp mesh-group WORD$gname member A.B.C.D$maddr", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group member\n" + "Mesh group name\n" + "Mesh group member\n" + "Peer IP address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN + 26]; + char xpath_member_value[XPATH_MAXLEN]; + int ret = CMD_WARNING_CONFIG_FAILED; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; -DEFPY(ip_msdp_mesh_group_source, - ip_msdp_mesh_group_source_cmd, - "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", - IP_STR + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { + /* Remove mesh group member. */ + strlcpy(xpath_member_value, xpath_value, + sizeof(xpath_member_value)); + strlcat(xpath_member_value, "/members[address='", + sizeof(xpath_member_value)); + strlcat(xpath_member_value, maddr_str, + sizeof(xpath_member_value)); + strlcat(xpath_member_value, "']", sizeof(xpath_member_value)); + if (yang_dnode_exists(vty->candidate_config->dnode, + xpath_member_value)) { + nb_cli_enqueue_change(vty, xpath_member_value, + NB_OP_DESTROY, NULL); + + /* + * If this is the last member, then we must remove the group altogether + * to not break legacy CLI behaviour. + */ + pim_cli_legacy_mesh_group_behavior(vty, gname); + ret = nb_cli_apply_changes(vty, NULL); + } else { + vty_out(vty, "%% mesh-group member does not exist\n"); + } + } else { + vty_out(vty, "%% mesh-group does not exist\n"); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY(pim_msdp_mesh_group_source, + pim_msdp_mesh_group_source_cmd, + "msdp mesh-group WORD$gname source A.B.C.D$saddr", CFG_MSDP_STR "Configure MSDP mesh-group\n" "Mesh group name\n" "Mesh group local address\n" "Source IP address for the TCP connection\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Create mesh group. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group source. */ + strlcat(xpath_value, "/source", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(ip_pim_msdp_mesh_group_source, + ip_msdp_mesh_group_source_cmd, + "ip msdp mesh-group WORD$gname source A.B.C.D$saddr", + IP_STR + CFG_MSDP_STR + "Configure MSDP mesh-group\n" + "Mesh group name\n" + "Mesh group local address\n" + "Source IP address for the TCP connection\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); - /* Create mesh group source. */ strlcat(xpath_value, "/source", sizeof(xpath_value)); nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, saddr_str); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group_source, - no_ip_msdp_mesh_group_source_cmd, - "no ip msdp mesh-group WORD$gname source [A.B.C.D]", +DEFPY(no_pim_msdp_mesh_group_source, + no_pim_msdp_mesh_group_source_cmd, + "no msdp mesh-group WORD$gname source [A.B.C.D]", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group source\n" "Mesh group name\n" "Mesh group source\n" "Mesh group local address\n") { - const char *vrfname; char xpath_value[XPATH_MAXLEN]; + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "./msdp-mesh-groups[name='%s']", gname); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); + + /* Create mesh group source. */ + strlcat(xpath_value, "/source", sizeof(xpath_value)); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + + /* + * If this is the last member, then we must remove the group altogether + * to not break legacy CLI behaviour. + */ + pim_cli_legacy_mesh_group_behavior(vty, gname); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_msdp_mesh_group_source, + no_ip_msdp_mesh_group_source_cmd, + "no ip msdp mesh-group WORD$gname source [A.B.C.D]", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group source\n" + "Mesh group name\n" + "Mesh group source\n" + "Mesh group local address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); return CMD_WARNING_CONFIG_FAILED; + } /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "./msdp-mesh-groups[name='%s']", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); /* Create mesh group source. */ @@ -5281,36 +6982,83 @@ DEFPY(no_ip_msdp_mesh_group_source, * to not break legacy CLI behaviour. */ pim_cli_legacy_mesh_group_behavior(vty, gname); + ret = nb_cli_apply_changes(vty, NULL); - return nb_cli_apply_changes(vty, NULL); + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; } -DEFPY(no_ip_msdp_mesh_group, - no_ip_msdp_mesh_group_cmd, - "no ip msdp mesh-group WORD$gname", +DEFPY(no_pim_msdp_mesh_group, + no_pim_msdp_mesh_group_cmd, + "no msdp mesh-group WORD$gname", NO_STR - IP_STR CFG_MSDP_STR "Delete MSDP mesh-group\n" "Mesh group name\n") { - const char *vrfname; - char xpath_value[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; + char xpath_value[XPATH_MAXLEN + 26]; /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", - "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) return CMD_SUCCESS; nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } +DEFPY_ATTR(no_ip_pim_msdp_mesh_group, + no_ip_msdp_mesh_group_cmd, + "no ip msdp mesh-group WORD$gname", + NO_STR + IP_STR + CFG_MSDP_STR + "Delete MSDP mesh-group\n" + "Mesh group name\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char xpath_value[XPATH_MAXLEN + 26]; + int ret = CMD_SUCCESS; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* Get mesh group base XPath. */ + snprintf(xpath_value, sizeof(xpath_value), + "%s/msdp-mesh-groups[name='%s']", VTY_CURR_XPATH, gname); + if (yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { + nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + } + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, struct json_object *json) @@ -5329,7 +7077,8 @@ static void ip_msdp_show_mesh_group(struct vty *vty, struct pim_msdp_mg *mg, if (json) { /* currently there is only one mesh group but we should still * make - * it a dict with mg-name as key */ + * it a dict with mg-name as key + */ json_mg_row = json_object_new_object(); json_object_string_add(json_mg_row, "name", mg->mesh_group_name); @@ -6311,119 +8060,224 @@ DEFUN_HIDDEN (show_ip_pim_vxlan_sg_work, return CMD_SUCCESS; } -DEFUN_HIDDEN (no_ip_pim_mlag, - no_ip_pim_mlag_cmd, - "no ip pim mlag", +DEFPY_HIDDEN (no_pim_mlag, + no_pim_mlag_cmd, + "no mlag", NO_STR - IP_STR - PIM_STR "MLAG\n") { char mlag_xpath[XPATH_MAXLEN]; - snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath)); + snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); + nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); + + return nb_cli_apply_changes(vty, NULL); +} +DEFPY_ATTR(no_ip_pim_mlag, + no_ip_pim_mlag_cmd, + "no ip pim mlag", + NO_STR + IP_STR + PIM_STR + "MLAG\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) +{ + char mlag_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; + + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } + snprintf(mlag_xpath, sizeof(mlag_xpath), "./mlag"); nb_cli_enqueue_change(vty, mlag_xpath, NB_OP_DESTROY, NULL); + ret = nb_cli_apply_changes(vty, NULL); + + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } + + return ret; +} + +DEFPY_HIDDEN (pim_mlag, + pim_mlag_cmd, + "mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", + "MLAG\n" + "peerlink sub interface\n" + "MLAG role\n" + "MLAG role primary\n" + "MLAG role secondary\n" + "peer session state\n" + "peer session state up\n" + "peer session state down\n" + "configure PIP\n" + "unique ip address\n") +{ + char mlag_peerlink_rif_xpath[XPATH_MAXLEN]; + char mlag_my_role_xpath[XPATH_MAXLEN]; + char mlag_peer_state_xpath[XPATH_MAXLEN]; + char mlag_reg_address_xpath[XPATH_MAXLEN]; + + snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), + "./mlag/peerlink-rif"); + nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); + + snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), + "./mlag/my-role"); + if (!strcmp(role, "primary")) { + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_PRIMARY"); + } else if (!strcmp(role, "secondary")) { + nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, + "MLAG_ROLE_SECONDARY"); + } else { + vty_out(vty, "unknown MLAG role %s\n", role); + return CMD_WARNING; + } + + snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), + "./mlag/peer-state"); + if (!strcmp(state, "up")) { + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "true"); + } else if (strcmp(state, "down")) { + nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, + "false"); + } else { + vty_out(vty, "unknown MLAG state %s\n", state); + return CMD_WARNING; + } + snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), + "./mlag/reg-address"); + nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, + addr_str); return nb_cli_apply_changes(vty, NULL); } - -DEFUN_HIDDEN (ip_pim_mlag, - ip_pim_mlag_cmd, - "ip pim mlag INTERFACE role [primary|secondary] state [up|down] addr A.B.C.D", - IP_STR - PIM_STR - "MLAG\n" - "peerlink sub interface\n" - "MLAG role\n" - "MLAG role primary\n" - "MLAG role secondary\n" - "peer session state\n" - "peer session state up\n" - "peer session state down\n" - "configure PIP\n" - "unique ip address\n") +DEFPY_ATTR(ip_pim_mlag, + ip_pim_mlag_cmd, + "ip pim mlag INTERFACE$iface role [primary|secondary]$role state [up|down]$state addr A.B.C.D$addr", + IP_STR + PIM_STR + "MLAG\n" + "peerlink sub interface\n" + "MLAG role\n" + "MLAG role primary\n" + "MLAG role secondary\n" + "peer session state\n" + "peer session state up\n" + "peer session state down\n" + "configure PIP\n" + "unique ip address\n", + CMD_ATTR_HIDDEN | CMD_ATTR_DEPRECATED) { - int idx; char mlag_peerlink_rif_xpath[XPATH_MAXLEN]; char mlag_my_role_xpath[XPATH_MAXLEN]; char mlag_peer_state_xpath[XPATH_MAXLEN]; char mlag_reg_address_xpath[XPATH_MAXLEN]; + int ret; + const char *vrfname; + char xpath[XPATH_MAXLEN]; + int orig_node = -1; - snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif", - sizeof(mlag_peerlink_rif_xpath)); + vrfname = pim_cli_get_vrf_name(vty); + if (vrfname) { + snprintf(xpath, sizeof(xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + if (nb_cli_apply_changes_clear_pending(vty, NULL) == + CMD_SUCCESS) { + orig_node = vty->node; + VTY_PUSH_XPATH(PIM_NODE, xpath); + } else { + return CMD_WARNING_CONFIG_FAILED; + } + } else { + vty_out(vty, "%% Failed to determine vrf name\n"); + return CMD_WARNING_CONFIG_FAILED; + } - idx = 3; - nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, - argv[idx]->arg); + snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), + "./mlag/peerlink-rif"); + nb_cli_enqueue_change(vty, mlag_peerlink_rif_xpath, NB_OP_MODIFY, iface); snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_my_role_xpath, "/mlag/my-role", - sizeof(mlag_my_role_xpath)); - - idx += 2; - if (!strcmp(argv[idx]->arg, "primary")) { + "./mlag/my-role"); + if (!strcmp(role, "primary")) { nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, "MLAG_ROLE_PRIMARY"); - - } else if (!strcmp(argv[idx]->arg, "secondary")) { + } else if (!strcmp(role, "secondary")) { nb_cli_enqueue_change(vty, mlag_my_role_xpath, NB_OP_MODIFY, "MLAG_ROLE_SECONDARY"); - } else { - vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg); - return CMD_WARNING; + vty_out(vty, "unknown MLAG role %s\n", role); + ret = CMD_WARNING; + goto done; } snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_peer_state_xpath, "/mlag/peer-state", - sizeof(mlag_peer_state_xpath)); - - idx += 2; - if (!strcmp(argv[idx]->arg, "up")) { + "./mlag/peer-state"); + if (!strcmp(state, "up")) { nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, "true"); - - } else if (strcmp(argv[idx]->arg, "down")) { + } else if (strcmp(state, "down")) { nb_cli_enqueue_change(vty, mlag_peer_state_xpath, NB_OP_MODIFY, "false"); - } else { - vty_out(vty, "unknown MLAG state %s\n", argv[idx]->arg); - return CMD_WARNING; + vty_out(vty, "unknown MLAG state %s\n", state); + ret = CMD_WARNING; + goto done; } snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), - FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); - strlcat(mlag_reg_address_xpath, "/mlag/reg-address", - sizeof(mlag_reg_address_xpath)); - - idx += 2; + "./mlag/reg-address"); nb_cli_enqueue_change(vty, mlag_reg_address_xpath, NB_OP_MODIFY, - argv[idx]->arg); + addr_str); - return nb_cli_apply_changes(vty, NULL); -} + ret = nb_cli_apply_changes(vty, NULL); -void pim_cmd_init(void) -{ - if_cmd_init(pim_interface_config_write); +done: + if (orig_node != -1) { + vty->node = orig_node; + vty->xpath_index--; + } - install_node(&debug_node); + return ret; +} - install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); +struct cmd_node pim_node = { + .name = "pim", + .node = PIM_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim)# ", + .config_write = pim_router_config_write, +}; +/* This function installs all of the deprecated PIM configuration commands that live in the global config and/or VRF nodes + * This configuration has been moved to the new 'router pim' config node instead like all the other routing protocols. + * No new commands should be added here. + */ +static void pim_install_deprecated(void) +{ install_element(CONFIG_NODE, &ip_pim_rp_cmd); install_element(VRF_NODE, &ip_pim_rp_cmd); install_element(CONFIG_NODE, &no_ip_pim_rp_cmd); @@ -6449,8 +8303,8 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); install_element(VRF_NODE, &no_ip_pim_spt_switchover_infinity_plist_cmd); - install_element(CONFIG_NODE, &pim_register_accept_list_cmd); - install_element(VRF_NODE, &pim_register_accept_list_cmd); + install_element(CONFIG_NODE, &ip_pim_register_accept_list_cmd); + install_element(VRF_NODE, &ip_pim_register_accept_list_cmd); install_element(CONFIG_NODE, &ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &no_ip_pim_joinprune_time_cmd); install_element(CONFIG_NODE, &ip_pim_keep_alive_cmd); @@ -6467,14 +8321,6 @@ void pim_cmd_init(void) install_element(VRF_NODE, &ip_pim_v6_secondary_cmd); install_element(CONFIG_NODE, &no_ip_pim_v6_secondary_cmd); install_element(VRF_NODE, &no_ip_pim_v6_secondary_cmd); - install_element(CONFIG_NODE, &ip_ssmpingd_cmd); - install_element(VRF_NODE, &ip_ssmpingd_cmd); - install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); - install_element(VRF_NODE, &no_ip_ssmpingd_cmd); - install_element(CONFIG_NODE, &ip_msdp_peer_cmd); - install_element(VRF_NODE, &ip_msdp_peer_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); - install_element(VRF_NODE, &no_ip_msdp_peer_cmd); install_element(CONFIG_NODE, &ip_pim_ecmp_cmd); install_element(VRF_NODE, &ip_pim_ecmp_cmd); install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd); @@ -6485,10 +8331,91 @@ void pim_cmd_init(void) install_element(VRF_NODE, &no_ip_pim_ecmp_rebalance_cmd); install_element(CONFIG_NODE, &ip_pim_mlag_cmd); install_element(CONFIG_NODE, &no_ip_pim_mlag_cmd); - install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); - install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); - install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); - install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); + + install_element(CONFIG_NODE, &ip_ssmpingd_cmd); + install_element(VRF_NODE, &ip_ssmpingd_cmd); + install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); + install_element(VRF_NODE, &no_ip_ssmpingd_cmd); + + install_element(CONFIG_NODE, &ip_msdp_peer_cmd); + install_element(VRF_NODE, &ip_msdp_peer_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); + install_element(VRF_NODE, &no_ip_msdp_peer_cmd); + install_element(CONFIG_NODE, &ip_msdp_timers_cmd); + install_element(VRF_NODE, &ip_msdp_timers_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); + install_element(VRF_NODE, &no_ip_msdp_timers_cmd); + install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); + install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); + install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); + install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); +} + +void pim_cmd_init(void) +{ + if_cmd_init(pim_interface_config_write); + + install_node(&debug_node); + + install_element(CONFIG_NODE, &router_pim_cmd); + install_element(CONFIG_NODE, &no_router_pim_cmd); + + install_node(&pim_node); + install_default(PIM_NODE); + + install_element(PIM_NODE, &pim_rp_cmd); + install_element(PIM_NODE, &no_pim_rp_cmd); + install_element(PIM_NODE, &pim_rp_prefix_list_cmd); + install_element(PIM_NODE, &no_pim_rp_prefix_list_cmd); + install_element(PIM_NODE, &no_pim_ssm_prefix_list_cmd); + install_element(PIM_NODE, &no_pim_ssm_prefix_list_name_cmd); + install_element(PIM_NODE, &pim_ssm_prefix_list_cmd); + install_element(PIM_NODE, &pim_register_suppress_cmd); + install_element(PIM_NODE, &no_pim_register_suppress_cmd); + install_element(PIM_NODE, &pim_spt_switchover_infinity_cmd); + install_element(PIM_NODE, &pim_spt_switchover_infinity_plist_cmd); + install_element(PIM_NODE, &no_pim_spt_switchover_infinity_cmd); + install_element(PIM_NODE, &no_pim_spt_switchover_infinity_plist_cmd); + install_element(PIM_NODE, &pim_register_accept_list_cmd); + install_element(PIM_NODE, &pim_joinprune_time_cmd); + install_element(PIM_NODE, &no_pim_joinprune_time_cmd); + install_element(PIM_NODE, &pim_keep_alive_cmd); + install_element(PIM_NODE, &pim_rp_keep_alive_cmd); + install_element(PIM_NODE, &no_pim_keep_alive_cmd); + install_element(PIM_NODE, &no_pim_rp_keep_alive_cmd); + install_element(PIM_NODE, &pim_packets_cmd); + install_element(PIM_NODE, &no_pim_packets_cmd); + install_element(PIM_NODE, &pim_v6_secondary_cmd); + install_element(PIM_NODE, &no_pim_v6_secondary_cmd); + install_element(PIM_NODE, &pim_ecmp_cmd); + install_element(PIM_NODE, &no_pim_ecmp_cmd); + install_element(PIM_NODE, &pim_ecmp_rebalance_cmd); + install_element(PIM_NODE, &no_pim_ecmp_rebalance_cmd); + install_element(PIM_NODE, &pim_mlag_cmd); + install_element(PIM_NODE, &no_pim_mlag_cmd); + + install_element(PIM_NODE, &pim_ssmpingd_cmd); + install_element(PIM_NODE, &no_pim_ssmpingd_cmd); + + install_element(PIM_NODE, &pim_msdp_peer_cmd); + install_element(PIM_NODE, &no_pim_msdp_peer_cmd); + install_element(PIM_NODE, &msdp_peer_md5_cmd); + install_element(PIM_NODE, &no_msdp_peer_md5_cmd); + install_element(PIM_NODE, &pim_msdp_timers_cmd); + install_element(PIM_NODE, &no_pim_msdp_timers_cmd); + install_element(PIM_NODE, &msdp_peer_sa_filter_cmd); + install_element(PIM_NODE, &no_ip_msdp_peer_sa_filter_cmd); + install_element(PIM_NODE, &pim_msdp_mesh_group_member_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_member_cmd); + install_element(PIM_NODE, &pim_msdp_mesh_group_source_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_source_cmd); + install_element(PIM_NODE, &no_pim_msdp_mesh_group_cmd); install_element(INTERFACE_NODE, &interface_ip_igmp_cmd); install_element(INTERFACE_NODE, &interface_no_ip_igmp_cmd); @@ -6534,6 +8461,22 @@ void pim_cmd_init(void) install_element(INTERFACE_NODE, &interface_ip_mroute_cmd); install_element(INTERFACE_NODE, &interface_no_ip_mroute_cmd); + install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); + install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); + /* Install BSM command */ + install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); + install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); + /* Install BFD command */ + install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); + install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); + install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); +#if HAVE_BFDD == 0 + install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); +#endif /* !HAVE_BFDD */ + install_element(VIEW_NODE, &show_ip_igmp_interface_cmd); install_element(VIEW_NODE, &show_ip_igmp_interface_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_igmp_join_cmd); @@ -6590,8 +8533,23 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_pim_bsrp_cmd); install_element(VIEW_NODE, &show_ip_pim_bsm_db_cmd); install_element(VIEW_NODE, &show_ip_pim_statistics_cmd); + install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); + install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); + install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); + install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); + install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); + install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); + install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); + install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); + + install_element(ENABLE_NODE, &pim_test_sg_keepalive_cmd); install_element(ENABLE_NODE, &clear_ip_mroute_count_cmd); + install_element(ENABLE_NODE, &clear_ip_msdp_peer_cmd); install_element(ENABLE_NODE, &clear_ip_interfaces_cmd); install_element(ENABLE_NODE, &clear_ip_igmp_interfaces_cmd); install_element(ENABLE_NODE, &clear_ip_mroute_cmd); @@ -6604,134 +8562,98 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &show_debugging_pim_cmd); install_element(ENABLE_NODE, &debug_igmp_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_cmd); - install_element(ENABLE_NODE, &debug_igmp_events_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); - install_element(ENABLE_NODE, &debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); - install_element(ENABLE_NODE, &debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); - install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); - install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); - install_element(ENABLE_NODE, &debug_mroute_cmd); - install_element(ENABLE_NODE, &debug_mroute_detail_cmd); - install_element(ENABLE_NODE, &no_debug_mroute_cmd); - install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); - install_element(ENABLE_NODE, &debug_pim_static_cmd); - install_element(ENABLE_NODE, &no_debug_pim_static_cmd); - install_element(ENABLE_NODE, &debug_pim_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); - install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); - install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); - install_element(ENABLE_NODE, &debug_pim_events_cmd); - install_element(ENABLE_NODE, &debug_pim_packets_cmd); - install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); - install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); - install_element(ENABLE_NODE, &debug_pim_trace_cmd); - install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); - install_element(ENABLE_NODE, &debug_ssmpingd_cmd); - install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); - install_element(ENABLE_NODE, &debug_pim_zebra_cmd); - install_element(ENABLE_NODE, &debug_pim_mlag_cmd); - install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); - install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); - install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); - install_element(ENABLE_NODE, &debug_msdp_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_cmd); - install_element(ENABLE_NODE, &debug_msdp_events_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); - install_element(ENABLE_NODE, &debug_msdp_packets_cmd); - install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); - install_element(ENABLE_NODE, &debug_mtrace_cmd); - install_element(ENABLE_NODE, &no_debug_mtrace_cmd); - install_element(ENABLE_NODE, &debug_bsm_cmd); - install_element(ENABLE_NODE, &no_debug_bsm_cmd); - install_element(CONFIG_NODE, &debug_igmp_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_cmd); install_element(CONFIG_NODE, &no_debug_igmp_cmd); + install_element(ENABLE_NODE, &debug_igmp_events_cmd); install_element(CONFIG_NODE, &debug_igmp_events_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_events_cmd); install_element(CONFIG_NODE, &no_debug_igmp_events_cmd); + install_element(ENABLE_NODE, &debug_igmp_packets_cmd); install_element(CONFIG_NODE, &debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_packets_cmd); install_element(CONFIG_NODE, &no_debug_igmp_packets_cmd); + install_element(ENABLE_NODE, &debug_igmp_trace_cmd); install_element(CONFIG_NODE, &debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_trace_cmd); install_element(CONFIG_NODE, &no_debug_igmp_trace_cmd); + install_element(ENABLE_NODE, &debug_igmp_trace_detail_cmd); install_element(CONFIG_NODE, &debug_igmp_trace_detail_cmd); + install_element(ENABLE_NODE, &no_debug_igmp_trace_detail_cmd); install_element(CONFIG_NODE, &no_debug_igmp_trace_detail_cmd); + install_element(ENABLE_NODE, &debug_mroute_cmd); install_element(CONFIG_NODE, &debug_mroute_cmd); + install_element(ENABLE_NODE, &debug_mroute_detail_cmd); install_element(CONFIG_NODE, &debug_mroute_detail_cmd); + install_element(ENABLE_NODE, &no_debug_mroute_cmd); install_element(CONFIG_NODE, &no_debug_mroute_cmd); + install_element(ENABLE_NODE, &no_debug_mroute_detail_cmd); install_element(CONFIG_NODE, &no_debug_mroute_detail_cmd); + install_element(ENABLE_NODE, &debug_pim_static_cmd); install_element(CONFIG_NODE, &debug_pim_static_cmd); + install_element(ENABLE_NODE, &no_debug_pim_static_cmd); install_element(CONFIG_NODE, &no_debug_pim_static_cmd); + install_element(ENABLE_NODE, &debug_pim_cmd); install_element(CONFIG_NODE, &debug_pim_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_cmd); install_element(CONFIG_NODE, &debug_pim_nht_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_det_cmd); install_element(CONFIG_NODE, &debug_pim_nht_det_cmd); + install_element(ENABLE_NODE, &debug_pim_nht_rp_cmd); install_element(CONFIG_NODE, &debug_pim_nht_rp_cmd); + install_element(ENABLE_NODE, &no_debug_pim_nht_rp_cmd); install_element(CONFIG_NODE, &no_debug_pim_nht_rp_cmd); + install_element(ENABLE_NODE, &debug_pim_events_cmd); install_element(CONFIG_NODE, &debug_pim_events_cmd); + install_element(ENABLE_NODE, &debug_pim_packets_cmd); install_element(CONFIG_NODE, &debug_pim_packets_cmd); + install_element(ENABLE_NODE, &debug_pim_packetdump_send_cmd); install_element(CONFIG_NODE, &debug_pim_packetdump_send_cmd); + install_element(ENABLE_NODE, &debug_pim_packetdump_recv_cmd); install_element(CONFIG_NODE, &debug_pim_packetdump_recv_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_cmd); install_element(CONFIG_NODE, &debug_pim_trace_cmd); + install_element(ENABLE_NODE, &debug_pim_trace_detail_cmd); install_element(CONFIG_NODE, &debug_pim_trace_detail_cmd); + install_element(ENABLE_NODE, &debug_ssmpingd_cmd); install_element(CONFIG_NODE, &debug_ssmpingd_cmd); + install_element(ENABLE_NODE, &no_debug_ssmpingd_cmd); install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd); + install_element(ENABLE_NODE, &debug_pim_zebra_cmd); install_element(CONFIG_NODE, &debug_pim_zebra_cmd); + install_element(ENABLE_NODE, &debug_pim_mlag_cmd); install_element(CONFIG_NODE, &debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd); + install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &debug_pim_vxlan_cmd); + install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd); + install_element(ENABLE_NODE, &debug_msdp_cmd); install_element(CONFIG_NODE, &debug_msdp_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_cmd); install_element(CONFIG_NODE, &no_debug_msdp_cmd); + install_element(ENABLE_NODE, &debug_msdp_events_cmd); install_element(CONFIG_NODE, &debug_msdp_events_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); install_element(CONFIG_NODE, &no_debug_msdp_events_cmd); + install_element(ENABLE_NODE, &debug_msdp_packets_cmd); install_element(CONFIG_NODE, &debug_msdp_packets_cmd); + install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd); + install_element(ENABLE_NODE, &debug_mtrace_cmd); install_element(CONFIG_NODE, &debug_mtrace_cmd); + install_element(ENABLE_NODE, &no_debug_mtrace_cmd); install_element(CONFIG_NODE, &no_debug_mtrace_cmd); + install_element(ENABLE_NODE, &debug_bsm_cmd); install_element(CONFIG_NODE, &debug_bsm_cmd); + install_element(ENABLE_NODE, &no_debug_bsm_cmd); install_element(CONFIG_NODE, &no_debug_bsm_cmd); - install_element(CONFIG_NODE, &ip_msdp_timers_cmd); - install_element(VRF_NODE, &ip_msdp_timers_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); - install_element(VRF_NODE, &no_ip_msdp_timers_cmd); - install_element(CONFIG_NODE, &ip_msdp_mesh_group_member_cmd); - install_element(VRF_NODE, &ip_msdp_mesh_group_member_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_member_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_member_cmd); - install_element(CONFIG_NODE, &ip_msdp_mesh_group_source_cmd); - install_element(VRF_NODE, &ip_msdp_mesh_group_source_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_source_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_source_cmd); - install_element(CONFIG_NODE, &no_ip_msdp_mesh_group_cmd); - install_element(VRF_NODE, &no_ip_msdp_mesh_group_cmd); - install_element(VIEW_NODE, &show_ip_msdp_peer_detail_cmd); - install_element(VIEW_NODE, &show_ip_msdp_peer_detail_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_detail_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_detail_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_sg_cmd); - install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); - install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); - install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); - install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); - install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); - install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_work_cmd); - install_element(INTERFACE_NODE, &interface_pim_use_source_cmd); - install_element(INTERFACE_NODE, &interface_no_pim_use_source_cmd); - /* Install BSM command */ - install_element(INTERFACE_NODE, &ip_pim_bsm_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bsm_cmd); - install_element(INTERFACE_NODE, &ip_pim_ucast_bsm_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_ucast_bsm_cmd); - /* Install BFD command */ - install_element(INTERFACE_NODE, &ip_pim_bfd_cmd); - install_element(INTERFACE_NODE, &ip_pim_bfd_param_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bfd_profile_cmd); - install_element(INTERFACE_NODE, &no_ip_pim_bfd_cmd); -#if HAVE_BFDD == 0 - install_element(INTERFACE_NODE, &no_ip_pim_bfd_param_cmd); -#endif /* !HAVE_BFDD */ + install_element(CONFIG_NODE, &ip_igmp_group_watermark_cmd); + install_element(VRF_NODE, &ip_igmp_group_watermark_cmd); + install_element(CONFIG_NODE, &no_ip_igmp_group_watermark_cmd); + install_element(VRF_NODE, &no_ip_igmp_group_watermark_cmd); + + pim_install_deprecated(); } diff --git a/pimd/pim_cmd_common.c b/pimd/pim_cmd_common.c index 5e50a09355..d1368ff1ff 100644 --- a/pimd/pim_cmd_common.c +++ b/pimd/pim_cmd_common.c @@ -100,25 +100,13 @@ int pim_process_no_join_prune_cmd(struct vty *vty) int pim_process_spt_switchover_infinity_cmd(struct vty *vty) { - const char *vrfname; - char spt_plist_xpath[XPATH_MAXLEN]; - char spt_action_xpath[XPATH_MAXLEN]; - - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; + char spt_plist_xpath[XPATH_MAXLEN + 40]; + char spt_action_xpath[XPATH_MAXLEN + 26]; snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "%s/spt-switchover/spt-infinity-prefix-list", VTY_CURR_XPATH); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "%s/spt-switchover/spt-action", VTY_CURR_XPATH); if (yang_dnode_exists(vty->candidate_config->dnode, spt_plist_xpath)) nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, @@ -132,55 +120,30 @@ int pim_process_spt_switchover_infinity_cmd(struct vty *vty) int pim_process_spt_switchover_prefixlist_cmd(struct vty *vty, const char *plist) { - const char *vrfname; char spt_plist_xpath[XPATH_MAXLEN]; char spt_action_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "./spt-switchover/spt-infinity-prefix-list"); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "./spt-switchover/spt-action"); nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, "PIM_SPT_INFINITY"); - nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, - plist); + nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_MODIFY, plist); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_spt_switchover_cmd(struct vty *vty) { - const char *vrfname; char spt_plist_xpath[XPATH_MAXLEN]; char spt_action_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", - sizeof(spt_plist_xpath)); - + "./spt-switchover/spt-infinity-prefix-list"); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(spt_action_xpath, "/spt-switchover/spt-action", - sizeof(spt_action_xpath)); + "./spt-switchover/spt-action"); nb_cli_enqueue_change(vty, spt_plist_xpath, NB_OP_DESTROY, NULL); nb_cli_enqueue_change(vty, spt_action_xpath, NB_OP_MODIFY, @@ -217,35 +180,20 @@ int pim_process_no_pim_packet_cmd(struct vty *vty) int pim_process_keepalivetimer_cmd(struct vty *vty, const char *kat) { - const char *vrfname; char ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); - - nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, - kat); + nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, kat); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_keepalivetimer_cmd(struct vty *vty) { - const char *vrfname; char ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL); - strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), "./keep-alive-timer"); nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL); @@ -254,35 +202,25 @@ int pim_process_no_keepalivetimer_cmd(struct vty *vty) int pim_process_rp_kat_cmd(struct vty *vty, const char *rpkat) { - const char *vrfname; char rp_ka_timer_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); + "./rp-keep-alive-timer"); - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - rpkat); + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rpkat); return nb_cli_apply_changes(vty, NULL); } int pim_process_no_rp_kat_cmd(struct vty *vty) { - const char *vrfname; char rp_ka_timer[6]; char rp_ka_timer_xpath[XPATH_MAXLEN]; uint v; char rs_timer_xpath[XPATH_MAXLEN]; - snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), - FRR_PIM_ROUTER_XPATH, FRR_PIM_AF_XPATH_VAL); + snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), FRR_PIM_ROUTER_XPATH, + FRR_PIM_AF_XPATH_VAL); strlcat(rs_timer_xpath, "/register-suppress-time", sizeof(rs_timer_xpath)); @@ -301,18 +239,10 @@ int pim_process_no_rp_kat_cmd(struct vty *vty) v = UINT16_MAX; snprintf(rp_ka_timer, sizeof(rp_ka_timer), "%u", v); - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); - strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", - sizeof(rp_ka_timer_xpath)); + "./rp-keep-alive-timer"); - nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, - rp_ka_timer); + nb_cli_enqueue_change(vty, rp_ka_timer_xpath, NB_OP_MODIFY, rp_ka_timer); return nb_cli_apply_changes(vty, NULL); } @@ -531,9 +461,7 @@ int pim_process_no_ip_mroute_cmd(struct vty *vty, const char *interface, int pim_process_rp_cmd(struct vty *vty, const char *rp_str, const char *group_str) { - const char *vrfname; char group_xpath[XPATH_MAXLEN]; - char rp_xpath[XPATH_MAXLEN]; int printed; int result = 0; struct prefix group; @@ -575,14 +503,9 @@ int pim_process_rp_cmd(struct vty *vty, const char *rp_str, } #endif - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); printed = snprintf(group_xpath, sizeof(group_xpath), - "%s/group-list[.='%s']", rp_xpath, group_str); + "./" FRR_PIM_STATIC_RP_XPATH "/group-list[.='%s']", + rp_str, group_str); if (printed >= (int)(sizeof(group_xpath))) { vty_out(vty, "Xpath too long (%d > %u)", printed + 1, @@ -599,17 +522,12 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, const char *group_str) { char group_xpath[XPATH_MAXLEN]; - char rp_xpath[XPATH_MAXLEN]; + char rp_xpath[XPATH_MAXLEN + 47]; int printed; - const char *vrfname; const struct lyd_node *group_dnode; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, + VTY_CURR_XPATH, rp_str); printed = snprintf(group_xpath, sizeof(group_xpath), "%s/group-list[.='%s']", rp_xpath, group_str); @@ -636,16 +554,10 @@ int pim_process_no_rp_cmd(struct vty *vty, const char *rp_str, int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list) { - const char *vrfname; char rp_plist_xpath[XPATH_MAXLEN]; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - snprintf(rp_plist_xpath, sizeof(rp_plist_xpath), - FRR_PIM_STATIC_RP_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL, rp_str); + "./" FRR_PIM_STATIC_RP_XPATH, rp_str); strlcat(rp_plist_xpath, "/prefix-list", sizeof(rp_plist_xpath)); nb_cli_enqueue_change(vty, rp_plist_xpath, NB_OP_MODIFY, prefix_list); @@ -656,21 +568,14 @@ int pim_process_rp_plist_cmd(struct vty *vty, const char *rp_str, int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, const char *prefix_list) { - char rp_xpath[XPATH_MAXLEN]; - char plist_xpath[XPATH_MAXLEN]; - const char *vrfname; + char rp_xpath[XPATH_MAXLEN + 47]; + char plist_xpath[XPATH_MAXLEN + 1070]; const struct lyd_node *plist_dnode; const char *plist; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(rp_xpath, sizeof(rp_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); - - snprintf(plist_xpath, sizeof(plist_xpath), FRR_PIM_STATIC_RP_XPATH, - "frr-pim:pimd", "pim", vrfname, FRR_PIM_AF_XPATH_VAL, rp_str); + snprintf(rp_xpath, sizeof(rp_xpath), "%s/" FRR_PIM_STATIC_RP_XPATH, + VTY_CURR_XPATH, rp_str); + snprintf(plist_xpath, sizeof(plist_xpath), "%s", rp_xpath); strlcat(plist_xpath, "/prefix-list", sizeof(plist_xpath)); plist_dnode = yang_dnode_get(vty->candidate_config->dnode, plist_xpath); @@ -679,7 +584,7 @@ int pim_process_no_rp_plist_cmd(struct vty *vty, const char *rp_str, return NB_OK; } - plist = yang_dnode_get_string(plist_dnode, "%s", plist_xpath); + plist = yang_dnode_get_string(plist_dnode, NULL); if (strcmp(prefix_list, plist)) { vty_out(vty, "%% Unable to find specified RP\n"); return NB_OK; @@ -3408,21 +3313,11 @@ int gm_process_no_last_member_query_interval_cmd(struct vty *vty) int pim_process_ssmpingd_cmd(struct vty *vty, enum nb_operation operation, const char *src_str) { - const char *vrfname; - char ssmpingd_ip_xpath[XPATH_MAXLEN]; char ssmpingd_src_ip_xpath[XPATH_MAXLEN]; int printed; - vrfname = pim_cli_get_vrf_name(vty); - if (vrfname == NULL) - return CMD_WARNING_CONFIG_FAILED; - - snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath), - FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, - FRR_PIM_AF_XPATH_VAL); printed = snprintf(ssmpingd_src_ip_xpath, sizeof(ssmpingd_src_ip_xpath), - "%s/ssm-pingd-source-ip[.='%s']", ssmpingd_ip_xpath, - src_str); + "./ssm-pingd-source-ip[.='%s']", src_str); if (printed >= (int)sizeof(ssmpingd_src_ip_xpath)) { vty_out(vty, "Xpath too long (%d > %u)", printed + 1, XPATH_MAXLEN); @@ -5705,3 +5600,34 @@ int pim_show_bsm_db_helper(const char *vrf, struct vty *vty, bool uj) return CMD_SUCCESS; } + +int pim_router_config_write(struct vty *vty) +{ + struct vrf *vrf; + struct pim_instance *pim; + int writes = 0; + char framestr[64] = { 0 }; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + pim = vrf->info; + + if (!pim) + continue; + + snprintfrr(framestr, sizeof(framestr), "router %s", + PIM_AF_ROUTER); + if (vrf->vrf_id != VRF_DEFAULT) { + strlcat(framestr, " vrf ", sizeof(framestr)); + strlcat(framestr, vrf->name, sizeof(framestr)); + } + vty_frame(vty, "%s\n", framestr); + ++writes; + + writes += pim_global_config_write_worker(pim, vty); + + vty_endframe(vty, "exit\n"); + ++writes; + } + + return writes; +} diff --git a/pimd/pim_cmd_common.h b/pimd/pim_cmd_common.h index e30203fad7..da2e44be58 100644 --- a/pimd/pim_cmd_common.h +++ b/pimd/pim_cmd_common.h @@ -182,6 +182,8 @@ int pim_show_interface_traffic_helper(const char *vrf, const char *if_name, void clear_pim_interfaces(struct pim_instance *pim); void pim_show_bsr(struct pim_instance *pim, struct vty *vty, bool uj); int pim_show_bsr_helper(const char *vrf, struct vty *vty, bool uj); +int pim_router_config_write(struct vty *vty); + /* * Special Macro to allow us to get the correct pim_instance; */ diff --git a/pimd/pim_instance.c b/pimd/pim_instance.c index b3410d15af..a9eec9a9d2 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -201,6 +201,7 @@ static int pim_vrf_config_write(struct vty *vty) { struct vrf *vrf; struct pim_instance *pim; + char spaces[10]; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { pim = vrf->info; @@ -208,10 +209,24 @@ static int pim_vrf_config_write(struct vty *vty) if (!pim) continue; - if (vrf->vrf_id != VRF_DEFAULT) + if (vrf->vrf_id != VRF_DEFAULT) { vty_frame(vty, "vrf %s\n", vrf->name); - - pim_global_config_write_worker(pim, vty); + snprintf(spaces, sizeof(spaces), "%s", " "); + } else { + snprintf(spaces, sizeof(spaces), "%s", ""); + } + + /* Global IGMP/MLD configuration */ + if (pim->gm_watermark_limit != 0) { +#if PIM_IPV == 4 + vty_out(vty, + "%s" PIM_AF_NAME " igmp watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#else + vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", + spaces, pim->gm_watermark_limit); +#endif + } if (vrf->vrf_id != VRF_DEFAULT) vty_endframe(vty, "exit-vrf\n!\n"); diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 400db396c2..8f2ce0bed3 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -59,6 +59,7 @@ struct zebra_privs_t pimd_privs = { .cap_num_p = array_size(_caps_p), .cap_num_i = 0}; +/* clang-format off */ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_filter_info, &frr_interface_info, @@ -70,7 +71,6 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_gmp_info, }; -/* clang-format off */ FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT, .proghelp = "Implementation of the PIM routing protocol.", diff --git a/pimd/pim_memory.c b/pimd/pim_memory.c index 85780f013b..604e24482d 100644 --- a/pimd/pim_memory.c +++ b/pimd/pim_memory.c @@ -26,6 +26,7 @@ DEFINE_MTYPE(PIMD, PIM_RP, "PIM RP info"); DEFINE_MTYPE(PIMD, PIM_FILTER_NAME, "PIM RP filter info"); DEFINE_MTYPE(PIMD, PIM_MSDP_PEER, "PIM MSDP peer"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG_NAME, "PIM MSDP mesh-group name"); +DEFINE_MTYPE(PIMD, PIM_MSDP_AUTH_KEY, "PIM MSDP authentication key"); DEFINE_MTYPE(PIMD, PIM_MSDP_SA, "PIM MSDP source-active cache"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG, "PIM MSDP mesh group"); DEFINE_MTYPE(PIMD, PIM_MSDP_MG_MBR, "PIM MSDP mesh group mbr"); diff --git a/pimd/pim_memory.h b/pimd/pim_memory.h index 41730e7522..353e09a71c 100644 --- a/pimd/pim_memory.h +++ b/pimd/pim_memory.h @@ -28,6 +28,7 @@ DECLARE_MTYPE(PIM_MSDP_MG_NAME); DECLARE_MTYPE(PIM_MSDP_SA); DECLARE_MTYPE(PIM_MSDP_MG); DECLARE_MTYPE(PIM_MSDP_MG_MBR); +DECLARE_MTYPE(PIM_MSDP_AUTH_KEY); DECLARE_MTYPE(PIM_SEC_ADDR); DECLARE_MTYPE(PIM_JP_AGG_GROUP); DECLARE_MTYPE(PIM_JP_AGG_SOURCE); diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index ea8c84cca5..215cc3c502 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -773,7 +773,10 @@ static void pim_msdp_peer_listen(struct pim_msdp_peer *mp) * first listening peer is configured; but don't bother tearing it down * when * all the peers go down */ - pim_msdp_sock_listen(mp->pim); + if (mp->auth_type == MSDP_AUTH_NONE) + pim_msdp_sock_listen(mp->pim); + else + pim_msdp_sock_auth_listen(mp); } /* 11.2.A4 and 11.2.A5: transition active or passive peer to @@ -1045,6 +1048,7 @@ struct pim_msdp_peer *pim_msdp_peer_add(struct pim_instance *pim, mp->state = PIM_MSDP_INACTIVE; mp->fd = -1; + mp->auth_listen_sock = -1; strlcpy(mp->last_reset, "-", sizeof(mp->last_reset)); /* higher IP address is listener */ if (ntohl(mp->local.s_addr) > ntohl(mp->peer.s_addr)) { @@ -1100,6 +1104,12 @@ static void pim_msdp_peer_free(struct pim_msdp_peer *mp) stream_fifo_free(mp->obuf); } + /* Free authentication data. */ + event_cancel(&mp->auth_listen_ev); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + if (mp->auth_listen_sock != -1) + close(mp->auth_listen_sock); + XFREE(MTYPE_PIM_MSDP_MG_NAME, mp->mesh_group_name); mp->pim = NULL; @@ -1128,19 +1138,32 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp) *mp = NULL; } -void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, - const struct in_addr *addr) +void pim_msdp_peer_restart(struct pim_msdp_peer *mp) { - pim_msdp_peer_stop_tcp_conn(mp, true); + /* Stop auth listening socket if any. */ + event_cancel(&mp->auth_listen_ev); + if (mp->auth_listen_sock != -1) { + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; + } - mp->local = *addr; + /* Stop previously running connection. */ + pim_msdp_peer_stop_tcp_conn(mp, true); + /* Start connection again. */ if (PIM_MSDP_PEER_IS_LISTENER(mp)) pim_msdp_peer_listen(mp); else pim_msdp_peer_connect(mp); } +void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, + const struct in_addr *addr) +{ + mp->local = *addr; + pim_msdp_peer_restart(mp); +} + /* peer hash and peer list helpers */ static unsigned int pim_msdp_peer_hash_key_make(const void *p) { @@ -1274,8 +1297,7 @@ static void pim_msdp_src_del(struct pim_msdp_mg *mg) } /*********************** MSDP feature APIs *********************************/ -int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces) +int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty) { struct pim_msdp_mg *mg; struct listnode *mbrnode; @@ -1290,14 +1312,14 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, if (mg->src_ip.s_addr != INADDR_ANY) { pim_inet4_dump("", mg->src_ip, src_str, sizeof(src_str)); - vty_out(vty, "%sip msdp mesh-group %s source %s\n", - spaces, mg->mesh_group_name, src_str); + vty_out(vty, " msdp mesh-group %s source %s\n", + mg->mesh_group_name, src_str); ++count; } for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) { - vty_out(vty, "%sip msdp mesh-group %s member %pI4\n", - spaces, mg->mesh_group_name, &mbr->mbr_ip); + vty_out(vty, " msdp mesh-group %s member %pI4\n", + mg->mesh_group_name, &mbr->mbr_ip); ++count; } } @@ -1305,8 +1327,7 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, return count; } -bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, - const char *spaces) +bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim) { struct pim_msdp_peer *mp; struct listnode *node; @@ -1317,8 +1338,21 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, if (mp->flags & PIM_MSDP_PEERF_IN_GROUP) continue; - vty_out(vty, "%sip msdp peer %pI4 source %pI4\n", spaces, - &mp->peer, &mp->local); + vty_out(vty, " msdp peer %pI4 source %pI4\n", &mp->peer, + &mp->local); + + if (mp->auth_type == MSDP_AUTH_MD5) + vty_out(vty, " msdp peer %pI4 password %s\n", &mp->peer, + mp->auth_key); + + if (mp->acl_in) + vty_out(vty, " msdp peer %pI4 sa-filter %s in\n", + &mp->peer, mp->acl_in); + + if (mp->acl_out) + vty_out(vty, " msdp peer %pI4 sa-filter %s out\n", + &mp->peer, mp->acl_out); + written = true; } diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index ddc015f9b6..f77b0e1a3a 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -89,6 +89,11 @@ enum pim_msdp_peer_flags { PIM_MSDP_PEERF_IN_GROUP = (1 << 2), }; +enum msdp_auth_type { + MSDP_AUTH_NONE = 0, + MSDP_AUTH_MD5 = 1, +}; + struct pim_msdp_peer { struct pim_instance *pim; @@ -98,6 +103,13 @@ struct pim_msdp_peer { char *mesh_group_name; char key_str[INET_ADDRSTRLEN]; + /* Authentication data. */ + enum msdp_auth_type auth_type; + char *auth_key; + + int auth_listen_sock; + struct event *auth_listen_ev; + /* state */ enum pim_msdp_peer_state state; enum pim_msdp_peer_flags flags; @@ -138,6 +150,11 @@ struct pim_msdp_peer { /* timestamps */ int64_t uptime; + + /** SA input access list name. */ + char *acl_in; + /** SA output access list name. */ + char *acl_out; }; struct pim_msdp_mg_mbr { @@ -228,10 +245,8 @@ void pim_msdp_peer_pkt_rxed(struct pim_msdp_peer *mp); void pim_msdp_peer_stop_tcp_conn(struct pim_msdp_peer *mp, bool chg_state); void pim_msdp_peer_reset_tcp_conn(struct pim_msdp_peer *mp, const char *rc_str); void pim_msdp_write(struct event *thread); -int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces); -bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, - const char *spaces); +int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty); +bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim); void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp); void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, pim_sgaddr *sg, struct in_addr rp); @@ -306,6 +321,15 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp); void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, const struct in_addr *addr); +/** + * Restart peer's connection. + * + * This is used internally in MSDP and should be used by northbound + * when wanting to immediately apply connections settings such as + * authentication. + */ +void pim_msdp_peer_restart(struct pim_msdp_peer *mp); + #else /* PIM_IPV == 6 */ static inline void pim_msdp_init(struct pim_instance *pim, struct event_loop *master) @@ -339,14 +363,13 @@ static inline void pim_msdp_sa_local_del(struct pim_instance *pim, } static inline int pim_msdp_config_write(struct pim_instance *pim, - struct vty *vty, const char *spaces) + struct vty *vty) { return 0; } static inline bool pim_msdp_peer_config_write(struct vty *vty, - struct pim_instance *pim, - const char *spaces) + struct pim_instance *pim) { return false; } diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index 4324a96bef..27f4966a1c 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -6,7 +6,9 @@ #include #include +#include #include +#include #include #include "frrevent.h" #include @@ -322,8 +324,8 @@ void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp) pim_msdp_pkt_send(mp, s); } -static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim, - struct pim_msdp_peer *mp) +static void pim_msdp_pkt_sa_push(struct pim_instance *pim, + struct pim_msdp_peer *mp) { struct stream *s; @@ -338,25 +340,6 @@ static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim, } } -/* push the stream into the obuf fifo of all the peers */ -static void pim_msdp_pkt_sa_push(struct pim_instance *pim, - struct pim_msdp_peer *mp) -{ - struct listnode *mpnode; - - if (mp) { - pim_msdp_pkt_sa_push_to_one_peer(pim, mp); - } else { - for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) { - if (PIM_DEBUG_MSDP_INTERNAL) { - zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push", - mp->key_str); - } - pim_msdp_pkt_sa_push_to_one_peer(pim, mp); - } - } -} - static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt, struct in_addr rp) { @@ -384,6 +367,90 @@ static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa) stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr); } +static bool msdp_cisco_match(const struct filter *filter, + const struct in_addr *source, + const struct in_addr *group) +{ + const struct filter_cisco *cfilter = &filter->u.cfilter; + uint32_t source_addr; + uint32_t group_addr; + + group_addr = group->s_addr & ~cfilter->mask_mask.s_addr; + + if (cfilter->extended) { + source_addr = source->s_addr & ~cfilter->addr_mask.s_addr; + if (group_addr == cfilter->mask.s_addr && + source_addr == cfilter->addr.s_addr) + return true; + } else if (group_addr == cfilter->addr.s_addr) + return true; + + return false; +} + +static enum filter_type msdp_access_list_apply(struct access_list *access, + const struct in_addr *source, + const struct in_addr *group) +{ + struct filter *filter; + struct prefix group_prefix; + + if (access == NULL) + return FILTER_DENY; + + for (filter = access->head; filter; filter = filter->next) { + if (filter->cisco) { + if (msdp_cisco_match(filter, source, group)) + return filter->type; + } else { + group_prefix.family = AF_INET; + group_prefix.prefixlen = IPV4_MAX_BITLEN; + group_prefix.u.prefix4.s_addr = group->s_addr; + if (access_list_apply(access, &group_prefix)) + return filter->type; + } + } + + return FILTER_DENY; +} + +bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, + const struct pim_msdp_sa *sa) +{ + struct access_list *acl; + + /* No output filter configured, just quit. */ + if (mp->acl_out == NULL) + return false; + + /* Find access list and test it. */ + acl = access_list_lookup(AFI_IP, mp->acl_out); + if (msdp_access_list_apply(acl, &sa->sg.src, &sa->sg.grp) == FILTER_DENY) + return true; + + return false; +} + +/** Count the number of SAs to be sent for a specific peer. */ +static size_t pim_msdp_peer_sa_count(const struct pim_instance *pim, + const struct pim_msdp_peer *peer) +{ + const struct pim_msdp_sa *sa; + const struct listnode *node; + size_t sa_count = 0; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, node, sa)) { + if (!CHECK_FLAG(sa->flags, PIM_MSDP_SAF_LOCAL)) + continue; + if (msdp_peer_sa_filter(peer, sa)) + continue; + + sa_count++; + } + + return sa_count; +} + static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, struct pim_msdp_peer *mp) { @@ -393,7 +460,7 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, struct prefix group_all; struct in_addr rp; int sa_count; - int local_cnt = pim->msdp.local_cnt; + int local_cnt = pim_msdp_peer_sa_count(pim, mp); sa_count = 0; if (PIM_DEBUG_MSDP_INTERNAL) { @@ -418,6 +485,15 @@ static void pim_msdp_pkt_sa_gen(struct pim_instance *pim, * peers */ continue; } + + if (msdp_peer_sa_filter(mp, sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out %s", + &mp->peer, sa->sg_str); + + continue; + } + /* add sa into scratch pad */ pim_msdp_pkt_sa_fill_one(sa); ++sa_count; @@ -457,15 +533,32 @@ static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim) void pim_msdp_pkt_sa_tx(struct pim_instance *pim) { - pim_msdp_pkt_sa_gen(pim, NULL /* mp */); + struct pim_msdp_peer *mp; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, node, mp)) + pim_msdp_pkt_sa_gen(pim, mp); + pim_msdp_pkt_sa_tx_done(pim); } void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa) { + struct pim_msdp_peer *mp; + struct listnode *node; + pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp); pim_msdp_pkt_sa_fill_one(sa); - pim_msdp_pkt_sa_push(sa->pim, NULL); + for (ALL_LIST_ELEMENTS_RO(sa->pim->msdp.peer_list, node, mp)) { + if (msdp_peer_sa_filter(mp, sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out %s", + &mp->peer, sa->sg_str); + continue; + } + + pim_msdp_pkt_sa_push(sa->pim, mp); + } pim_msdp_pkt_sa_tx_done(sa->pim); } @@ -487,6 +580,15 @@ void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, /* Fills the message contents. */ sa.pim = mp->pim; sa.sg = sg; + + /* Don't push it if filtered. */ + if (msdp_peer_sa_filter(mp, &sa)) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA out (%pI4, %pI4)", + &mp->peer, &sa.sg.src, &sa.sg.grp); + return; + } + pim_msdp_pkt_sa_fill_one(&sa); /* Pushes the message. */ @@ -511,6 +613,7 @@ static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len) static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) { + struct access_list *acl; int prefix_len; pim_sgaddr sg; struct listnode *peer_node; @@ -534,6 +637,19 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) if (PIM_DEBUG_MSDP_PACKETS) { zlog_debug(" sg %pSG", &sg); } + + /* Filter incoming SA with configured access list. */ + if (mp->acl_in) { + acl = access_list_lookup(AFI_IP, mp->acl_in); + if (msdp_access_list_apply(acl, &sg.src, &sg.grp) == + FILTER_DENY) { + if (PIM_DEBUG_MSDP_EVENTS) + zlog_debug("MSDP peer %pI4 filter SA in (%pI4, %pI4)", + &mp->peer, &sg.src, &sg.grp); + return; + } + } + pim_msdp_sa_ref(mp->pim, mp, &sg, rp); /* Forwards the SA to the peers that are not in the RPF to the RP nor in diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h index 1584a24539..3af8d93685 100644 --- a/pimd/pim_msdp_packet.h +++ b/pimd/pim_msdp_packet.h @@ -57,5 +57,7 @@ void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa); void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp); void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, struct in_addr rp, pim_sgaddr sg); +bool msdp_peer_sa_filter(const struct pim_msdp_peer *mp, + const struct pim_msdp_sa *sa); #endif diff --git a/pimd/pim_msdp_socket.c b/pimd/pim_msdp_socket.c index fe8d5e934a..2fb0bb87c7 100644 --- a/pimd/pim_msdp_socket.c +++ b/pimd/pim_msdp_socket.c @@ -49,6 +49,192 @@ static void pim_msdp_update_sock_send_buffer_size(int fd) } } +/** + * Helper function to reduce code duplication. + * + * \param vrf VRF pointer (`NULL` means default VRF) + * \param mp the MSDP session pointer. + * \returns valid file descriptor otherwise `-1`. + */ +static int _pim_msdp_sock_listen(const struct vrf *vrf, + const struct pim_msdp_peer *mp) +{ + const struct interface *ifp; + int sock; + int rv; + socklen_t socklen; + struct sockaddr_in sin = {}; + union sockunion su_peer = {}; + + sock = socket(AF_INET, SOCK_STREAM, 0); + if (sock == -1) { + zlog_warn("%s: socket: %s", __func__, strerror(errno)); + return -1; + } + + socklen = sizeof(sin); + sin.sin_family = AF_INET; + sin.sin_port = htons(PIM_MSDP_TCP_PORT); +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sin.sin_len = socklen; +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + if (mp) + sin.sin_addr = mp->local; + + sockopt_reuseaddr(sock); + sockopt_reuseport(sock); + + /* Bind socket to VRF/address. */ + if (vrf && vrf->vrf_id != VRF_DEFAULT) { + ifp = if_lookup_by_name(vrf->name, vrf->vrf_id); + if (ifp == NULL) { + flog_err(EC_LIB_INTERFACE, + "%s: Unable to lookup vrf interface: %s", + __func__, vrf->name); + close(sock); + return -1; + } + + if (vrf_bind(vrf->vrf_id, sock, ifp->name) == -1) { + flog_err_sys(EC_LIB_SOCKET, + "%s: Unable to bind to socket: %s", + __func__, safe_strerror(errno)); + close(sock); + return -1; + } + } + + frr_with_privs (&pimd_privs) { + rv = bind(sock, (struct sockaddr *)&sin, socklen); + } + if (rv == -1) { + flog_err_sys(EC_LIB_SOCKET, + "pim_msdp_socket bind to port %d: %s", + ntohs(sin.sin_port), safe_strerror(errno)); + close(sock); + return -1; + } + + /* Set MD5 authentication. */ + if (mp && mp->auth_key) { + su_peer = mp->su_peer; + frr_with_privs (&pimd_privs) { + sockopt_tcp_signature(sock, &su_peer, mp->auth_key); + } + } + + + /* Start listening. */ + rv = listen(sock, SOMAXCONN); + if (rv == -1) { + flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s", + safe_strerror(errno)); + close(sock); + return -1; + } + + /* Set socket DSCP byte */ + if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) { + zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", + sock, safe_strerror(errno)); + } + + return sock; +} + +static void pim_msdp_sock_auth_accept(struct event *t) +{ + struct pim_msdp_peer *mp = EVENT_ARG(t); + int sock; + socklen_t sinlen; + struct sockaddr_in sin = {}; + + /* accept client connection. */ + sinlen = sizeof(sin); + sock = accept(mp->auth_listen_sock, (struct sockaddr *)&sin, &sinlen); + if (sock == -1) { + flog_err_sys(EC_LIB_SOCKET, "pim_msdp_sock_accept failed (%s)", + safe_strerror(errno)); + + /* Accept failed, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + /* + * Previous connection still going. + * + * We must wait for the user to close the previous connection in order + * to establish the new one. User can manually force that by calling + * `clear ip msdp peer A.B.C.D`. + */ + if (mp->fd != -1) { + ++mp->pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer connection refused from %pI4: old connection still running", + &sin.sin_addr); + } + close(sock); + + /* Unexpected connection, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + /* Unexpected client connected. */ + if (mp->peer.s_addr != sin.sin_addr.s_addr) { + ++mp->pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer connection refused from %pI4", + &sin.sin_addr); + } + close(sock); + + /* Unexpected peer, schedule listen again. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + return; + } + + if (PIM_DEBUG_MSDP_INTERNAL) + zlog_debug("MSDP peer %s accept success", mp->key_str); + + /* Configure socket. */ + mp->fd = sock; + set_nonblocking(mp->fd); + pim_msdp_update_sock_send_buffer_size(mp->fd); + pim_msdp_peer_established(mp); + + /* Stop listening. */ + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; +} + +int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp) +{ + /* Clear any listening connection if it exists. */ + event_cancel(&mp->auth_listen_ev); + if (mp->auth_listen_sock != -1) { + close(mp->auth_listen_sock); + mp->auth_listen_sock = -1; + } + + /* Start new listening socket. */ + mp->auth_listen_sock = _pim_msdp_sock_listen(mp->pim->vrf, mp); + if (mp->auth_listen_sock == -1) + return -1; + + /* Listen for connections and connected only with the expected end. */ + event_add_read(router->master, pim_msdp_sock_auth_accept, mp, + mp->auth_listen_sock, &mp->auth_listen_ev); + + return 0; +} + /* passive peer socket accept */ static void pim_msdp_sock_accept(struct event *thread) { @@ -91,6 +277,21 @@ static void pim_msdp_sock_accept(struct event *thread) return; } + /* + * If authentication is configured then we can not accept + * unauthenticated connections. + */ + if (mp->auth_type != MSDP_AUTH_NONE) { + ++pim->msdp.rejected_accepts; + if (PIM_DEBUG_MSDP_EVENTS) { + flog_err(EC_PIM_MSDP_PACKET, + "msdp peer unauthenticated connection refused from %pSU", + &su); + } + close(msdp_sock); + return; + } + if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP peer %s accept success%s", mp->key_str, mp->fd >= 0 ? "(dup)" : ""); @@ -116,9 +317,6 @@ static void pim_msdp_sock_accept(struct event *thread) int pim_msdp_sock_listen(struct pim_instance *pim) { int sock; - int socklen; - struct sockaddr_in sin; - int rc; struct pim_msdp_listener *listener = &pim->msdp.listener; if (pim->msdp.flags & PIM_MSDPF_LISTENER) { @@ -126,72 +324,20 @@ int pim_msdp_sock_listen(struct pim_instance *pim) return 0; } - sock = socket(AF_INET, SOCK_STREAM, 0); - if (sock < 0) { - flog_err_sys(EC_LIB_SOCKET, "socket: %s", safe_strerror(errno)); - return sock; - } + sock = _pim_msdp_sock_listen(pim->vrf, NULL); + if (sock == -1) + return -1; - memset(&sin, 0, sizeof(struct sockaddr_in)); - sin.sin_family = AF_INET; - sin.sin_port = htons(PIM_MSDP_TCP_PORT); - socklen = sizeof(struct sockaddr_in); + + memset(&listener->su.sin, 0, sizeof(listener->su.sin)); + listener->su.sin.sin_family = AF_INET; + listener->su.sin.sin_port = htons(PIM_MSDP_TCP_PORT); #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin.sin_len = socklen; + listener->su.sin.sin_len = sizeof(listener->su.sin); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sockopt_reuseaddr(sock); - sockopt_reuseport(sock); - - if (pim->vrf->vrf_id != VRF_DEFAULT) { - struct interface *ifp = - if_lookup_by_name(pim->vrf->name, pim->vrf->vrf_id); - if (!ifp) { - flog_err(EC_LIB_INTERFACE, - "%s: Unable to lookup vrf interface: %s", - __func__, pim->vrf->name); - close(sock); - return -1; - } - if (pim_socket_bind(sock, ifp)) { - flog_err_sys(EC_LIB_SOCKET, - "%s: Unable to bind to socket: %s", - __func__, safe_strerror(errno)); - close(sock); - return -1; - } - } - - frr_with_privs(&pimd_privs) { - /* bind to well known TCP port */ - rc = bind(sock, (struct sockaddr *)&sin, socklen); - } - - if (rc < 0) { - flog_err_sys(EC_LIB_SOCKET, - "pim_msdp_socket bind to port %d: %s", - ntohs(sin.sin_port), safe_strerror(errno)); - close(sock); - return rc; - } - - rc = listen(sock, 3 /* backlog */); - if (rc < 0) { - flog_err_sys(EC_LIB_SOCKET, "pim_msdp_socket listen: %s", - safe_strerror(errno)); - close(sock); - return rc; - } - - /* Set socket DSCP byte */ - if (setsockopt_ipv4_tos(sock, IPTOS_PREC_INTERNETCONTROL)) { - zlog_warn("can't set sockopt IP_TOS to MSDP socket %d: %s", - sock, safe_strerror(errno)); - } - /* add accept thread */ listener->fd = sock; - memcpy(&listener->su, &sin, socklen); event_add_read(pim->msdp.master, pim_msdp_sock_accept, pim, sock, &listener->thread); @@ -272,6 +418,14 @@ int pim_msdp_sock_connect(struct pim_msdp_peer *mp) mp->fd, safe_strerror(errno)); } + /* Set authentication (if configured). */ + if (mp->auth_key) { + frr_with_privs (&pimd_privs) { + sockopt_tcp_signature(mp->fd, &mp->su_peer, + mp->auth_key); + } + } + /* Connect to the remote mp. */ return (sockunion_connect(mp->fd, &mp->su_peer, htons(PIM_MSDP_TCP_PORT), 0)); diff --git a/pimd/pim_msdp_socket.h b/pimd/pim_msdp_socket.h index ae31664f9c..d2c601409a 100644 --- a/pimd/pim_msdp_socket.h +++ b/pimd/pim_msdp_socket.h @@ -6,6 +6,9 @@ #ifndef PIM_MSDP_SOCKET_H #define PIM_MSDP_SOCKET_H +struct pim_msdp_peer; + +int pim_msdp_sock_auth_listen(struct pim_msdp_peer *mp); int pim_msdp_sock_listen(struct pim_instance *pim); int pim_msdp_sock_connect(struct pim_msdp_peer *mp); #endif diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 339935f81a..72b5bdefc9 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -163,6 +163,33 @@ const struct frr_yang_module_info frr_pim_info = { .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, } }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in", + .cbs = { + .modify = pim_msdp_peer_sa_filter_in_modify, + .destroy = pim_msdp_peer_sa_filter_in_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out", + .cbs = { + .modify = pim_msdp_peer_sa_filter_out_modify, + .destroy = pim_msdp_peer_sa_filter_out_destroy, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type", + .cbs = { + .modify = pim_msdp_peer_authentication_type_modify, + } + }, + { + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key", + .cbs = { + .modify = pim_msdp_peer_authentication_key_modify, + .destroy = pim_msdp_peer_authentication_key_destroy, + } + }, { .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag", .cbs = { diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index 0321d076f0..3c7ab49ab3 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -65,6 +65,13 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify( struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args); +int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args); +int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_mlag_destroy( @@ -207,9 +214,6 @@ int routing_control_plane_protocols_name_validate( "./frr-pim:pim/address-family[address-family='%s']/" \ "mroute[source-addr='%s'][group-addr='%s']" #define FRR_PIM_STATIC_RP_XPATH \ - "/frr-routing:routing/control-plane-protocols/" \ - "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ - "frr-pim:pim/address-family[address-family='%s']/" \ "frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']" #define FRR_GMP_INTERFACE_XPATH \ "./frr-gmp:gmp/address-family[address-family='%s']" @@ -218,6 +222,5 @@ int routing_control_plane_protocols_name_validate( #define FRR_GMP_JOIN_XPATH \ "./frr-gmp:gmp/address-family[address-family='%s']/" \ "static-group[group-addr='%s'][source-addr='%s']" -#define FRR_PIM_MSDP_XPATH FRR_PIM_VRF_XPATH "/msdp" #endif /* _FRR_PIM_NB_H_ */ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index be0be8588b..bc7338ce18 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -9,12 +9,14 @@ #include "pimd.h" #include "pim_nb.h" #include "lib/northbound_cli.h" +#include "lib/sockopt.h" #include "pim_igmpv3.h" #include "pim_neighbor.h" #include "pim_nht.h" #include "pim_pim.h" #include "pim_mlag.h" #include "pim_bfd.h" +#include "pim_msdp_socket.h" #include "pim_static.h" #include "pim_ssm.h" #include "pim_ssmpingd.h" @@ -1053,6 +1055,9 @@ pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address nb_cb_destroy_args); pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_peer_authentication_type_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_peer_authentication_key_destroy, nb_cb_destroy_args); #if PIM_IPV != 6 /* @@ -1154,6 +1159,81 @@ int pim_msdp_mesh_group_source_destroy(struct nb_cb_destroy_args *args) return NB_OK; } +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-type + */ +int pim_msdp_peer_authentication_type_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + mp->auth_type = yang_dnode_get_enum(args->dnode, NULL); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/authentication-key + */ +int pim_msdp_peer_authentication_key_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + if (strlen(yang_dnode_get_string(args->dnode, NULL)) > + TCP_MD5SIG_MAXKEYLEN) { + snprintf(args->errmsg, args->errmsg_len, + "MD5 authentication key too long"); + return NB_ERR_VALIDATION; + } + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + mp->auth_key = XSTRDUP(MTYPE_PIM_MSDP_AUTH_KEY, + yang_dnode_get_string(args->dnode, NULL)); + + /* We must start listening the new authentication key now. */ + if (PIM_MSDP_PEER_IS_LISTENER(mp)) + pim_msdp_sock_auth_listen(mp); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_authentication_key_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_PIM_MSDP_AUTH_KEY, mp->auth_key); + break; + } + + return NB_OK; +} /* * XPath: @@ -1286,6 +1366,94 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms } #endif /* PIM_IPV != 6 */ +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-in + */ +int pim_msdp_peer_sa_filter_in_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + mp->acl_in = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_in_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_in); + break; + } + + return NB_OK; +} + +/* + * XPath: + * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-peer/sa-filter-out + */ +int pim_msdp_peer_sa_filter_out_modify(struct nb_cb_modify_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + mp->acl_out = XSTRDUP(MTYPE_TMP, + yang_dnode_get_string(args->dnode, NULL)); + break; + } + + return NB_OK; +} + +int pim_msdp_peer_sa_filter_out_destroy(struct nb_cb_destroy_args *args) +{ + struct pim_msdp_peer *mp; + + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + /* NOTHING */ + break; + case NB_EV_APPLY: + mp = nb_running_get_entry(args->dnode, NULL, true); + XFREE(MTYPE_TMP, mp->acl_out); + break; + } + + return NB_OK; +} + /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag */ diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 32cdf4bf82..57dcff3b47 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -161,18 +161,27 @@ void pim_nht_bsr_add(struct pim_instance *pim, pim_addr addr) pnc->bsr_count++; } +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc; + + pnc = pim_nht_get(pim, addr); + + pnc->candrp_count++; + return CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID); +} + static void pim_nht_drop_maybe(struct pim_instance *pim, struct pim_nexthop_cache *pnc) { if (PIM_DEBUG_PIM_NHT) - zlog_debug( - "%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u", - __func__, &pnc->rpf.rpf_addr, pim->vrf->name, - pnc->rp_list->count, pnc->upstream_hash->count, - pnc->bsr_count); + zlog_debug("%s: NHT %pPA(%s) rp_list count:%d upstream count:%ld BSR count:%u Cand-RP count:%u", + __func__, &pnc->rpf.rpf_addr, pim->vrf->name, + pnc->rp_list->count, pnc->upstream_hash->count, + pnc->bsr_count, pnc->candrp_count); - if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 - && pnc->bsr_count == 0) { + if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 && + pnc->bsr_count == 0 && pnc->candrp_count == 0) { struct zclient *zclient = pim_zebra_zclient_get(); pim_sendmsg_zebra_rnh(pim, zclient, pnc, @@ -258,6 +267,27 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr addr) pim_nht_drop_maybe(pim, pnc); } +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr) +{ + struct pim_nexthop_cache *pnc = NULL; + struct pim_nexthop_cache lookup; + + lookup.rpf.rpf_addr = addr; + + pnc = hash_lookup(pim->rpf_hash, &lookup); + + if (!pnc) { + zlog_warn("attempting to delete nonexistent NHT C-RP entry %pPA", + &addr); + return; + } + + assertf(pnc->candrp_count > 0, "addr=%pPA", &addr); + pnc->candrp_count--; + + pim_nht_drop_maybe(pim, pnc); +} + bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip) { @@ -900,6 +930,9 @@ void pim_nexthop_update(struct vrf *vrf, struct prefix *match, pim_update_rp_nh(pim, pnc); if (pnc->upstream_hash->count) pim_update_upstream_nh(pim, pnc); + + if (pnc->candrp_count) + pim_crp_nht_update(pim, pnc); } int pim_ecmp_nexthop_lookup(struct pim_instance *pim, diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index a1feb76e3b..e74b375dc6 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -38,6 +38,7 @@ struct pim_nexthop_cache { * same BSR */ uint32_t bsr_count; + uint32_t candrp_count; }; struct pnc_hash_walk_data { @@ -71,4 +72,10 @@ void pim_nht_bsr_del(struct pim_instance *pim, pim_addr bsr_addr); bool pim_nht_bsr_rpf_check(struct pim_instance *pim, pim_addr bsr_addr, struct interface *src_ifp, pim_addr src_ip); void pim_upstream_nh_if_update(struct pim_instance *pim, struct interface *ifp); + +/* wrappers for usage with Candidate RPs in BSMs */ +bool pim_nht_candrp_add(struct pim_instance *pim, pim_addr addr); +void pim_nht_candrp_del(struct pim_instance *pim, pim_addr addr); +void pim_crp_nht_update(struct pim_instance *pim, struct pim_nexthop_cache *pnc); + #endif diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 1bc265b138..6a7e8924f2 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -636,17 +636,15 @@ static int pim_msg_send_frame(pim_addr src, pim_addr dst, ifindex_t ifindex, int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, int pim_msg_size, struct interface *ifp) { - struct pim_interface *pim_ifp; - + if (ifp) { + struct pim_interface *pim_ifp = ifp->info; - pim_ifp = ifp->info; - - if (pim_ifp->pim_passive_enable) { - if (PIM_DEBUG_PIM_PACKETS) - zlog_debug( - "skip sending PIM message on passive interface %s", - ifp->name); - return 0; + if (pim_ifp->pim_passive_enable) { + if (PIM_DEBUG_PIM_PACKETS) + zlog_debug("skip sending PIM message on passive interface %s", + ifp->name); + return 0; + } } #if PIM_IPV == 4 @@ -710,7 +708,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, if (PIM_DEBUG_PIM_PACKETS) zlog_debug("%s: to %pPA on %s: msg_size=%d checksum=%x", - __func__, &dst, ifp->name, pim_msg_size, + __func__, &dst, ifp ? ifp->name : "*", pim_msg_size, header->checksum); if (PIM_DEBUG_PIM_PACKETDUMP_SEND) { @@ -718,7 +716,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, } pim_msg_send_frame(fd, (char *)buffer, sendlen, (struct sockaddr *)&to, - tolen, ifp->name); + tolen, ifp ? ifp->name : "*"); return 0; #else @@ -727,7 +725,7 @@ int pim_msg_send(int fd, pim_addr src, pim_addr dst, uint8_t *pim_msg, iovector[0].iov_base = pim_msg; iovector[0].iov_len = pim_msg_size; - pim_msg_send_frame(src, dst, ifp->ifindex, &iovector[0], fd); + pim_msg_send_frame(src, dst, ifp ? ifp->ifindex : 0, &iovector[0], fd); return 0; #endif diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index d8d25712a3..0f8940bb16 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -543,6 +543,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_all); + if (rp_all->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_all->rp.rpf_addr, &rp_all->group); pim_rp_refresh_group_to_rp_mapping(pim); pim_find_or_track_nexthop(pim, nht_p, NULL, rp_all, NULL); @@ -634,6 +637,9 @@ int pim_rp_new(struct pim_instance *pim, pim_addr rp_addr, struct prefix group, pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_info); + if (rp_info->i_am_rp && PIM_DEBUG_PIM_NHT_RP) + zlog_debug("new RP %pPA for %pFX is ourselves", + &rp_info->rp.rpf_addr, &rp_info->group); pim_rp_refresh_group_to_rp_mapping(pim); /* Register addr with Zebra NHT */ @@ -1101,16 +1107,17 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, pim_addr source, pim_addr group) { struct rp_info *rp_info; - struct prefix g; + struct prefix g = {}; - memset(&g, 0, sizeof(g)); + if (!pim_addr_is_any(source)) { + *up = source; + return 1; + } pim_addr_to_prefix(&g, group); - rp_info = pim_rp_find_match_group(pim, &g); - if (!rp_info || ((pim_rpf_addr_is_inaddr_any(&rp_info->rp)) && - (pim_addr_is_any(source)))) { + if (!rp_info || pim_rpf_addr_is_inaddr_any(&rp_info->rp)) { if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Received a (*,G) with no RP configured", __func__); @@ -1118,16 +1125,11 @@ int pim_rp_set_upstream_addr(struct pim_instance *pim, pim_addr *up, return 0; } - if (pim_addr_is_any(source)) - *up = rp_info->rp.rpf_addr; - else - *up = source; - + *up = rp_info->rp.rpf_addr; return 1; } -int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces) +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty) { struct listnode *node; struct rp_info *rp_info; @@ -1143,13 +1145,11 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, rp_addr = rp_info->rp.rpf_addr; if (rp_info->plist) - vty_out(vty, - "%s" PIM_AF_NAME - " pim rp %pPA prefix-list %s\n", - spaces, &rp_addr, rp_info->plist); + vty_out(vty, " rp %pPA prefix-list %s\n", &rp_addr, + rp_info->plist); else - vty_out(vty, "%s" PIM_AF_NAME " pim rp %pPA %pFX\n", - spaces, &rp_addr, &rp_info->group); + vty_out(vty, " rp %pPA %pFX\n", &rp_addr, + &rp_info->group); count++; } diff --git a/pimd/pim_rp.h b/pimd/pim_rp.h index 9416a9a8a8..32c6306740 100644 --- a/pimd/pim_rp.h +++ b/pimd/pim_rp.h @@ -46,8 +46,7 @@ int pim_rp_change(struct pim_instance *pim, pim_addr new_rp_addr, void pim_rp_prefix_list_update(struct pim_instance *pim, struct prefix_list *plist); -int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, - const char *spaces); +int pim_rp_config_write(struct pim_instance *pim, struct vty *vty); void pim_rp_setup(struct pim_instance *pim); diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index 0f6547ee2e..1910a68495 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -172,89 +172,66 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) { int writes = 0; struct pim_ssm *ssm = pim->ssm_info; - char spaces[10]; - if (pim->vrf->vrf_id == VRF_DEFAULT) - snprintf(spaces, sizeof(spaces), "%s", ""); - else - snprintf(spaces, sizeof(spaces), "%s", " "); - - writes += pim_msdp_peer_config_write(vty, pim, spaces); - writes += pim_msdp_config_write(pim, vty, spaces); + writes += pim_msdp_peer_config_write(vty, pim); + writes += pim_msdp_config_write(pim, vty); if (!pim->send_v6_secondary) { - vty_out(vty, "%sno ip pim send-v6-secondary\n", spaces); + vty_out(vty, " no send-v6-secondary\n"); ++writes; } - writes += pim_rp_config_write(pim, vty, spaces); + writes += pim_rp_config_write(pim, vty); if (pim->vrf->vrf_id == VRF_DEFAULT) { if (router->register_suppress_time != PIM_REGISTER_SUPPRESSION_TIME_DEFAULT) { - vty_out(vty, "%s" PIM_AF_NAME " pim register-suppress-time %d\n", - spaces, router->register_suppress_time); + vty_out(vty, " register-suppress-time %d\n", + router->register_suppress_time); ++writes; } if (router->t_periodic != PIM_DEFAULT_T_PERIODIC) { - vty_out(vty, "%s" PIM_AF_NAME " pim join-prune-interval %d\n", - spaces, router->t_periodic); + vty_out(vty, " join-prune-interval %d\n", + router->t_periodic); ++writes; } if (router->packet_process != PIM_DEFAULT_PACKET_PROCESS) { - vty_out(vty, "%s" PIM_AF_NAME " pim packets %d\n", spaces, - router->packet_process); + vty_out(vty, " packets %d\n", router->packet_process); ++writes; } } if (pim->keep_alive_time != PIM_KEEPALIVE_PERIOD) { - vty_out(vty, "%s" PIM_AF_NAME " pim keep-alive-timer %d\n", - spaces, pim->keep_alive_time); + vty_out(vty, " keep-alive-timer %d\n", pim->keep_alive_time); ++writes; } if (pim->rp_keep_alive_time != (unsigned int)PIM_RP_KEEPALIVE_PERIOD) { - vty_out(vty, "%s" PIM_AF_NAME " pim rp keep-alive-timer %d\n", - spaces, pim->rp_keep_alive_time); + vty_out(vty, " rp keep-alive-timer %d\n", + pim->rp_keep_alive_time); ++writes; } if (ssm->plist_name) { - vty_out(vty, "%sip pim ssm prefix-list %s\n", spaces, - ssm->plist_name); + vty_out(vty, " ssm prefix-list %s\n", ssm->plist_name); ++writes; } if (pim->register_plist) { - vty_out(vty, "%sip pim register-accept-list %s\n", spaces, - pim->register_plist); + vty_out(vty, " register-accept-list %s\n", pim->register_plist); ++writes; } if (pim->spt.switchover == PIM_SPT_INFINITY) { if (pim->spt.plist) vty_out(vty, - "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond prefix-list %s\n", - spaces, pim->spt.plist); + " spt-switchover infinity-and-beyond prefix-list %s\n", + pim->spt.plist); else - vty_out(vty, - "%s" PIM_AF_NAME " pim spt-switchover infinity-and-beyond\n", - spaces); + vty_out(vty, " spt-switchover infinity-and-beyond\n"); ++writes; } if (pim->ecmp_rebalance_enable) { - vty_out(vty, "%sip pim ecmp rebalance\n", spaces); + vty_out(vty, " ecmp rebalance\n"); ++writes; } else if (pim->ecmp_enable) { - vty_out(vty, "%sip pim ecmp\n", spaces); - ++writes; - } - - if (pim->gm_watermark_limit != 0) { -#if PIM_IPV == 4 - vty_out(vty, "%s" PIM_AF_NAME " igmp watermark-warn %u\n", - spaces, pim->gm_watermark_limit); -#else - vty_out(vty, "%s" PIM_AF_NAME " mld watermark-warn %u\n", - spaces, pim->gm_watermark_limit); -#endif + vty_out(vty, " ecmp\n"); ++writes; } @@ -263,8 +240,7 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) struct ssmpingd_sock *ss; ++writes; for (ALL_LIST_ELEMENTS_RO(pim->ssmpingd_list, node, ss)) { - vty_out(vty, "%s" PIM_AF_NAME " ssmpingd %pPA\n", - spaces, &ss->source_addr); + vty_out(vty, " ssmpingd %pPA\n", &ss->source_addr); ++writes; } } @@ -272,8 +248,8 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) if (pim->msdp.hold_time != PIM_MSDP_PEER_HOLD_TIME || pim->msdp.keep_alive != PIM_MSDP_PEER_KA_TIME || pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) { - vty_out(vty, "%sip msdp timers %u %u", spaces, - pim->msdp.hold_time, pim->msdp.keep_alive); + vty_out(vty, " msdp timers %u %u", pim->msdp.hold_time, + pim->msdp.keep_alive); if (pim->msdp.connection_retry != PIM_MSDP_PEER_CONNECT_RETRY_TIME) vty_out(vty, " %u", pim->msdp.connection_retry); diff --git a/python/firstheader.py b/python/firstheader.py index 06e2895845..1a3cadfd5e 100644 --- a/python/firstheader.py +++ b/python/firstheader.py @@ -15,7 +15,7 @@ argp.add_argument("--warn-empty", action="store_const", const=True) argp.add_argument("--pipe", action="store_const", const=True) -include_re = re.compile('^#\s*include\s+["<]([^ ">]+)[">]', re.M) +include_re = re.compile(r'^#\s*include\s+["<]([^ ">]+)[">]', re.M) ignore = [ lambda fn: fn.startswith("tools/"), diff --git a/python/makefile.py b/python/makefile.py index 573871fb68..45f032296f 100644 --- a/python/makefile.py +++ b/python/makefile.py @@ -91,7 +91,7 @@ autoderp = "#AUTODERP# " out_lines = [] bcdeps = [] -make_rule_re = re.compile("^([^:\s]+):\s*([^:\s]+)\s*($|\n)") +make_rule_re = re.compile(r"^([^:\s]+):\s*([^:\s]+)\s*($|\n)") while lines: line = lines.pop(0) diff --git a/python/xref2vtysh.py b/python/xref2vtysh.py index 75d9ccf367..0cfb11e721 100644 --- a/python/xref2vtysh.py +++ b/python/xref2vtysh.py @@ -26,6 +26,8 @@ except ImportError: pass +import _clippy + frr_top_src = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # vtysh needs to know which daemon(s) to send commands to. For lib/, this is @@ -58,6 +60,16 @@ #include "linklist.h" #include "vtysh/vtysh.h" + +#pragma GCC visibility push(internal) + +#define MAKE_VECTOR(name, len, ...) \\ + static void * name ## _vitems[] = { __VA_ARGS__ }; \\ + static struct _vector name = { \\ + .active = len, \\ + .count = len, \\ + .index = name ## _vitems, \\ + } """ if sys.stderr.isatty(): @@ -335,23 +347,159 @@ def output_defs(cls, ofd): ofd.write(entry.get_def()) @classmethod - def output_install(cls, ofd, nodes): - ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + def output_node_graph(cls, ofd, node, cmds, splitfile): + graph = _clippy.Graph(None) + + for _, cmd in sorted(cmds.items()): + cg = _clippy.Graph(cmd.cmd, cmd._spec["doc"], cmd.name) + graph.merge(cg) + + if len(graph) <= 2: + return [] + + ofd.write("\n") + ofd.write(f"static struct cmd_token ctkn_{node}[];\n") + ofd.write(f"static struct graph_node gn_{node}[];\n") + ofd.write("\n") + + vectors = [] + cmdels = set() + + ofd.write(f"static struct cmd_token ctkn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + vectors.append( + ( + list(i.idx for i in token.next()), + list(i.idx for i in token.prev()), + ) + ) - for name, items in sorted(nodes.items_named()): - for item in sorted(items.values(), key=lambda i: i.name): - ofd.write("\tinstall_element(%s, &%s_vtysh);\n" % (name, item.name)) + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t{'{'} /* [{i}] = {token.text} */ {'}'},\n") + cmdels.add(token.text) + continue + + ofd.write(f"\t{'{'} /* [{i}] */\n\t\t.type = {token.type},\n") + if token.attr: + ofd.write(f"\t\t.attr = {token.attr},\n") + if token.allowrepeat: + ofd.write(f"\t\t.allowrepeat = true,\n") + if token.varname_src: + ofd.write(f"\t\t.varname_src = {token.varname_src},\n") + if token.text: + ofd.write(f'\t\t.text = (char *)"{c_escape(token.text)}",\n') + if token.desc: + ofd.write(f'\t\t.desc = (char *)"{c_escape(token.desc)}",\n') + if token.min: + ofd.write(f"\t\t.min = {token.min},\n") + if token.max: + ofd.write(f"\t\t.max = {token.max},\n") + if token.varname: + ofd.write(f'\t\t.varname = (char *)"{c_escape(token.varname)}",\n') + + if token.type == "FORK_TKN": + fj = token.join() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + if token.type == "JOIN_TKN": + fj = token.fork() + ofd.write(f"\t\t.forkjoin = &gn_{node}[{fj.idx}],\n") + + ofd.write(f"\t{'}'},\n") + + ofd.write("};\n\n") + + if splitfile: + for cmdel in sorted(cmdels): + ofd.write(f"extern struct cmd_element {cmdel}_vtysh;\n") + ofd.write("\n") + + for i, next_prev in enumerate(vectors): + n, p = next_prev + items = ", ".join(f"&gn_{node}[{i}]" for i in n) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_next, {len(n)}, {items});\n") + items = ", ".join(f"&gn_{node}[{i}]" for i in p) + ofd.write(f"MAKE_VECTOR(gn_{node}_{i}_prev, {len(p)}, {items});\n") + + ofd.write(f"\nstatic struct graph_node gn_{node}[] = {'{'}\n") + for i, token in enumerate(graph): + ofd.write("\t{\n") + ofd.write(f"\t\t.from = &gn_{node}_{i}_prev,\n") + ofd.write(f"\t\t.to = &gn_{node}_{i}_next,\n") + if token.type == "CMD_ELEMENT_TKN": + ofd.write(f"\t\t.data = (void *)&{token.text}_vtysh,\n") + else: + ofd.write(f"\t\t.data = &ctkn_{node}[{i}],\n") + ofd.write("\t},\n") + ofd.write("};\n") + + items = ", ".join(f"&gn_{node}[{i}]" for i in range(0, len(graph))) + ofd.write(f"MAKE_VECTOR(gvec_{node}, {len(graph)}, {items});\n") + + ofd.write( + f""" +{"extern " if splitfile else "static "}void install_{node}(void);\n +{"" if splitfile else "static "}void install_{node}(void)\n +{'{'} + unsigned node_id = {node}; + struct cmd_node *node; + + assert(node_id < vector_active(cmdvec)); + node = vector_slot(cmdvec, node_id); + assert(node); + assert(vector_active(node->cmdgraph->nodes) == 1); + graph_delete_node(node->cmdgraph, vector_slot(node->cmdgraph->nodes, 0)); + vector_free(node->cmdgraph->nodes); + node->cmdgraph->nodes = &gvec_{node}; +{'}'} +""" + ) - ofd.write("}\n") + return [node] @classmethod - def run(cls, xref, ofd): - ofd.write(vtysh_cmd_head) + def run(cls, xref, ofds): + for ofd in ofds: + ofd.write(vtysh_cmd_head) + + ofd = ofds.pop(0) NodeDict.load_nodenames() nodes = cls.load(xref) cls.output_defs(ofd) - cls.output_install(ofd, nodes) + + out_nodes = [] + for nodeid, cmds in nodes.items(): + node = nodes.nodename(nodeid) + + if ofds: + gfd, splitfile = ofds[nodeid % len(ofds)], True + else: + gfd, splitfile = ofd, False + + # install_element(VIEW_NODE, x) implies install_element(ENABLE_NODE, x) + # this needs to be handled here. + if node == "ENABLE_NODE": + nodeid_view = list( + k for k, v in nodes.nodenames.items() if v == "VIEW_NODE" + ) + assert len(nodeid_view) == 1 + cmds.update(nodes[nodeid_view[0]]) + + out_nodes.extend(cls.output_node_graph(gfd, node, cmds, splitfile)) + + out_nodes.sort() + + if ofds: + ofd.write("\n") + for name in out_nodes: + ofd.write(f"extern void install_{name}(void);\n") + + ofd.write("\nvoid vtysh_init_cmd(void)\n{\n") + + for name in out_nodes: + ofd.write(f"\tinstall_{name}();\n") + + ofd.write("}\n") def main(): diff --git a/python/xrelfo.py b/python/xrelfo.py index 07cd74071f..5f7616f250 100644 --- a/python/xrelfo.py +++ b/python/xrelfo.py @@ -447,7 +447,9 @@ def main(): argp = argparse.ArgumentParser(description="FRR xref ELF extractor") argp.add_argument("-o", dest="output", type=str, help="write JSON output") argp.add_argument("--out-by-file", type=str, help="write by-file JSON output") - argp.add_argument("-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c") + argp.add_argument( + "-c", dest="vtysh_cmds", type=str, help="write vtysh_cmd.c", nargs="*" + ) argp.add_argument("-Wlog-format", action="store_const", const=True) argp.add_argument("-Wlog-args", action="store_const", const=True) argp.add_argument("-Werror", action="store_const", const=True) @@ -528,9 +530,17 @@ def _main(args): os.rename(args.out_by_file + ".tmp", args.out_by_file) if args.vtysh_cmds: - with open(args.vtysh_cmds + ".tmp", "w") as fd: - CommandEntry.run(out, fd) - os.rename(args.vtysh_cmds + ".tmp", args.vtysh_cmds) + fds = [] + for filename in args.vtysh_cmds: + fds.append(open(filename + ".tmp", "w")) + + CommandEntry.run(out, fds) + + while fds: + fds.pop(0).close() + for filename in args.vtysh_cmds: + os.rename(filename + ".tmp", filename) + if args.Werror and CommandEntry.warn_counter: sys.exit(1) diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 9f1588507f..955a73e307 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -30,6 +30,7 @@ %{!?with_rtadv: %global with_rtadv 1 } %{!?with_watchfrr: %global with_watchfrr 1 } %{!?with_pathd: %global with_pathd 1 } +%{!?with_grpc: %global with_grpc 0 } # user and group %{!?frr_user: %global frr_user frr } @@ -201,6 +202,12 @@ BuildRequires: python3-devel BuildRequires: python3-sphinx %endif %endif +%if %{with_grpc} +BuildRequires: grpc-devel >= 1.16.1 +BuildRequires: protobuf-devel >= 3.6.1 +BuildRequires: protobuf-compiler >= 3.6.1 +BuildRequires: protobuf-c-devel +%endif %if 0%{?rhel} > 7 #platform-python-devel is needed for /usr/bin/pathfix.py BuildRequires: platform-python-devel @@ -301,6 +308,17 @@ through the AgentX protocol. Provides read-only access to current routing state through standard SNMP MIBs. +%if %{with_grpc} +%package grpc +Summary: GRPC support for FRR daemons +Group: System Environment/Daemons +License: GPLv3+ +Requires: %{name} = %{version}-%{release} + +%description grpc +Adds GRPC support to the individual FRR daemons. +%endif + %prep %setup -q -n frr-%{frrversion} @@ -424,6 +442,11 @@ routing state through standard SNMP MIBs. --enable-pathd \ %else --disable-pathd \ +%endif +%if %{with_grpc} + --enable-grpc \ +%else + --disable-grpc \ %endif --enable-snmp # end @@ -783,6 +806,12 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %{_libdir}/frr/modules/*snmp.so +%if %{with_grpc} +%files grpc +%{_libdir}/libfrrgrpc_pb.* +%{_libdir}/frr/modules/grpc.so +%endif + %files devel %{_libdir}/lib*.so %dir %{_includedir}/%{name} diff --git a/ripd/ripd.c b/ripd/ripd.c index ab4ffe5a92..8768819fe2 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -3054,7 +3054,10 @@ DEFUN (show_ip_rip, } vty_out(vty, - "Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface\n\n" diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index f4dadf377d..0aa2a9e486 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -2070,7 +2070,10 @@ DEFUN (show_ipv6_ripng, /* Header of display. */ vty_out(vty, - "Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP\n" + "Codes: K - kernel route, C - connected, L - local, S - static,\n" + " R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP,\n" + " T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR,\n" + " f - OpenFabric, t - Table-Direct\n" "Sub-codes:\n" " (n) - normal, (s) - static, (d) - default, (r) - redistribute,\n" " (i) - interface, (a/S) - aggregated/Suppressed\n\n" diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index f4ce147978..2e72a4b990 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -65,9 +65,18 @@ static void sharp_global_init(void) sg.srv6_locators = list_new(); } +static void sharp_srv6_locators_list_delete(void *item) +{ + struct sharp_srv6_locator *loc = item; + + list_delete(&loc->chunks); +} + static void sharp_global_destroy(void) { list_delete(&sg.nhs); + + sg.srv6_locators->del = sharp_srv6_locators_list_delete; list_delete(&sg.srv6_locators); } diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 133da918fa..1048436b43 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -247,12 +247,12 @@ static bool route_add(const struct prefix *p, vrf_id_t vrf_id, uint8_t instance, memcpy(&api.prefix, p, sizeof(*p)); api.flags = flags; - SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); /* Only send via ID if nhgroup has been successfully installed */ if (nhgid && sharp_nhgroup_id_is_installed(nhgid)) { zapi_route_set_nhg_id(&api, &nhgid); } else { + SET_FLAG(api.message, ZAPI_MESSAGE_NEXTHOP); for (ALL_NEXTHOPS_PTR(nhg, nh)) { /* Check if we set a VNI label */ if (nh->nh_label && diff --git a/snapcraft/scripts/bfdd-service b/snapcraft/scripts/bfdd-service index f94a7abb4b..5e41d1ae6d 100644 --- a/snapcraft/scripts/bfdd-service +++ b/snapcraft/scripts/bfdd-service @@ -9,6 +9,5 @@ exec $SNAP/sbin/bfdd \ -f $SNAP_DATA/bfdd.conf \ --pid_file $SNAP_DATA/bfdd.pid \ --socket $SNAP_DATA/zsock \ - --vty_socket $SNAP_DATA \ - --bfdctl $SNAP_DATA/bfdd.sock + --vty_socket $SNAP_DATA diff --git a/snapcraft/snapcraft.yaml.in b/snapcraft/snapcraft.yaml.in index d90236f7a2..eea9bfc0ee 100644 --- a/snapcraft/snapcraft.yaml.in +++ b/snapcraft/snapcraft.yaml.in @@ -249,7 +249,7 @@ apps: - network-bind - network-control bfdd-debug: - command: sbin/bfdd -f $SNAP_DATA/bfdd.conf --pid_file $SNAP_DATA/bfdd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA --bfdctl $SNAP_DATA/bfdd.sock + command: sbin/bfdd -f $SNAP_DATA/bfdd.conf --pid_file $SNAP_DATA/bfdd.pid --socket $SNAP_DATA/zsock --vty_socket $SNAP_DATA plugs: - network - network-bind diff --git a/tests/isisd/test_isis_spf.c b/tests/isisd/test_isis_spf.c index 4ea28cda2f..93009a1b84 100644 --- a/tests/isisd/test_isis_spf.c +++ b/tests/isisd/test_isis_spf.c @@ -55,7 +55,7 @@ static void test_run_spf(struct vty *vty, const struct isis_topology *topology, isis_run_spf(spftree); /* Print the SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree); + isis_print_spftree(vty, spftree, NULL); isis_print_routes(vty, spftree, NULL, false, false); /* Cleanup SPF tree. */ @@ -85,7 +85,7 @@ static void test_run_lfa(struct vty *vty, const struct isis_topology *topology, isis_lfa_compute(area, NULL, spftree_self, protected_resource); /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -148,7 +148,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, vty_out(vty, "\n"); /* Print the post-convergence SPT. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); /* * Activate the computed RLFAs (if any) using artificial LDP labels for @@ -164,7 +164,7 @@ static void test_run_rlfa(struct vty *vty, const struct isis_topology *topology, } /* Print the SPT and the corresponding main/backup routing tables. */ - isis_print_spftree(vty, spftree_self); + isis_print_spftree(vty, spftree_self, NULL); vty_out(vty, "Main:\n"); isis_print_routes(vty, spftree_self, NULL, false, false); vty_out(vty, "Backup:\n"); @@ -228,7 +228,7 @@ static void test_run_ti_lfa(struct vty *vty, /* * Print the post-convergence SPT and the corresponding routing table. */ - isis_print_spftree(vty, spftree_pc); + isis_print_spftree(vty, spftree_pc, NULL); isis_print_routes(vty, spftree_self, NULL, false, true); /* Cleanup everything. */ @@ -245,12 +245,25 @@ static int test_run(struct vty *vty, const struct isis_topology *topology, struct isis_area *area; struct lfa_protected_resource protected_resource = {}; uint8_t fail_id[ISIS_SYS_ID_LEN] = {}; + static char sysidstr[ISO_SYSID_STRLEN]; + char net_title[255]; + uint8_t buff[255]; + struct iso_address *addr = NULL; /* Init topology. */ area = isis_area_create("1", NULL); memcpy(area->isis->sysid, root->sysid, sizeof(area->isis->sysid)); area->is_type = IS_LEVEL_1_AND_2; area->srdb.enabled = true; + area->area_addrs = list_new(); + area->area_addrs->del = isis_area_address_delete; + addr = XMALLOC(MTYPE_ISIS_AREA_ADDR, sizeof(struct iso_address)); + snprintfrr(sysidstr, sizeof(sysidstr), "%pSY", area->isis->sysid); + snprintf(net_title, sizeof(net_title), "49.%s.00", sysidstr); + addr->addr_len = dotformat2buff(buff, net_title); + memcpy(addr->area_addr, buff, addr->addr_len); + addr->addr_len -= (ISIS_SYS_ID_LEN + ISIS_NSEL_LEN); + listnode_add(area->area_addrs, addr); if (test_topology_load(topology, area, area->lspdb) != 0) { vty_out(vty, "%% Failed to load topology\n"); return CMD_WARNING; diff --git a/tests/isisd/test_isis_spf.refout b/tests/isisd/test_isis_spf.refout index 23d41b9e5d..255d920c10 100644 --- a/tests/isisd/test_isis_spf.refout +++ b/tests/isisd/test_isis_spf.refout @@ -1,20 +1,22 @@ test# test isis topology 1 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -29,21 +31,23 @@ IS-IS L1 IPv4 routing table: - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -59,22 +63,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) - rt5 - -10.0.255.3/32 IP TE 40 rt3 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt5 - rt6(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -89,22 +95,24 @@ IS-IS L1 IPv4 routing table: - rt5 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) - rt5 - -2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt5 - rt6(4) + 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -120,19 +128,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -147,23 +157,25 @@ IS-IS L1 IPv4 routing table: test# test isis topology 4 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -180,25 +192,27 @@ IS-IS L1 IPv4 routing table: test# test isis topology 5 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -216,33 +230,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 6 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -rt5 TE-IS 40 rt2 - rt6(4) - rt3 - -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - -rt7 TE-IS 50 rt2 - rt5(4) - rt3 - rt8(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) - rt3 - -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - -10.0.255.7/32 IP TE 60 rt2 - rt7(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + rt5 TE-IS 40 rt2 - rt6(4) + rt3 - rt6(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt3 - rt8(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + rt3 - rt5(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + rt3 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -264,34 +280,36 @@ IS-IS L1 IPv4 routing table: test# test isis topology 7 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt5(4) -rt6 TE-IS 30 rt4 - rt5(4) -rt8 TE-IS 30 rt4 - rt5(4) - rt7(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt10 TE-IS 40 rt4 - rt7(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt6(4) -rt9 TE-IS 40 rt4 - rt8(4) -rt11 TE-IS 40 rt4 - rt8(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) -10.0.255.6/32 IP TE 40 rt4 - rt6(4) -10.0.255.8/32 IP TE 40 rt4 - rt8(4) -rt12 TE-IS 50 rt4 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 50 rt4 - rt10(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) -10.0.255.9/32 IP TE 50 rt4 - rt9(4) -10.0.255.11/32 IP TE 50 rt4 - rt11(4) -10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 TE-IS 30 rt4 - rt5(4) + rt7(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt10 TE-IS 40 rt4 - rt7(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt6(4) + rt9 TE-IS 40 rt4 - rt8(4) + rt11 TE-IS 40 rt4 - rt8(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + 10.0.255.8/32 IP TE 40 rt4 - rt8(4) + rt12 TE-IS 50 rt4 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 50 rt4 - rt10(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + 10.0.255.9/32 IP TE 50 rt4 - rt9(4) + 10.0.255.11/32 IP TE 50 rt4 - rt11(4) + 10.0.255.12/32 IP TE 60 rt4 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -312,33 +330,35 @@ IS-IS L1 IPv4 routing table: test# test isis topology 8 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt3 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt2 - rt2(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt6 TE-IS 30 rt2 - rt3(4) - rt5(4) -rt8 TE-IS 30 rt2 - rt5(4) -rt10 TE-IS 30 rt4 - rt7(4) -10.0.255.3/32 IP TE 30 rt2 - rt3(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt9 TE-IS 40 rt2 - rt8(4) -rt11 TE-IS 40 rt2 - rt8(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) -10.0.255.10/32 IP TE 40 rt4 - rt10(4) -rt12 TE-IS 50 rt2 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.11/32 IP TE 50 rt2 - rt11(4) -10.0.255.12/32 IP TE 60 rt2 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt3 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt2 - rt2(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt6 TE-IS 30 rt2 - rt3(4) + rt5(4) + rt8 TE-IS 30 rt2 - rt5(4) + rt10 TE-IS 30 rt4 - rt7(4) + 10.0.255.3/32 IP TE 30 rt2 - rt3(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt9 TE-IS 40 rt2 - rt8(4) + rt11 TE-IS 40 rt2 - rt8(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + 10.0.255.10/32 IP TE 40 rt4 - rt10(4) + rt12 TE-IS 50 rt2 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.11/32 IP TE 50 rt2 - rt11(4) + 10.0.255.12/32 IP TE 60 rt2 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -359,28 +379,30 @@ IS-IS L1 IPv4 routing table: test# test isis topology 9 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.6/32 IP TE 60 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -10.0.255.8/32 IP TE 60 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.6/32 IP TE 60 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + 10.0.255.8/32 IP TE 60 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -397,28 +419,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 50 - rt2 16090 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) -2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) -2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) + 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) + 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -436,23 +460,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -rt8 TE-IS 30 rt2 - rt5(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.4/32 IP TE 30 rt4 - rt4(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt4 - rt7(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + rt8 TE-IS 30 rt2 - rt5(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.4/32 IP TE 30 rt4 - rt4(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt4 - rt7(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -468,23 +494,25 @@ IS-IS L1 IPv4 routing table: 10.0.255.8/32 40 - rt2 16080 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -rt8 TE-IS 30 rt2 - rt5(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) -2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + rt8 TE-IS 30 rt2 - rt5(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) + 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -501,22 +529,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt1 spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -531,22 +561,24 @@ IS-IS L1 IPv4 routing table: - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -562,27 +594,29 @@ IS-IS L1 IPv6 routing table: test# test isis topology 12 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -rt9 TE-IS 40 rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt10 TE-IS 50 rt2 - rt8(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) -10.0.255.9/32 IP TE 50 rt3 - rt9(4) -10.0.255.10/32 IP TE 60 rt2 - rt10(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt9 TE-IS 40 rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt10 TE-IS 50 rt2 - rt8(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + 10.0.255.9/32 IP TE 50 rt3 - rt9(4) + 10.0.255.10/32 IP TE 60 rt2 - rt10(4) + IS-IS L1 IPv4 routing table: @@ -601,24 +635,26 @@ IS-IS L1 IPv4 routing table: test# test isis topology 13 root rt1 spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -636,23 +672,25 @@ IS-IS L1 IPv4 routing table: test# test# test isis topology 4 root rt1 reverse-spf ipv4-only IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -669,21 +707,23 @@ IS-IS L1 IPv4 routing table: test# test isis topology 11 root rt1 reverse-spf IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt4(4) - rt5(4) -10.0.255.4/32 IP TE 30 rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt4(4) + rt5(4) + 10.0.255.4/32 IP TE 30 rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -695,21 +735,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt2 pseudo_TE-IS 20 rt3 - rt3(4) -rt4 TE-IS 20 rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt4(4) - rt5(4) -2001:db8::4/128 IP6 internal 30 rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt2 pseudo_TE-IS 20 rt3 - rt3(4) + rt4 TE-IS 20 rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt4(4) + rt5(4) + 2001:db8::4/128 IP6 internal 30 rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -723,21 +765,23 @@ IS-IS L1 IPv6 routing table: test# test# test isis topology 1 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -756,21 +800,23 @@ Backup: IS-IS L1 IPv4 routing table: IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -790,21 +836,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt1 pseudonode-id 1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -826,21 +874,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 50 - rt2 implicit-null IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -2001:db8::4/128 IP6 internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt4 + 2001:db8::4/128 IP6 internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -863,21 +913,23 @@ IS-IS L1 IPv6 routing table: test# test isis topology 2 root rt4 lfa system-id rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -899,21 +951,23 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 30 - rt5 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -2001:db8::4/128 IP6 internal 0 rt4(4) -rt1 TE-IS 10 rt1 - rt4(4) -rt5 TE-IS 10 rt5 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt4 + 2001:db8::4/128 IP6 internal 0 rt4(4) + rt1 TE-IS 10 rt1 - rt4(4) + rt5 TE-IS 10 rt5 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -936,19 +990,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -973,10 +1029,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt3 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -986,19 +1044,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 3 root rt1 lfa system-id rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt5 TE-IS 30 rt2 - rt4(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt5 TE-IS 30 rt2 - rt4(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1020,10 +1080,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.3/32 30 - rt2 16030 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -1033,34 +1095,36 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt1 lfa system-id rt4 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt7 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt5(4) -rt6 TE-IS 30 rt4 - rt5(4) -rt8 TE-IS 30 rt4 - rt5(4) - rt7(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.7/32 IP TE 30 rt4 - rt7(4) -rt10 TE-IS 40 rt4 - rt7(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt6(4) -rt9 TE-IS 40 rt4 - rt8(4) -rt11 TE-IS 40 rt4 - rt8(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) -10.0.255.6/32 IP TE 40 rt4 - rt6(4) -10.0.255.8/32 IP TE 40 rt4 - rt8(4) -rt12 TE-IS 50 rt4 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 50 rt4 - rt10(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) -10.0.255.9/32 IP TE 50 rt4 - rt9(4) -10.0.255.11/32 IP TE 50 rt4 - rt11(4) -10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt7 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 TE-IS 30 rt4 - rt5(4) + rt7(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.7/32 IP TE 30 rt4 - rt7(4) + rt10 TE-IS 40 rt4 - rt7(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt6(4) + rt9 TE-IS 40 rt4 - rt8(4) + rt11 TE-IS 40 rt4 - rt8(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + 10.0.255.8/32 IP TE 40 rt4 - rt8(4) + rt12 TE-IS 50 rt4 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 50 rt4 - rt10(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + 10.0.255.9/32 IP TE 50 rt4 - rt9(4) + 10.0.255.11/32 IP TE 50 rt4 - rt11(4) + 10.0.255.12/32 IP TE 60 rt4 - rt12(4) + Main: IS-IS L1 IPv4 routing table: @@ -1098,10 +1162,12 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 90 - rt2 16120 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 40 rt2 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt1 + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 40 rt2 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -1111,40 +1177,42 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt7 lfa system-id rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt7 -10.0.255.7/32 IP internal 0 rt7(4) -rt4 TE-IS 10 rt4 - rt7(4) -rt8 TE-IS 10 rt8 - rt7(4) -rt10 TE-IS 20 rt10 - rt7(4) -rt1 TE-IS 20 rt4 - rt4(4) -rt5 TE-IS 20 rt4 - rt4(4) - rt8 - rt8(4) -rt9 TE-IS 20 rt8 - rt8(4) -rt11 TE-IS 20 rt8 - rt8(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -rt2 TE-IS 30 rt4 - rt5(4) - rt8 - -rt6 TE-IS 30 rt4 - rt5(4) - rt8 - -rt12 TE-IS 30 rt8 - rt9(4) - rt11(4) -10.0.255.10/32 IP TE 30 rt10 - rt10(4) -10.0.255.1/32 IP TE 30 rt4 - rt1(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) - rt8 - -10.0.255.9/32 IP TE 30 rt8 - rt9(4) -10.0.255.11/32 IP TE 30 rt8 - rt11(4) -rt3 TE-IS 40 rt4 - rt2(4) - rt8 - rt6(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) - rt8 - -10.0.255.6/32 IP TE 40 rt4 - rt6(4) - rt8 - -10.0.255.12/32 IP TE 40 rt8 - rt12(4) -10.0.255.3/32 IP TE 50 rt4 - rt3(4) - rt8 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt7 + 10.0.255.7/32 IP internal 0 rt7(4) + rt4 TE-IS 10 rt4 - rt7(4) + rt8 TE-IS 10 rt8 - rt7(4) + rt10 TE-IS 20 rt10 - rt7(4) + rt1 TE-IS 20 rt4 - rt4(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt8 - rt8(4) + rt9 TE-IS 20 rt8 - rt8(4) + rt11 TE-IS 20 rt8 - rt8(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + rt2 TE-IS 30 rt4 - rt5(4) + rt8 - rt5(4) + rt6 TE-IS 30 rt4 - rt5(4) + rt8 - rt5(4) + rt12 TE-IS 30 rt8 - rt9(4) + rt11(4) + 10.0.255.10/32 IP TE 30 rt10 - rt10(4) + 10.0.255.1/32 IP TE 30 rt4 - rt1(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + rt8 - rt5(4) + 10.0.255.9/32 IP TE 30 rt8 - rt9(4) + 10.0.255.11/32 IP TE 30 rt8 - rt11(4) + rt3 TE-IS 40 rt4 - rt2(4) + rt8 - rt6(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + rt8 - rt2(4) + 10.0.255.6/32 IP TE 40 rt4 - rt6(4) + rt8 - rt6(4) + 10.0.255.12/32 IP TE 40 rt8 - rt12(4) + 10.0.255.3/32 IP TE 50 rt4 - rt3(4) + rt8 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -1179,11 +1247,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.12/32 50 - rt10 16120 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt7 -rt4 TE-IS 10 rt4 - rt7(4) -rt8 TE-IS 10 rt8 - rt7(4) -rt10 TE-IS 20 rt10 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt7 + rt4 TE-IS 10 rt4 - rt7(4) + rt8 TE-IS 10 rt8 - rt7(4) + rt10 TE-IS 20 rt10 - rt7(4) + Main: IS-IS L1 IPv6 routing table: @@ -1193,38 +1263,40 @@ IS-IS L1 IPv6 routing table: test# test isis topology 7 root rt8 lfa system-id rt11 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt8 -10.0.255.8/32 IP internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt7 TE-IS 10 rt7 - rt8(4) -rt9 TE-IS 10 rt9 - rt8(4) -rt11 TE-IS 10 rt11 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -rt4 TE-IS 20 rt5 - rt5(4) - rt7 - rt7(4) -rt6 TE-IS 20 rt5 - rt5(4) -rt12 TE-IS 20 rt9 - rt9(4) - rt11 - rt11(4) -rt10 TE-IS 20 rt11 - rt11(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -10.0.255.9/32 IP TE 20 rt9 - rt9(4) -10.0.255.11/32 IP TE 20 rt11 - rt11(4) -rt3 TE-IS 30 rt5 - rt2(4) - rt6(4) -rt1 TE-IS 30 rt5 - rt4(4) - rt7 - -10.0.255.2/32 IP TE 30 rt5 - rt2(4) -10.0.255.4/32 IP TE 30 rt5 - rt4(4) - rt7 - -10.0.255.6/32 IP TE 30 rt5 - rt6(4) -10.0.255.12/32 IP TE 30 rt9 - rt12(4) - rt11 - -10.0.255.10/32 IP TE 30 rt11 - rt10(4) -10.0.255.3/32 IP TE 40 rt5 - rt3(4) -10.0.255.1/32 IP TE 40 rt5 - rt1(4) - rt7 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt8 + 10.0.255.8/32 IP internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt7 TE-IS 10 rt7 - rt8(4) + rt9 TE-IS 10 rt9 - rt8(4) + rt11 TE-IS 10 rt11 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + rt4 TE-IS 20 rt5 - rt5(4) + rt7 - rt7(4) + rt6 TE-IS 20 rt5 - rt5(4) + rt12 TE-IS 20 rt9 - rt9(4) + rt11 - rt11(4) + rt10 TE-IS 20 rt11 - rt11(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + 10.0.255.9/32 IP TE 20 rt9 - rt9(4) + 10.0.255.11/32 IP TE 20 rt11 - rt11(4) + rt3 TE-IS 30 rt5 - rt2(4) + rt6(4) + rt1 TE-IS 30 rt5 - rt4(4) + rt7 - rt4(4) + 10.0.255.2/32 IP TE 30 rt5 - rt2(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + rt7 - rt4(4) + 10.0.255.6/32 IP TE 30 rt5 - rt6(4) + 10.0.255.12/32 IP TE 30 rt9 - rt12(4) + rt11 - rt12(4) + 10.0.255.10/32 IP TE 30 rt11 - rt10(4) + 10.0.255.3/32 IP TE 40 rt5 - rt3(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + rt7 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -1255,12 +1327,14 @@ IS-IS L1 IPv4 routing table: 10.0.255.10/32 40 - rt7 16100 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt8 -rt5 TE-IS 10 rt5 - rt8(4) -rt7 TE-IS 10 rt7 - rt8(4) -rt9 TE-IS 10 rt9 - rt8(4) -rt11 TE-IS 10 rt11 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt8 + rt5 TE-IS 10 rt5 - rt8(4) + rt7 TE-IS 10 rt7 - rt8(4) + rt9 TE-IS 10 rt9 - rt8(4) + rt11 TE-IS 10 rt11 - rt8(4) + Main: IS-IS L1 IPv6 routing table: @@ -1270,28 +1344,30 @@ IS-IS L1 IPv6 routing table: test# test isis topology 9 root rt3 lfa system-id rt1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt3 -10.0.255.3/32 IP internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 20 rt1 - rt1(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -rt4 TE-IS 30 rt1 - rt2(4) -10.0.255.2/32 IP TE 30 rt1 - rt2(4) -rt5 TE-IS 40 rt1 - rt4(4) -10.0.255.4/32 IP TE 40 rt1 - rt4(4) -rt9 TE-IS 50 rt1 - rt5(4) -10.0.255.5/32 IP TE 50 rt1 - rt5(4) -rt6 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt7 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt8 TE-IS 60 rt1 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 60 rt1 - rt9(4) -10.0.255.6/32 IP TE 70 rt1 - rt6(4) -10.0.255.7/32 IP TE 70 rt1 - rt7(4) -10.0.255.8/32 IP TE 70 rt1 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt3 + 10.0.255.3/32 IP internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 20 rt1 - rt1(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + rt4 TE-IS 30 rt1 - rt2(4) + 10.0.255.2/32 IP TE 30 rt1 - rt2(4) + rt5 TE-IS 40 rt1 - rt4(4) + 10.0.255.4/32 IP TE 40 rt1 - rt4(4) + rt9 TE-IS 50 rt1 - rt5(4) + 10.0.255.5/32 IP TE 50 rt1 - rt5(4) + rt6 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt7 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt8 TE-IS 60 rt1 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 60 rt1 - rt9(4) + 10.0.255.6/32 IP TE 70 rt1 - rt6(4) + 10.0.255.7/32 IP TE 70 rt1 - rt7(4) + 10.0.255.8/32 IP TE 70 rt1 - rt8(4) + Main: IS-IS L1 IPv4 routing table: @@ -1323,28 +1399,30 @@ IS-IS L1 IPv4 routing table: 10.0.255.9/32 130 - rt4 16090 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt3 -2001:db8::3/128 IP6 internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 20 rt1 - rt1(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -rt4 TE-IS 30 rt1 - rt2(4) -2001:db8::2/128 IP6 internal 30 rt1 - rt2(4) -rt5 TE-IS 40 rt1 - rt4(4) -2001:db8::4/128 IP6 internal 40 rt1 - rt4(4) -rt9 TE-IS 50 rt1 - rt5(4) -2001:db8::5/128 IP6 internal 50 rt1 - rt5(4) -rt6 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt7 TE-IS 60 rt1 - rt4(4) - rt9(4) -rt8 TE-IS 60 rt1 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 60 rt1 - rt9(4) -2001:db8::6/128 IP6 internal 70 rt1 - rt6(4) -2001:db8::7/128 IP6 internal 70 rt1 - rt7(4) -2001:db8::8/128 IP6 internal 70 rt1 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt3 + 2001:db8::3/128 IP6 internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 20 rt1 - rt1(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + rt4 TE-IS 30 rt1 - rt2(4) + 2001:db8::2/128 IP6 internal 30 rt1 - rt2(4) + rt5 TE-IS 40 rt1 - rt4(4) + 2001:db8::4/128 IP6 internal 40 rt1 - rt4(4) + rt9 TE-IS 50 rt1 - rt5(4) + 2001:db8::5/128 IP6 internal 50 rt1 - rt5(4) + rt6 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt7 TE-IS 60 rt1 - rt4(4) + rt9(4) + rt8 TE-IS 60 rt1 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 60 rt1 - rt9(4) + 2001:db8::6/128 IP6 internal 70 rt1 - rt6(4) + 2001:db8::7/128 IP6 internal 70 rt1 - rt7(4) + 2001:db8::8/128 IP6 internal 70 rt1 - rt8(4) + Main: IS-IS L1 IPv6 routing table: @@ -1377,23 +1455,25 @@ IS-IS L1 IPv6 routing table: test# test isis topology 10 root rt8 lfa system-id rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt8 -10.0.255.8/32 IP internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt1 TE-IS 30 rt5 - rt2(4) -10.0.255.2/32 IP TE 30 rt5 - rt2(4) -10.0.255.1/32 IP TE 40 rt5 - rt1(4) -rt6 TE-IS 50 rt6 - rt8(4) -rt7 TE-IS 50 rt7 - rt8(4) -rt3 TE-IS 50 rt5 - rt1(4) -rt4 TE-IS 50 rt5 - rt1(4) -10.0.255.6/32 IP TE 60 rt6 - rt6(4) -10.0.255.7/32 IP TE 60 rt7 - rt7(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) -10.0.255.4/32 IP TE 60 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt8 + 10.0.255.8/32 IP internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt1 TE-IS 30 rt5 - rt2(4) + 10.0.255.2/32 IP TE 30 rt5 - rt2(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + rt6 TE-IS 50 rt6 - rt8(4) + rt7 TE-IS 50 rt7 - rt8(4) + rt3 TE-IS 50 rt5 - rt1(4) + rt4 TE-IS 50 rt5 - rt1(4) + 10.0.255.6/32 IP TE 60 rt6 - rt6(4) + 10.0.255.7/32 IP TE 60 rt7 - rt7(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + 10.0.255.4/32 IP TE 60 rt5 - rt4(4) + Main: IS-IS L1 IPv4 routing table: @@ -1426,23 +1506,25 @@ IS-IS L1 IPv4 routing table: - rt7 16050 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt8 -2001:db8::8/128 IP6 internal 0 rt8(4) -rt5 TE-IS 10 rt5 - rt8(4) -rt2 TE-IS 20 rt5 - rt5(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -rt1 TE-IS 30 rt5 - rt2(4) -2001:db8::2/128 IP6 internal 30 rt5 - rt2(4) -2001:db8::1/128 IP6 internal 40 rt5 - rt1(4) -rt6 TE-IS 50 rt6 - rt8(4) -rt7 TE-IS 50 rt7 - rt8(4) -rt3 TE-IS 50 rt5 - rt1(4) -rt4 TE-IS 50 rt5 - rt1(4) -2001:db8::6/128 IP6 internal 60 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt7 - rt7(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) -2001:db8::4/128 IP6 internal 60 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt8 + 2001:db8::8/128 IP6 internal 0 rt8(4) + rt5 TE-IS 10 rt5 - rt8(4) + rt2 TE-IS 20 rt5 - rt5(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + rt1 TE-IS 30 rt5 - rt2(4) + 2001:db8::2/128 IP6 internal 30 rt5 - rt2(4) + 2001:db8::1/128 IP6 internal 40 rt5 - rt1(4) + rt6 TE-IS 50 rt6 - rt8(4) + rt7 TE-IS 50 rt7 - rt8(4) + rt3 TE-IS 50 rt5 - rt1(4) + rt4 TE-IS 50 rt5 - rt1(4) + 2001:db8::6/128 IP6 internal 60 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt7 - rt7(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + 2001:db8::4/128 IP6 internal 60 rt5 - rt4(4) + Main: IS-IS L1 IPv6 routing table: @@ -1476,22 +1558,24 @@ IS-IS L1 IPv6 routing table: test# test isis topology 11 root rt3 lfa system-id rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt3 -10.0.255.3/32 IP internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 10 rt2 - rt3(4) -rt5 TE-IS 10 rt5 - rt3(4) -rt2 pseudo_TE-IS 20 rt1 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt5 - rt5(4) -rt6 TE-IS 20 rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt5 - -10.0.255.6/32 IP TE 30 rt5 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt3 + 10.0.255.3/32 IP internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 10 rt2 - rt3(4) + rt5 TE-IS 10 rt5 - rt3(4) + rt2 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 - rt5(4) + rt6 TE-IS 20 rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 - rt4(4) + 10.0.255.6/32 IP TE 30 rt5 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1515,22 +1599,24 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 40 - rt2 16060 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt3 -2001:db8::3/128 IP6 internal 0 rt3(4) -rt1 TE-IS 10 rt1 - rt3(4) -rt2 TE-IS 10 rt2 - rt3(4) -rt5 TE-IS 10 rt5 - rt3(4) -rt2 pseudo_TE-IS 20 rt1 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt5 - rt5(4) -rt6 TE-IS 20 rt5 - rt5(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) - rt5 - -2001:db8::6/128 IP6 internal 30 rt5 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt3 + 2001:db8::3/128 IP6 internal 0 rt3(4) + rt1 TE-IS 10 rt1 - rt3(4) + rt2 TE-IS 10 rt2 - rt3(4) + rt5 TE-IS 10 rt5 - rt3(4) + rt2 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 - rt5(4) + rt6 TE-IS 20 rt5 - rt5(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt5 - rt4(4) + 2001:db8::6/128 IP6 internal 30 rt5 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -1555,24 +1641,26 @@ IS-IS L1 IPv6 routing table: test# test isis topology 13 root rt4 lfa system-id rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt3 - rt1(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -1599,11 +1687,13 @@ IS-IS L1 IPv4 routing table: 10.0.255.7/32 120 - rt5 16070 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt4 -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt5 TE-IS 100 rt5 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ---------------------------------------------------- + rt4 + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt5 TE-IS 100 rt5 - rt4(4) + Main: IS-IS L1 IPv6 routing table: @@ -1613,18 +1703,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt1 pseudonode-id 1 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Main: IS-IS L1 IPv4 routing table: @@ -1641,18 +1733,20 @@ Backup: IS-IS L1 IPv4 routing table: IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Main: IS-IS L1 IPv6 routing table: @@ -1670,18 +1764,20 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt1 lfa system-id rt2 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + Main: IS-IS L1 IPv4 routing table: @@ -1702,18 +1798,20 @@ IS-IS L1 IPv4 routing table: 10.0.255.2/32 30 - rt3 - IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt1 -rt5 TE-IS 20 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt1 + rt5 TE-IS 20 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + Main: IS-IS L1 IPv6 routing table: @@ -1735,19 +1833,21 @@ IS-IS L1 IPv6 routing table: test# test isis topology 14 root rt5 lfa system-id rt4 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt1 pseudo_TE-IS 20 rt4 - rt4(4) -rt1 TE-IS 20 rt4 - rt1(2) -rt3 TE-IS 20 rt4 - rt1(2) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt1(4) - rt3(4) -10.0.255.1/32 IP TE 30 rt4 - rt1(4) -10.0.255.3/32 IP TE 30 rt4 - rt3(4) -10.0.255.2/32 IP TE 40 rt4 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt1 pseudo_TE-IS 20 rt4 - rt4(4) + rt1 TE-IS 20 rt4 - rt1(2) + rt3 TE-IS 20 rt4 - rt1(2) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt1(4) + rt3(4) + 10.0.255.1/32 IP TE 30 rt4 - rt1(4) + 10.0.255.3/32 IP TE 30 rt4 - rt3(4) + 10.0.255.2/32 IP TE 40 rt4 - rt2(4) + Main: IS-IS L1 IPv4 routing table: @@ -1771,19 +1871,21 @@ IS-IS L1 IPv4 routing table: 10.0.255.4/32 70 - rt3 - IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt1 pseudo_TE-IS 20 rt4 - rt4(4) -rt1 TE-IS 20 rt4 - rt1(2) -rt3 TE-IS 20 rt4 - rt1(2) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -rt2 TE-IS 30 rt4 - rt1(4) - rt3(4) -2001:db8::1/128 IP6 internal 30 rt4 - rt1(4) -2001:db8::3/128 IP6 internal 30 rt4 - rt3(4) -2001:db8::2/128 IP6 internal 40 rt4 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt1 pseudo_TE-IS 20 rt4 - rt4(4) + rt1 TE-IS 20 rt4 - rt1(2) + rt3 TE-IS 20 rt4 - rt1(2) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + rt2 TE-IS 30 rt4 - rt1(4) + rt3(4) + 2001:db8::1/128 IP6 internal 30 rt4 - rt1(4) + 2001:db8::3/128 IP6 internal 30 rt4 - rt3(4) + 2001:db8::2/128 IP6 internal 40 rt4 - rt2(4) + Main: IS-IS L1 IPv6 routing table: @@ -1823,36 +1925,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -10.0.255.2/32 IP TE 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + 10.0.255.2/32 IP TE 60 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv4 routing table: @@ -1890,36 +1996,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) -2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) + 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) - rt3 - rt5(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt2 - rt6(4) + rt3 - rt6(4) + Main: IS-IS L1 IPv6 routing table: @@ -1964,39 +2074,43 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -10.0.255.1/32 IP TE 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) -10.0.255.2/32 IP TE 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 10.0.255.1/32 IP TE 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + 10.0.255.2/32 IP TE 55 rt6 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt1 TE-IS 10 rt1 - rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt4 - rt4(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -10.0.255.2/32 IP TE 35 rt1 - rt2(4) -rt3 TE-IS 40 rt3 - rt5(4) - rt1 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) - rt1 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt1 TE-IS 10 rt1 - rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 - rt4(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 10.0.255.2/32 IP TE 35 rt1 - rt2(4) + rt3 TE-IS 40 rt3 - rt5(4) + rt1 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + rt1 - rt3(4) + Main: IS-IS L1 IPv4 routing table: @@ -2041,39 +2155,43 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt1 TE-IS 10 rt1 - rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt1 pseudo_TE-IS 20 rt1 - rt1(4) - rt4 - rt4(4) -2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt2 TE-IS 25 rt1 - rt1(4) -2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) -rt3 TE-IS 40 rt3 - rt5(4) - rt1 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) - rt1 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt1 TE-IS 10 rt1 - rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt1 pseudo_TE-IS 20 rt1 - rt1(4) + rt4 - rt4(4) + 2001:db8::1/128 IP6 internal 20 rt1 - rt1(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt2 TE-IS 25 rt1 - rt1(4) + 2001:db8::2/128 IP6 internal 35 rt1 - rt2(4) + rt3 TE-IS 40 rt3 - rt5(4) + rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + rt1 - rt3(4) + Main: IS-IS L1 IPv6 routing table: @@ -2123,38 +2241,42 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) -rt2 TE-IS 30 rt6 - rt4(4) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt1 TE-IS 40 rt3 - rt3(4) - rt6 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -10.0.255.2/32 IP TE 40 rt6 - rt2(4) -10.0.255.1/32 IP TE 50 rt3 - rt1(4) - rt6 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt2 TE-IS 30 rt6 - rt4(4) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt1 TE-IS 40 rt3 - rt3(4) + rt6 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + 10.0.255.2/32 IP TE 40 rt6 - rt2(4) + 10.0.255.1/32 IP TE 50 rt3 - rt1(4) + rt6 - rt1(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) - rt4 - rt2(4) -rt1 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) - rt4 - -10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt4 - rt2(4) + rt1 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 - rt3(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2210,36 +2332,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 TE-IS 30 rt4 - rt2(4) -rt3 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.1/32 IP TE 40 rt4 - rt1(4) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 TE-IS 30 rt4 - rt2(4) + rt3 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) - rt4 - rt2(4) -rt1 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) - rt4 - -10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt4 - rt2(4) + rt1 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 - rt3(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2276,44 +2402,48 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt3 - rt7(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 50 rt3 - rt8(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt4 TE-IS 60 rt3 - rt6(4) -10.0.255.6/32 IP TE 60 rt3 - rt6(4) -rt2 TE-IS 70 rt3 - rt4(4) -10.0.255.4/32 IP TE 70 rt3 - rt4(4) -10.0.255.2/32 IP TE 80 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt3 - rt7(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 50 rt3 - rt8(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt4 TE-IS 60 rt3 - rt6(4) + 10.0.255.6/32 IP TE 60 rt3 - rt6(4) + rt2 TE-IS 70 rt3 - rt4(4) + 10.0.255.4/32 IP TE 70 rt3 - rt4(4) + 10.0.255.2/32 IP TE 80 rt3 - rt2(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt2 - rt4(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt2 - rt6(4) - rt3 - rt7(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt2 - rt4(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt2 - rt6(4) + rt3 - rt7(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + rt3 - rt8(4) + Main: IS-IS L1 IPv4 routing table: @@ -2362,46 +2492,50 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt2 - rt1(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt2 - rt1(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt3 TE-IS 10 rt3 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) - rt3 - -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt3 TE-IS 10 rt3 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt3 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -2452,64 +2586,68 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt9 TE-IS 20 rt12 - rt12(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt7 TE-IS 30 rt10 - rt10(4) -rt8 TE-IS 30 rt12 - rt9(4) -10.0.255.9/32 IP TE 30 rt12 - rt9(4) -rt4 TE-IS 40 rt10 - rt7(4) -rt5 TE-IS 40 rt12 - rt8(4) -10.0.255.7/32 IP TE 40 rt10 - rt7(4) -10.0.255.8/32 IP TE 40 rt12 - rt8(4) -rt6 TE-IS 50 rt12 - rt9(4) - rt5(4) -rt1 TE-IS 50 rt10 - rt4(4) -rt2 TE-IS 50 rt12 - rt5(4) -10.0.255.4/32 IP TE 50 rt10 - rt4(4) -10.0.255.5/32 IP TE 50 rt12 - rt5(4) -rt3 TE-IS 60 rt12 - rt6(4) - rt2(4) -10.0.255.6/32 IP TE 60 rt12 - rt6(4) -10.0.255.1/32 IP TE 60 rt10 - rt1(4) -10.0.255.2/32 IP TE 60 rt12 - rt2(4) -10.0.255.3/32 IP TE 70 rt12 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt9 TE-IS 20 rt12 - rt12(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt7 TE-IS 30 rt10 - rt10(4) + rt8 TE-IS 30 rt12 - rt9(4) + 10.0.255.9/32 IP TE 30 rt12 - rt9(4) + rt4 TE-IS 40 rt10 - rt7(4) + rt5 TE-IS 40 rt12 - rt8(4) + 10.0.255.7/32 IP TE 40 rt10 - rt7(4) + 10.0.255.8/32 IP TE 40 rt12 - rt8(4) + rt6 TE-IS 50 rt12 - rt9(4) + rt5(4) + rt1 TE-IS 50 rt10 - rt4(4) + rt2 TE-IS 50 rt12 - rt5(4) + 10.0.255.4/32 IP TE 50 rt10 - rt4(4) + 10.0.255.5/32 IP TE 50 rt12 - rt5(4) + rt3 TE-IS 60 rt12 - rt6(4) + rt2(4) + 10.0.255.6/32 IP TE 60 rt12 - rt6(4) + 10.0.255.1/32 IP TE 60 rt10 - rt1(4) + 10.0.255.2/32 IP TE 60 rt12 - rt2(4) + 10.0.255.3/32 IP TE 70 rt12 - rt3(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt8 TE-IS 10 rt8 - rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt5 TE-IS 20 rt8 - rt8(4) -rt7 TE-IS 20 rt8 - rt8(4) -rt9 TE-IS 20 rt8 - rt8(4) - rt12 - rt12(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt2 TE-IS 30 rt8 - rt5(4) -rt4 TE-IS 30 rt8 - rt5(4) - rt7(4) -rt6 TE-IS 30 rt8 - rt5(4) -10.0.255.5/32 IP TE 30 rt8 - rt5(4) -10.0.255.7/32 IP TE 30 rt8 - rt7(4) -10.0.255.9/32 IP TE 30 rt8 - rt9(4) - rt12 - -rt3 TE-IS 40 rt8 - rt2(4) - rt6(4) -rt1 TE-IS 40 rt8 - rt4(4) -10.0.255.2/32 IP TE 40 rt8 - rt2(4) -10.0.255.4/32 IP TE 40 rt8 - rt4(4) -10.0.255.6/32 IP TE 40 rt8 - rt6(4) -10.0.255.3/32 IP TE 50 rt8 - rt3(4) -10.0.255.1/32 IP TE 50 rt8 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt8 TE-IS 10 rt8 - rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt5 TE-IS 20 rt8 - rt8(4) + rt7 TE-IS 20 rt8 - rt8(4) + rt9 TE-IS 20 rt8 - rt8(4) + rt12 - rt12(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt2 TE-IS 30 rt8 - rt5(4) + rt4 TE-IS 30 rt8 - rt5(4) + rt7(4) + rt6 TE-IS 30 rt8 - rt5(4) + 10.0.255.5/32 IP TE 30 rt8 - rt5(4) + 10.0.255.7/32 IP TE 30 rt8 - rt7(4) + 10.0.255.9/32 IP TE 30 rt8 - rt9(4) + rt12 - rt9(4) + rt3 TE-IS 40 rt8 - rt2(4) + rt6(4) + rt1 TE-IS 40 rt8 - rt4(4) + 10.0.255.2/32 IP TE 40 rt8 - rt2(4) + 10.0.255.4/32 IP TE 40 rt8 - rt4(4) + 10.0.255.6/32 IP TE 40 rt8 - rt6(4) + 10.0.255.3/32 IP TE 50 rt8 - rt3(4) + 10.0.255.1/32 IP TE 50 rt8 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2577,73 +2715,77 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt9 TE-IS 30 rt9 - rt6(4) -rt5 TE-IS 30 rt3 - rt2(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) -rt8 TE-IS 40 rt9 - rt9(4) - rt3 - rt5(4) -rt12 TE-IS 40 rt9 - rt9(4) -rt4 TE-IS 40 rt3 - rt5(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt7 TE-IS 50 rt9 - rt8(4) - rt3 - rt4(4) -rt11 TE-IS 50 rt9 - rt8(4) - rt3 - rt12(4) -rt1 TE-IS 50 rt3 - rt4(4) -10.0.255.8/32 IP TE 50 rt9 - rt8(4) - rt3 - -10.0.255.12/32 IP TE 50 rt9 - rt12(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -rt10 TE-IS 60 rt9 - rt11(4) - rt3 - -10.0.255.7/32 IP TE 60 rt9 - rt7(4) - rt3 - -10.0.255.11/32 IP TE 60 rt9 - rt11(4) - rt3 - -10.0.255.1/32 IP TE 60 rt3 - rt1(4) -10.0.255.10/32 IP TE 70 rt9 - rt10(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 TE-IS 30 rt3 - rt2(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt8 TE-IS 40 rt9 - rt9(4) + rt3 - rt5(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt4 TE-IS 40 rt3 - rt5(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt7 TE-IS 50 rt9 - rt8(4) + rt3 - rt4(4) + rt11 TE-IS 50 rt9 - rt8(4) + rt3 - rt12(4) + rt1 TE-IS 50 rt3 - rt4(4) + 10.0.255.8/32 IP TE 50 rt9 - rt8(4) + rt3 - rt8(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + rt10 TE-IS 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.7/32 IP TE 60 rt9 - rt7(4) + rt3 - rt7(4) + 10.0.255.11/32 IP TE 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.1/32 IP TE 60 rt3 - rt1(4) + 10.0.255.10/32 IP TE 70 rt9 - rt10(4) + rt3 - rt10(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt5 TE-IS 10 rt5 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt4 TE-IS 20 rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt9 TE-IS 30 rt9 - rt6(4) - rt5 - rt8(4) -rt1 TE-IS 30 rt5 - rt4(4) -rt7 TE-IS 30 rt5 - rt4(4) - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) - rt5 - -10.0.255.4/32 IP TE 30 rt5 - rt4(4) -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt12 TE-IS 40 rt9 - rt9(4) - rt5 - rt11(4) -rt10 TE-IS 40 rt5 - rt11(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) - rt5 - -10.0.255.1/32 IP TE 40 rt5 - rt1(4) -10.0.255.7/32 IP TE 40 rt5 - rt7(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.12/32 IP TE 50 rt9 - rt12(4) - rt5 - -10.0.255.10/32 IP TE 50 rt5 - rt10(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt5 TE-IS 10 rt5 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt4 TE-IS 20 rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 - rt8(4) + rt1 TE-IS 30 rt5 - rt4(4) + rt7 TE-IS 30 rt5 - rt4(4) + rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt5 - rt2(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt5 - rt11(4) + rt10 TE-IS 40 rt5 - rt11(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + rt5 - rt9(4) + 10.0.255.1/32 IP TE 40 rt5 - rt1(4) + 10.0.255.7/32 IP TE 40 rt5 - rt7(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + rt5 - rt12(4) + 10.0.255.10/32 IP TE 50 rt5 - rt10(4) + Main: IS-IS L1 IPv4 routing table: @@ -2706,62 +2848,66 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt5 TE-IS 30 rt3 - rt6(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt8 TE-IS 40 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt9 TE-IS 50 rt3 - rt8(4) -rt11 TE-IS 50 rt3 - rt8(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt12 TE-IS 60 rt3 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 60 rt3 - rt9(4) -10.0.255.11/32 IP TE 60 rt3 - rt11(4) -10.0.255.12/32 IP TE 70 rt3 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt5 TE-IS 30 rt3 - rt6(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt8 TE-IS 40 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt9 TE-IS 50 rt3 - rt8(4) + rt11 TE-IS 50 rt3 - rt8(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt12 TE-IS 60 rt3 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 60 rt3 - rt9(4) + 10.0.255.11/32 IP TE 60 rt3 - rt11(4) + 10.0.255.12/32 IP TE 70 rt3 - rt12(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt5 TE-IS 10 rt5 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt9 TE-IS 30 rt5 - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) - rt5 - -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt12 TE-IS 40 rt5 - rt9(4) - rt11(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.9/32 IP TE 40 rt5 - rt9(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.12/32 IP TE 50 rt5 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt5 TE-IS 10 rt5 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt9 TE-IS 30 rt5 - rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt5 - rt6(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt12 TE-IS 40 rt5 - rt9(4) + rt11(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.9/32 IP TE 40 rt5 - rt9(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.12/32 IP TE 50 rt5 - rt12(4) + Main: IS-IS L1 IPv4 routing table: @@ -2815,36 +2961,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -10.0.255.1/32 IP TE 60 rt1 - rt1(4) -10.0.255.3/32 IP TE 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -10.0.255.5/32 IP TE 70 rt3 - rt5(4) -10.0.255.4/32 IP TE 80 rt3 - rt4(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 10.0.255.1/32 IP TE 60 rt1 - rt1(4) + 10.0.255.3/32 IP TE 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 10.0.255.5/32 IP TE 70 rt3 - rt5(4) + 10.0.255.4/32 IP TE 80 rt3 - rt4(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt4 TE-IS 10 rt4 - rt2(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt6 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -rt3 TE-IS 30 rt4 - rt5(4) -10.0.255.5/32 IP TE 30 rt4 - rt5(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) -rt2 -rt1 TE-IS 40 rt4 - rt2(2) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) -10.0.255.1/32 IP TE 50 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt4 TE-IS 10 rt4 - rt2(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt6 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + rt3 TE-IS 30 rt4 - rt5(4) + 10.0.255.5/32 IP TE 30 rt4 - rt5(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt2 + rt1 TE-IS 40 rt4 - rt2(2) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + 10.0.255.1/32 IP TE 50 rt4 - rt1(4) + Main: IS-IS L1 IPv4 routing table: @@ -2893,36 +3043,40 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) -2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) -2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) + 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt4 TE-IS 10 rt4 - rt2(4) -rt5 TE-IS 20 rt4 - rt4(4) -rt6 TE-IS 20 rt4 - rt4(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -rt3 TE-IS 30 rt4 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) -rt2 -rt1 TE-IS 40 rt4 - rt2(2) -2001:db8::3/128 IP6 internal 40 rt4 - rt3(4) -2001:db8::1/128 IP6 internal 50 rt4 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt4 TE-IS 10 rt4 - rt2(4) + rt5 TE-IS 20 rt4 - rt4(4) + rt6 TE-IS 20 rt4 - rt4(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + rt3 TE-IS 30 rt4 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt4 - rt5(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt2 + rt1 TE-IS 40 rt4 - rt2(2) + 2001:db8::3/128 IP6 internal 40 rt4 - rt3(4) + 2001:db8::1/128 IP6 internal 50 rt4 - rt1(4) + Main: IS-IS L1 IPv6 routing table: @@ -2966,42 +3120,46 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt5 TE-IS 40 rt2 - rt3(4) -rt6 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) - rt6(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.6/32 IP TE 50 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 TE-IS 40 rt2 - rt3(4) + rt6 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt6(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.6/32 IP TE 50 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) - rt3 - rt3(4) -rt5 TE-IS 20 rt3 - rt3(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) - rt6(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) - rt3 - -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + rt3 - rt3(4) + rt5 TE-IS 20 rt3 - rt3(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + rt6(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt3 - rt4(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + Main: IS-IS L1 IPv4 routing table: @@ -3044,19 +3202,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -10.0.255.2/32 IP TE 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + 10.0.255.2/32 IP TE 60 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3080,19 +3240,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt6 TE-IS 30 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) -rt4 TE-IS 40 rt3 - rt6(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -rt2 TE-IS 50 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) -2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt6 TE-IS 30 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 30 rt3 - rt5(4) + rt4 TE-IS 40 rt3 - rt6(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + rt2 TE-IS 50 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt3 - rt4(4) + 2001:db8::2/128 IP6 internal 60 rt3 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -3127,22 +3289,24 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -10.0.255.6/32 IP TE 30 rt4 - rt6(4) - rt5 - -rt3 TE-IS 50 rt5 - rt5(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + 10.0.255.6/32 IP TE 30 rt4 - rt6(4) + rt5 - rt6(4) + rt3 TE-IS 50 rt5 - rt5(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3175,22 +3339,24 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt4 TE-IS 10 rt4 - rt1(4) -rt5 TE-IS 10 rt5 - rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -rt1 -rt6 TE-IS 20 rt4 - rt4(4) - rt5 - rt5(4) -2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) - rt5 - -rt3 TE-IS 50 rt5 - rt5(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt4 TE-IS 10 rt4 - rt1(4) + rt5 TE-IS 10 rt5 - rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + rt1 + rt6 TE-IS 20 rt4 - rt4(4) + rt5 - rt5(4) + 2001:db8::4/128 IP6 internal 20 rt4 - rt4(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + 2001:db8::6/128 IP6 internal 30 rt4 - rt6(4) + rt5 - rt6(4) + rt3 TE-IS 50 rt5 - rt5(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -3217,20 +3383,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -10.0.255.2/32 IP TE 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -rt4 TE-IS 55 rt2 - rt2(4) -rt1 -rt6 TE-IS 65 rt2 - rt4(4) -rt5 TE-IS 65 rt2 - rt1(2) -10.0.255.4/32 IP TE 65 rt2 - rt4(4) -10.0.255.6/32 IP TE 75 rt2 - rt6(4) -10.0.255.5/32 IP TE 75 rt2 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + 10.0.255.2/32 IP TE 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + rt4 TE-IS 55 rt2 - rt2(4) + rt1 + rt6 TE-IS 65 rt2 - rt4(4) + rt5 TE-IS 65 rt2 - rt1(2) + 10.0.255.4/32 IP TE 65 rt2 - rt4(4) + 10.0.255.6/32 IP TE 75 rt2 - rt6(4) + 10.0.255.5/32 IP TE 75 rt2 - rt5(4) + IS-IS L1 IPv4 routing table: @@ -3258,20 +3426,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 15 rt2 - rt1(4) -2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) -rt3 TE-IS 30 rt3 - rt1(4) -2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) -rt4 TE-IS 55 rt2 - rt2(4) -rt1 -rt6 TE-IS 65 rt2 - rt4(4) -rt5 TE-IS 65 rt2 - rt1(2) -2001:db8::4/128 IP6 internal 65 rt2 - rt4(4) -2001:db8::6/128 IP6 internal 75 rt2 - rt6(4) -2001:db8::5/128 IP6 internal 75 rt2 - rt5(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 15 rt2 - rt1(4) + 2001:db8::2/128 IP6 internal 25 rt2 - rt2(4) + rt3 TE-IS 30 rt3 - rt1(4) + 2001:db8::3/128 IP6 internal 40 rt3 - rt3(4) + rt4 TE-IS 55 rt2 - rt2(4) + rt1 + rt6 TE-IS 65 rt2 - rt4(4) + rt5 TE-IS 65 rt2 - rt1(2) + 2001:db8::4/128 IP6 internal 65 rt2 - rt4(4) + 2001:db8::6/128 IP6 internal 75 rt2 - rt6(4) + 2001:db8::5/128 IP6 internal 75 rt2 - rt5(4) + IS-IS L1 IPv6 routing table: @@ -3303,20 +3473,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -10.0.255.1/32 IP TE 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -10.0.255.3/32 IP TE 50 rt3 - rt3(4) -10.0.255.2/32 IP TE 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------ + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 10.0.255.1/32 IP TE 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 10.0.255.3/32 IP TE 50 rt3 - rt3(4) + 10.0.255.2/32 IP TE 55 rt6 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3347,20 +3519,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt5 -2001:db8::5/128 IP6 internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -rt1 pseudo_TE-IS 30 rt6 - rt4(4) -rt1 TE-IS 30 rt6 - rt1(2) -2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) -rt3 TE-IS 40 rt3 - rt5(4) -2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) -rt2 TE-IS 45 rt6 - rt1(4) -2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) -2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt5 + 2001:db8::5/128 IP6 internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + rt1 pseudo_TE-IS 30 rt6 - rt4(4) + rt1 TE-IS 30 rt6 - rt1(2) + 2001:db8::4/128 IP6 internal 30 rt6 - rt4(4) + rt3 TE-IS 40 rt3 - rt5(4) + 2001:db8::1/128 IP6 internal 40 rt6 - rt1(4) + rt2 TE-IS 45 rt6 - rt1(4) + 2001:db8::3/128 IP6 internal 50 rt3 - rt3(4) + 2001:db8::2/128 IP6 internal 55 rt6 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -3396,21 +3570,23 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt4 TE-IS 20 rt6 - rt6(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt3 - rt5(4) -rt2 TE-IS 30 rt6 - rt4(4) -10.0.255.4/32 IP TE 30 rt6 - rt4(4) -rt1 TE-IS 40 rt3 - rt3(4) - rt6 - rt2(4) -10.0.255.3/32 IP TE 40 rt3 - rt3(4) -10.0.255.2/32 IP TE 40 rt6 - rt2(4) -10.0.255.1/32 IP TE 50 rt3 - rt1(4) - rt6 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt4 TE-IS 20 rt6 - rt6(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt3 - rt5(4) + rt2 TE-IS 30 rt6 - rt4(4) + 10.0.255.4/32 IP TE 30 rt6 - rt4(4) + rt1 TE-IS 40 rt3 - rt3(4) + rt6 - rt2(4) + 10.0.255.3/32 IP TE 40 rt3 - rt3(4) + 10.0.255.2/32 IP TE 40 rt6 - rt2(4) + 10.0.255.1/32 IP TE 50 rt3 - rt1(4) + rt6 - rt1(4) + IS-IS L1 IPv4 routing table: @@ -3450,19 +3626,21 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt5 -10.0.255.5/32 IP internal 0 rt5(4) -rt4 TE-IS 10 rt4 - rt5(4) -rt6 TE-IS 10 rt6 - rt5(4) -rt2 TE-IS 20 rt4 - rt4(4) -10.0.255.4/32 IP TE 20 rt4 - rt4(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt1 TE-IS 30 rt4 - rt2(4) -rt3 TE-IS 30 rt4 - rt2(4) -10.0.255.2/32 IP TE 30 rt4 - rt2(4) -10.0.255.1/32 IP TE 40 rt4 - rt1(4) -10.0.255.3/32 IP TE 40 rt4 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt5 + 10.0.255.5/32 IP internal 0 rt5(4) + rt4 TE-IS 10 rt4 - rt5(4) + rt6 TE-IS 10 rt6 - rt5(4) + rt2 TE-IS 20 rt4 - rt4(4) + 10.0.255.4/32 IP TE 20 rt4 - rt4(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt1 TE-IS 30 rt4 - rt2(4) + rt3 TE-IS 30 rt4 - rt2(4) + 10.0.255.2/32 IP TE 30 rt4 - rt2(4) + 10.0.255.1/32 IP TE 40 rt4 - rt1(4) + 10.0.255.3/32 IP TE 40 rt4 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3484,23 +3662,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 70 rt3 - rt5(4) -rt4 TE-IS 80 rt3 - rt6(4) -rt8 TE-IS 80 rt3 - rt6(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) -rt2 TE-IS 90 rt3 - rt4(4) -10.0.255.4/32 IP TE 90 rt3 - rt4(4) -10.0.255.8/32 IP TE 90 rt3 - rt8(4) -10.0.255.2/32 IP TE 100 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 70 rt3 - rt5(4) + rt4 TE-IS 80 rt3 - rt6(4) + rt8 TE-IS 80 rt3 - rt6(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + rt2 TE-IS 90 rt3 - rt4(4) + 10.0.255.4/32 IP TE 90 rt3 - rt4(4) + 10.0.255.8/32 IP TE 90 rt3 - rt8(4) + 10.0.255.2/32 IP TE 100 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3531,23 +3711,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt1(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -rt5 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -rt6 TE-IS 90 rt2 - rt5(4) -rt8 TE-IS 100 rt2 - rt6(4) -10.0.255.6/32 IP TE 100 rt2 - rt6(4) -10.0.255.8/32 IP TE 110 rt2 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt1(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + rt5 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + rt6 TE-IS 90 rt2 - rt5(4) + rt8 TE-IS 100 rt2 - rt6(4) + 10.0.255.6/32 IP TE 100 rt2 - rt6(4) + 10.0.255.8/32 IP TE 110 rt2 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -3575,23 +3757,25 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -rt5 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt3 - rt5(4) -10.0.255.5/32 IP TE 30 rt3 - rt5(4) -rt8 TE-IS 40 rt3 - rt7(4) -10.0.255.7/32 IP TE 40 rt3 - rt7(4) -rt6 TE-IS 50 rt3 - rt8(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt4 TE-IS 60 rt3 - rt6(4) -10.0.255.6/32 IP TE 60 rt3 - rt6(4) -rt2 TE-IS 70 rt3 - rt4(4) -10.0.255.4/32 IP TE 70 rt3 - rt4(4) -10.0.255.2/32 IP TE 80 rt3 - rt2(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + rt5 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt3 - rt5(4) + 10.0.255.5/32 IP TE 30 rt3 - rt5(4) + rt8 TE-IS 40 rt3 - rt7(4) + 10.0.255.7/32 IP TE 40 rt3 - rt7(4) + rt6 TE-IS 50 rt3 - rt8(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt4 TE-IS 60 rt3 - rt6(4) + 10.0.255.6/32 IP TE 60 rt3 - rt6(4) + rt2 TE-IS 70 rt3 - rt4(4) + 10.0.255.4/32 IP TE 70 rt3 - rt4(4) + 10.0.255.2/32 IP TE 80 rt3 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -3624,24 +3808,26 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt4 -10.0.255.4/32 IP internal 0 rt4(4) -rt2 TE-IS 10 rt2 - rt4(4) -rt6 TE-IS 10 rt6 - rt4(4) -rt1 TE-IS 20 rt2 - rt2(4) -rt5 TE-IS 20 rt6 - rt6(4) -rt8 TE-IS 20 rt6 - rt6(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -rt3 TE-IS 30 rt2 - rt1(4) -rt7 TE-IS 30 rt6 - rt5(4) - rt8(4) -10.0.255.1/32 IP TE 30 rt2 - rt1(4) -10.0.255.5/32 IP TE 30 rt6 - rt5(4) -10.0.255.8/32 IP TE 30 rt6 - rt8(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -10.0.255.7/32 IP TE 40 rt6 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt4 + 10.0.255.4/32 IP internal 0 rt4(4) + rt2 TE-IS 10 rt2 - rt4(4) + rt6 TE-IS 10 rt6 - rt4(4) + rt1 TE-IS 20 rt2 - rt2(4) + rt5 TE-IS 20 rt6 - rt6(4) + rt8 TE-IS 20 rt6 - rt6(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + rt3 TE-IS 30 rt2 - rt1(4) + rt7 TE-IS 30 rt6 - rt5(4) + rt8(4) + 10.0.255.1/32 IP TE 30 rt2 - rt1(4) + 10.0.255.5/32 IP TE 30 rt6 - rt5(4) + 10.0.255.8/32 IP TE 30 rt6 - rt8(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + 10.0.255.7/32 IP TE 40 rt6 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -3676,33 +3862,35 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt11 -10.0.255.11/32 IP internal 0 rt11(4) -rt10 TE-IS 10 rt10 - rt11(4) -rt12 TE-IS 10 rt12 - rt11(4) -rt9 TE-IS 20 rt12 - rt12(4) -10.0.255.10/32 IP TE 20 rt10 - rt10(4) -10.0.255.12/32 IP TE 20 rt12 - rt12(4) -rt7 TE-IS 30 rt10 - rt10(4) -rt8 TE-IS 30 rt12 - rt9(4) -10.0.255.9/32 IP TE 30 rt12 - rt9(4) -rt4 TE-IS 40 rt10 - rt7(4) -rt5 TE-IS 40 rt12 - rt8(4) -10.0.255.7/32 IP TE 40 rt10 - rt7(4) -10.0.255.8/32 IP TE 40 rt12 - rt8(4) -rt6 TE-IS 50 rt12 - rt9(4) - rt5(4) -rt1 TE-IS 50 rt10 - rt4(4) -rt2 TE-IS 50 rt12 - rt5(4) -10.0.255.4/32 IP TE 50 rt10 - rt4(4) -10.0.255.5/32 IP TE 50 rt12 - rt5(4) -rt3 TE-IS 60 rt12 - rt6(4) - rt2(4) -10.0.255.6/32 IP TE 60 rt12 - rt6(4) -10.0.255.1/32 IP TE 60 rt10 - rt1(4) -10.0.255.2/32 IP TE 60 rt12 - rt2(4) -10.0.255.3/32 IP TE 70 rt12 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt11 + 10.0.255.11/32 IP internal 0 rt11(4) + rt10 TE-IS 10 rt10 - rt11(4) + rt12 TE-IS 10 rt12 - rt11(4) + rt9 TE-IS 20 rt12 - rt12(4) + 10.0.255.10/32 IP TE 20 rt10 - rt10(4) + 10.0.255.12/32 IP TE 20 rt12 - rt12(4) + rt7 TE-IS 30 rt10 - rt10(4) + rt8 TE-IS 30 rt12 - rt9(4) + 10.0.255.9/32 IP TE 30 rt12 - rt9(4) + rt4 TE-IS 40 rt10 - rt7(4) + rt5 TE-IS 40 rt12 - rt8(4) + 10.0.255.7/32 IP TE 40 rt10 - rt7(4) + 10.0.255.8/32 IP TE 40 rt12 - rt8(4) + rt6 TE-IS 50 rt12 - rt9(4) + rt5(4) + rt1 TE-IS 50 rt10 - rt4(4) + rt2 TE-IS 50 rt12 - rt5(4) + 10.0.255.4/32 IP TE 50 rt10 - rt4(4) + 10.0.255.5/32 IP TE 50 rt12 - rt5(4) + rt3 TE-IS 60 rt12 - rt6(4) + rt2(4) + 10.0.255.6/32 IP TE 60 rt12 - rt6(4) + 10.0.255.1/32 IP TE 60 rt10 - rt1(4) + 10.0.255.2/32 IP TE 60 rt12 - rt2(4) + 10.0.255.3/32 IP TE 70 rt12 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -3750,39 +3938,41 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt6 -10.0.255.6/32 IP internal 0 rt6(4) -rt3 TE-IS 10 rt3 - rt6(4) -rt2 TE-IS 20 rt3 - rt3(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt9 TE-IS 30 rt9 - rt6(4) -rt5 TE-IS 30 rt3 - rt2(4) -10.0.255.2/32 IP TE 30 rt3 - rt2(4) -rt8 TE-IS 40 rt9 - rt9(4) - rt3 - rt5(4) -rt12 TE-IS 40 rt9 - rt9(4) -rt4 TE-IS 40 rt3 - rt5(4) -10.0.255.9/32 IP TE 40 rt9 - rt9(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt7 TE-IS 50 rt9 - rt8(4) - rt3 - rt4(4) -rt11 TE-IS 50 rt9 - rt8(4) - rt3 - rt12(4) -rt1 TE-IS 50 rt3 - rt4(4) -10.0.255.8/32 IP TE 50 rt9 - rt8(4) - rt3 - -10.0.255.12/32 IP TE 50 rt9 - rt12(4) -10.0.255.4/32 IP TE 50 rt3 - rt4(4) -rt10 TE-IS 60 rt9 - rt11(4) - rt3 - -10.0.255.7/32 IP TE 60 rt9 - rt7(4) - rt3 - -10.0.255.11/32 IP TE 60 rt9 - rt11(4) - rt3 - -10.0.255.1/32 IP TE 60 rt3 - rt1(4) -10.0.255.10/32 IP TE 70 rt9 - rt10(4) - rt3 - + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt6 + 10.0.255.6/32 IP internal 0 rt6(4) + rt3 TE-IS 10 rt3 - rt6(4) + rt2 TE-IS 20 rt3 - rt3(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt9 TE-IS 30 rt9 - rt6(4) + rt5 TE-IS 30 rt3 - rt2(4) + 10.0.255.2/32 IP TE 30 rt3 - rt2(4) + rt8 TE-IS 40 rt9 - rt9(4) + rt3 - rt5(4) + rt12 TE-IS 40 rt9 - rt9(4) + rt4 TE-IS 40 rt3 - rt5(4) + 10.0.255.9/32 IP TE 40 rt9 - rt9(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt7 TE-IS 50 rt9 - rt8(4) + rt3 - rt4(4) + rt11 TE-IS 50 rt9 - rt8(4) + rt3 - rt12(4) + rt1 TE-IS 50 rt3 - rt4(4) + 10.0.255.8/32 IP TE 50 rt9 - rt8(4) + rt3 - rt8(4) + 10.0.255.12/32 IP TE 50 rt9 - rt12(4) + 10.0.255.4/32 IP TE 50 rt3 - rt4(4) + rt10 TE-IS 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.7/32 IP TE 60 rt9 - rt7(4) + rt3 - rt7(4) + 10.0.255.11/32 IP TE 60 rt9 - rt11(4) + rt3 - rt11(4) + 10.0.255.1/32 IP TE 60 rt3 - rt1(4) + 10.0.255.10/32 IP TE 70 rt9 - rt10(4) + rt3 - rt10(4) + IS-IS L1 IPv4 routing table: @@ -3829,34 +4019,36 @@ Q-space: rt10 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt5 TE-IS 10 rt5 - rt2(4) -rt6 TE-IS 20 rt3 - rt3(4) - rt5 - rt5(4) -rt8 TE-IS 20 rt5 - rt5(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -rt9 TE-IS 30 rt5 - rt8(4) -rt11 TE-IS 30 rt5 - rt8(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) - rt5 - -10.0.255.8/32 IP TE 30 rt5 - rt8(4) -rt12 TE-IS 40 rt5 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 40 rt5 - rt9(4) -10.0.255.11/32 IP TE 40 rt5 - rt11(4) -10.0.255.12/32 IP TE 50 rt5 - rt12(4) -rt10 TE-IS 60 rt5 - rt11(4) -rt7 TE-IS 70 rt5 - rt10(4) -10.0.255.10/32 IP TE 70 rt5 - rt10(4) -rt4 TE-IS 80 rt5 - rt7(4) -10.0.255.7/32 IP TE 80 rt5 - rt7(4) -rt1 TE-IS 90 rt5 - rt4(4) -10.0.255.4/32 IP TE 90 rt5 - rt4(4) -10.0.255.1/32 IP TE 100 rt5 - rt1(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt5 TE-IS 10 rt5 - rt2(4) + rt6 TE-IS 20 rt3 - rt3(4) + rt5 - rt5(4) + rt8 TE-IS 20 rt5 - rt5(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + rt9 TE-IS 30 rt5 - rt8(4) + rt11 TE-IS 30 rt5 - rt8(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt5 - rt6(4) + 10.0.255.8/32 IP TE 30 rt5 - rt8(4) + rt12 TE-IS 40 rt5 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 40 rt5 - rt9(4) + 10.0.255.11/32 IP TE 40 rt5 - rt11(4) + 10.0.255.12/32 IP TE 50 rt5 - rt12(4) + rt10 TE-IS 60 rt5 - rt11(4) + rt7 TE-IS 70 rt5 - rt10(4) + 10.0.255.10/32 IP TE 70 rt5 - rt10(4) + rt4 TE-IS 80 rt5 - rt7(4) + 10.0.255.7/32 IP TE 80 rt5 - rt7(4) + rt1 TE-IS 90 rt5 - rt4(4) + 10.0.255.4/32 IP TE 90 rt5 - rt4(4) + 10.0.255.1/32 IP TE 100 rt5 - rt1(4) + IS-IS L1 IPv4 routing table: @@ -3894,32 +4086,34 @@ Q-space: rt12 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 10 rt1 - rt2(4) -rt3 TE-IS 10 rt3 - rt2(4) -rt4 TE-IS 20 rt1 - rt1(4) -rt6 TE-IS 20 rt3 - rt3(4) -10.0.255.1/32 IP TE 20 rt1 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt7 TE-IS 30 rt1 - rt4(4) -rt5 TE-IS 30 rt3 - rt6(4) -10.0.255.4/32 IP TE 30 rt1 - rt4(4) -10.0.255.6/32 IP TE 30 rt3 - rt6(4) -rt10 TE-IS 40 rt1 - rt7(4) -rt8 TE-IS 40 rt3 - rt5(4) -10.0.255.7/32 IP TE 40 rt1 - rt7(4) -10.0.255.5/32 IP TE 40 rt3 - rt5(4) -rt9 TE-IS 50 rt3 - rt8(4) -rt11 TE-IS 50 rt3 - rt8(4) -10.0.255.10/32 IP TE 50 rt1 - rt10(4) -10.0.255.8/32 IP TE 50 rt3 - rt8(4) -rt12 TE-IS 60 rt3 - rt9(4) - rt11(4) -10.0.255.9/32 IP TE 60 rt3 - rt9(4) -10.0.255.11/32 IP TE 60 rt3 - rt11(4) -10.0.255.12/32 IP TE 70 rt3 - rt12(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 10 rt1 - rt2(4) + rt3 TE-IS 10 rt3 - rt2(4) + rt4 TE-IS 20 rt1 - rt1(4) + rt6 TE-IS 20 rt3 - rt3(4) + 10.0.255.1/32 IP TE 20 rt1 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt7 TE-IS 30 rt1 - rt4(4) + rt5 TE-IS 30 rt3 - rt6(4) + 10.0.255.4/32 IP TE 30 rt1 - rt4(4) + 10.0.255.6/32 IP TE 30 rt3 - rt6(4) + rt10 TE-IS 40 rt1 - rt7(4) + rt8 TE-IS 40 rt3 - rt5(4) + 10.0.255.7/32 IP TE 40 rt1 - rt7(4) + 10.0.255.5/32 IP TE 40 rt3 - rt5(4) + rt9 TE-IS 50 rt3 - rt8(4) + rt11 TE-IS 50 rt3 - rt8(4) + 10.0.255.10/32 IP TE 50 rt1 - rt10(4) + 10.0.255.8/32 IP TE 50 rt3 - rt8(4) + rt12 TE-IS 60 rt3 - rt9(4) + rt11(4) + 10.0.255.9/32 IP TE 60 rt3 - rt9(4) + 10.0.255.11/32 IP TE 60 rt3 - rt11(4) + 10.0.255.12/32 IP TE 70 rt3 - rt12(4) + IS-IS L1 IPv4 routing table: @@ -3954,28 +4148,30 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt5 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -10.0.255.5/32 IP TE 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 50 rt2 - rt9(4) -10.0.255.6/32 IP TE 60 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) -10.0.255.8/32 IP TE 60 rt2 - rt8(4) -rt3 TE-IS 120 rt2 - rt4(4) -10.0.255.3/32 IP TE 130 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt5 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 10.0.255.5/32 IP TE 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 50 rt2 - rt9(4) + 10.0.255.6/32 IP TE 60 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + 10.0.255.8/32 IP TE 60 rt2 - rt8(4) + rt3 TE-IS 120 rt2 - rt4(4) + 10.0.255.3/32 IP TE 130 rt2 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4005,28 +4201,30 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt5 TE-IS 30 rt2 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) -rt9 TE-IS 40 rt2 - rt5(4) -2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) -rt6 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt7 TE-IS 50 rt2 - rt4(4) - rt9(4) -rt8 TE-IS 50 rt2 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) -2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) -2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) -2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) -rt3 TE-IS 120 rt2 - rt4(4) -2001:db8::3/128 IP6 internal 130 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt5 TE-IS 30 rt2 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt2 - rt4(4) + rt9 TE-IS 40 rt2 - rt5(4) + 2001:db8::5/128 IP6 internal 40 rt2 - rt5(4) + rt6 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt7 TE-IS 50 rt2 - rt4(4) + rt9(4) + rt8 TE-IS 50 rt2 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 50 rt2 - rt9(4) + 2001:db8::6/128 IP6 internal 60 rt2 - rt6(4) + 2001:db8::7/128 IP6 internal 60 rt2 - rt7(4) + 2001:db8::8/128 IP6 internal 60 rt2 - rt8(4) + rt3 TE-IS 120 rt2 - rt4(4) + 2001:db8::3/128 IP6 internal 130 rt2 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4051,28 +4249,30 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -10.0.255.3/32 IP TE 20 rt3 - rt3(4) -rt4 TE-IS 110 rt3 - rt3(4) -rt2 TE-IS 120 rt3 - rt4(4) -rt5 TE-IS 120 rt3 - rt4(4) -10.0.255.4/32 IP TE 120 rt3 - rt4(4) -rt9 TE-IS 130 rt3 - rt5(4) -10.0.255.2/32 IP TE 130 rt3 - rt2(4) -10.0.255.5/32 IP TE 130 rt3 - rt5(4) -rt6 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt7 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt8 TE-IS 140 rt3 - rt4(4) - rt9(4) -10.0.255.9/32 IP TE 140 rt3 - rt9(4) -10.0.255.6/32 IP TE 150 rt3 - rt6(4) -10.0.255.7/32 IP TE 150 rt3 - rt7(4) -10.0.255.8/32 IP TE 150 rt3 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + 10.0.255.3/32 IP TE 20 rt3 - rt3(4) + rt4 TE-IS 110 rt3 - rt3(4) + rt2 TE-IS 120 rt3 - rt4(4) + rt5 TE-IS 120 rt3 - rt4(4) + 10.0.255.4/32 IP TE 120 rt3 - rt4(4) + rt9 TE-IS 130 rt3 - rt5(4) + 10.0.255.2/32 IP TE 130 rt3 - rt2(4) + 10.0.255.5/32 IP TE 130 rt3 - rt5(4) + rt6 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt7 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt8 TE-IS 140 rt3 - rt4(4) + rt9(4) + 10.0.255.9/32 IP TE 140 rt3 - rt9(4) + 10.0.255.6/32 IP TE 150 rt3 - rt6(4) + 10.0.255.7/32 IP TE 150 rt3 - rt7(4) + 10.0.255.8/32 IP TE 150 rt3 - rt8(4) + IS-IS L1 IPv4 routing table: @@ -4102,28 +4302,30 @@ Q-space: rt9 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 10 rt3 - rt1(4) -2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) -rt4 TE-IS 110 rt3 - rt3(4) -rt2 TE-IS 120 rt3 - rt4(4) -rt5 TE-IS 120 rt3 - rt4(4) -2001:db8::4/128 IP6 internal 120 rt3 - rt4(4) -rt9 TE-IS 130 rt3 - rt5(4) -2001:db8::2/128 IP6 internal 130 rt3 - rt2(4) -2001:db8::5/128 IP6 internal 130 rt3 - rt5(4) -rt6 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt7 TE-IS 140 rt3 - rt4(4) - rt9(4) -rt8 TE-IS 140 rt3 - rt4(4) - rt9(4) -2001:db8::9/128 IP6 internal 140 rt3 - rt9(4) -2001:db8::6/128 IP6 internal 150 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 150 rt3 - rt7(4) -2001:db8::8/128 IP6 internal 150 rt3 - rt8(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 10 rt3 - rt1(4) + 2001:db8::3/128 IP6 internal 20 rt3 - rt3(4) + rt4 TE-IS 110 rt3 - rt3(4) + rt2 TE-IS 120 rt3 - rt4(4) + rt5 TE-IS 120 rt3 - rt4(4) + 2001:db8::4/128 IP6 internal 120 rt3 - rt4(4) + rt9 TE-IS 130 rt3 - rt5(4) + 2001:db8::2/128 IP6 internal 130 rt3 - rt2(4) + 2001:db8::5/128 IP6 internal 130 rt3 - rt5(4) + rt6 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt7 TE-IS 140 rt3 - rt4(4) + rt9(4) + rt8 TE-IS 140 rt3 - rt4(4) + rt9(4) + 2001:db8::9/128 IP6 internal 140 rt3 - rt9(4) + 2001:db8::6/128 IP6 internal 150 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 150 rt3 - rt7(4) + 2001:db8::8/128 IP6 internal 150 rt3 - rt8(4) + IS-IS L1 IPv6 routing table: @@ -4160,45 +4362,47 @@ Q-space: rt5 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt9 -10.0.255.9/32 IP internal 0 rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt8 TE-IS 10 rt8 - rt9(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -10.0.255.8/32 IP TE 20 rt8 - rt8(4) -rt4 TE-IS 40 rt6 - rt6(4) - rt7 - rt7(4) - rt8 - rt8(4) -rt2 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -rt5 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -10.0.255.4/32 IP TE 50 rt6 - rt4(4) - rt7 - - rt8 - -rt1 TE-IS 60 rt6 - rt2(4) - rt7 - - rt8 - -10.0.255.2/32 IP TE 60 rt6 - rt2(4) - rt7 - - rt8 - -10.0.255.5/32 IP TE 60 rt6 - rt5(4) - rt7 - - rt8 - -rt3 TE-IS 70 rt6 - rt1(4) - rt7 - - rt8 - -10.0.255.1/32 IP TE 70 rt6 - rt1(4) - rt7 - - rt8 - -10.0.255.3/32 IP TE 80 rt6 - rt3(4) - rt7 - - rt8 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt9 + 10.0.255.9/32 IP internal 0 rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt8 TE-IS 10 rt8 - rt9(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + 10.0.255.8/32 IP TE 20 rt8 - rt8(4) + rt4 TE-IS 40 rt6 - rt6(4) + rt7 - rt7(4) + rt8 - rt8(4) + rt2 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt5 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + 10.0.255.4/32 IP TE 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt1 TE-IS 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 10.0.255.2/32 IP TE 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 10.0.255.5/32 IP TE 60 rt6 - rt5(4) + rt7 - rt5(4) + rt8 - rt5(4) + rt3 TE-IS 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 10.0.255.1/32 IP TE 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 10.0.255.3/32 IP TE 80 rt6 - rt3(4) + rt7 - rt3(4) + rt8 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4242,45 +4446,47 @@ Q-space: rt5 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt9 -2001:db8::9/128 IP6 internal 0 rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt8 TE-IS 10 rt8 - rt9(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) -2001:db8::8/128 IP6 internal 20 rt8 - rt8(4) -rt4 TE-IS 40 rt6 - rt6(4) - rt7 - rt7(4) - rt8 - rt8(4) -rt2 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -rt5 TE-IS 50 rt6 - rt4(4) - rt7 - - rt8 - -2001:db8::4/128 IP6 internal 50 rt6 - rt4(4) - rt7 - - rt8 - -rt1 TE-IS 60 rt6 - rt2(4) - rt7 - - rt8 - -2001:db8::2/128 IP6 internal 60 rt6 - rt2(4) - rt7 - - rt8 - -2001:db8::5/128 IP6 internal 60 rt6 - rt5(4) - rt7 - - rt8 - -rt3 TE-IS 70 rt6 - rt1(4) - rt7 - - rt8 - -2001:db8::1/128 IP6 internal 70 rt6 - rt1(4) - rt7 - - rt8 - -2001:db8::3/128 IP6 internal 80 rt6 - rt3(4) - rt7 - - rt8 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt9 + 2001:db8::9/128 IP6 internal 0 rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt8 TE-IS 10 rt8 - rt9(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) + 2001:db8::8/128 IP6 internal 20 rt8 - rt8(4) + rt4 TE-IS 40 rt6 - rt6(4) + rt7 - rt7(4) + rt8 - rt8(4) + rt2 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt5 TE-IS 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + 2001:db8::4/128 IP6 internal 50 rt6 - rt4(4) + rt7 - rt4(4) + rt8 - rt4(4) + rt1 TE-IS 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 2001:db8::2/128 IP6 internal 60 rt6 - rt2(4) + rt7 - rt2(4) + rt8 - rt2(4) + 2001:db8::5/128 IP6 internal 60 rt6 - rt5(4) + rt7 - rt5(4) + rt8 - rt5(4) + rt3 TE-IS 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 2001:db8::1/128 IP6 internal 70 rt6 - rt1(4) + rt7 - rt1(4) + rt8 - rt1(4) + 2001:db8::3/128 IP6 internal 80 rt6 - rt3(4) + rt7 - rt3(4) + rt8 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4329,25 +4535,27 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt9 -10.0.255.9/32 IP internal 0 rt9(4) -rt5 TE-IS 10 rt5 - rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt4 TE-IS 20 rt5 - rt5(4) -10.0.255.5/32 IP TE 20 rt5 - rt5(4) -10.0.255.6/32 IP TE 20 rt6 - rt6(4) -10.0.255.7/32 IP TE 20 rt7 - rt7(4) -rt2 TE-IS 30 rt5 - rt4(4) -10.0.255.4/32 IP TE 30 rt5 - rt4(4) -rt1 TE-IS 40 rt5 - rt2(4) -10.0.255.2/32 IP TE 40 rt5 - rt2(4) -rt8 TE-IS 50 rt5 - rt4(4) -rt3 TE-IS 50 rt5 - rt1(4) -10.0.255.1/32 IP TE 50 rt5 - rt1(4) -10.0.255.8/32 IP TE 60 rt5 - rt8(4) -10.0.255.3/32 IP TE 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt9 + 10.0.255.9/32 IP internal 0 rt9(4) + rt5 TE-IS 10 rt5 - rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt4 TE-IS 20 rt5 - rt5(4) + 10.0.255.5/32 IP TE 20 rt5 - rt5(4) + 10.0.255.6/32 IP TE 20 rt6 - rt6(4) + 10.0.255.7/32 IP TE 20 rt7 - rt7(4) + rt2 TE-IS 30 rt5 - rt4(4) + 10.0.255.4/32 IP TE 30 rt5 - rt4(4) + rt1 TE-IS 40 rt5 - rt2(4) + 10.0.255.2/32 IP TE 40 rt5 - rt2(4) + rt8 TE-IS 50 rt5 - rt4(4) + rt3 TE-IS 50 rt5 - rt1(4) + 10.0.255.1/32 IP TE 50 rt5 - rt1(4) + 10.0.255.8/32 IP TE 60 rt5 - rt8(4) + 10.0.255.3/32 IP TE 60 rt5 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4381,25 +4589,27 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt9 -2001:db8::9/128 IP6 internal 0 rt9(4) -rt5 TE-IS 10 rt5 - rt9(4) -rt6 TE-IS 10 rt6 - rt9(4) -rt7 TE-IS 10 rt7 - rt9(4) -rt4 TE-IS 20 rt5 - rt5(4) -2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) -2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) -2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) -rt2 TE-IS 30 rt5 - rt4(4) -2001:db8::4/128 IP6 internal 30 rt5 - rt4(4) -rt1 TE-IS 40 rt5 - rt2(4) -2001:db8::2/128 IP6 internal 40 rt5 - rt2(4) -rt8 TE-IS 50 rt5 - rt4(4) -rt3 TE-IS 50 rt5 - rt1(4) -2001:db8::1/128 IP6 internal 50 rt5 - rt1(4) -2001:db8::8/128 IP6 internal 60 rt5 - rt8(4) -2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt9 + 2001:db8::9/128 IP6 internal 0 rt9(4) + rt5 TE-IS 10 rt5 - rt9(4) + rt6 TE-IS 10 rt6 - rt9(4) + rt7 TE-IS 10 rt7 - rt9(4) + rt4 TE-IS 20 rt5 - rt5(4) + 2001:db8::5/128 IP6 internal 20 rt5 - rt5(4) + 2001:db8::6/128 IP6 internal 20 rt6 - rt6(4) + 2001:db8::7/128 IP6 internal 20 rt7 - rt7(4) + rt2 TE-IS 30 rt5 - rt4(4) + 2001:db8::4/128 IP6 internal 30 rt5 - rt4(4) + rt1 TE-IS 40 rt5 - rt2(4) + 2001:db8::2/128 IP6 internal 40 rt5 - rt2(4) + rt8 TE-IS 50 rt5 - rt4(4) + rt3 TE-IS 50 rt5 - rt1(4) + 2001:db8::1/128 IP6 internal 50 rt5 - rt1(4) + 2001:db8::8/128 IP6 internal 60 rt5 - rt8(4) + 2001:db8::3/128 IP6 internal 60 rt5 - rt3(4) + IS-IS L1 IPv6 routing table: @@ -4428,29 +4638,31 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.4/32 IP TE 30 rt4 - rt4(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.7/32 IP TE 40 rt4 - rt7(4) -rt8 TE-IS 80 rt3 - rt6(4) - rt4 - rt7(4) -rt5 TE-IS 90 rt3 - rt8(4) - rt4 - -10.0.255.8/32 IP TE 90 rt3 - rt8(4) - rt4 - -rt2 TE-IS 100 rt3 - rt5(4) - rt4 - -10.0.255.5/32 IP TE 100 rt3 - rt5(4) - rt4 - -10.0.255.2/32 IP TE 110 rt3 - rt2(4) - rt4 - + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.4/32 IP TE 30 rt4 - rt4(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.7/32 IP TE 40 rt4 - rt7(4) + rt8 TE-IS 80 rt3 - rt6(4) + rt4 - rt7(4) + rt5 TE-IS 90 rt3 - rt8(4) + rt4 - rt8(4) + 10.0.255.8/32 IP TE 90 rt3 - rt8(4) + rt4 - rt8(4) + rt2 TE-IS 100 rt3 - rt5(4) + rt4 - rt5(4) + 10.0.255.5/32 IP TE 100 rt3 - rt5(4) + rt4 - rt5(4) + 10.0.255.2/32 IP TE 110 rt3 - rt2(4) + rt4 - rt2(4) + IS-IS L1 IPv4 routing table: @@ -4483,29 +4695,31 @@ Q-space: rt8 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt4 TE-IS 20 rt4 - rt1(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt7 TE-IS 30 rt4 - rt4(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) -rt8 TE-IS 80 rt3 - rt6(4) - rt4 - rt7(4) -rt5 TE-IS 90 rt3 - rt8(4) - rt4 - -2001:db8::8/128 IP6 internal 90 rt3 - rt8(4) - rt4 - -rt2 TE-IS 100 rt3 - rt5(4) - rt4 - -2001:db8::5/128 IP6 internal 100 rt3 - rt5(4) - rt4 - -2001:db8::2/128 IP6 internal 110 rt3 - rt2(4) - rt4 - + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt4 TE-IS 20 rt4 - rt1(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt7 TE-IS 30 rt4 - rt4(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::4/128 IP6 internal 30 rt4 - rt4(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::7/128 IP6 internal 40 rt4 - rt7(4) + rt8 TE-IS 80 rt3 - rt6(4) + rt4 - rt7(4) + rt5 TE-IS 90 rt3 - rt8(4) + rt4 - rt8(4) + 2001:db8::8/128 IP6 internal 90 rt3 - rt8(4) + rt4 - rt8(4) + rt2 TE-IS 100 rt3 - rt5(4) + rt4 - rt5(4) + 2001:db8::5/128 IP6 internal 100 rt3 - rt5(4) + rt4 - rt5(4) + 2001:db8::2/128 IP6 internal 110 rt3 - rt2(4) + rt4 - rt2(4) + IS-IS L1 IPv6 routing table: @@ -4540,23 +4754,25 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt8 TE-IS 30 rt2 - rt5(4) -10.0.255.3/32 IP TE 30 rt3 - rt3(4) -10.0.255.5/32 IP TE 30 rt2 - rt5(4) -10.0.255.6/32 IP TE 40 rt3 - rt6(4) -10.0.255.8/32 IP TE 40 rt2 - rt8(4) -rt7 TE-IS 80 rt2 - rt8(4) -rt4 TE-IS 90 rt2 - rt7(4) -10.0.255.7/32 IP TE 90 rt2 - rt7(4) -10.0.255.4/32 IP TE 100 rt2 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt8 TE-IS 30 rt2 - rt5(4) + 10.0.255.3/32 IP TE 30 rt3 - rt3(4) + 10.0.255.5/32 IP TE 30 rt2 - rt5(4) + 10.0.255.6/32 IP TE 40 rt3 - rt6(4) + 10.0.255.8/32 IP TE 40 rt2 - rt8(4) + rt7 TE-IS 80 rt2 - rt8(4) + rt4 TE-IS 90 rt2 - rt7(4) + 10.0.255.7/32 IP TE 90 rt2 - rt7(4) + 10.0.255.4/32 IP TE 100 rt2 - rt4(4) + IS-IS L1 IPv4 routing table: @@ -4586,23 +4802,25 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt1 -2001:db8::1/128 IP6 internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt3 TE-IS 20 rt3 - rt1(4) -rt5 TE-IS 20 rt2 - rt2(4) -2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) -rt6 TE-IS 30 rt3 - rt3(4) -rt8 TE-IS 30 rt2 - rt5(4) -2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) -2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) -2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) -2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) -rt7 TE-IS 80 rt2 - rt8(4) -rt4 TE-IS 90 rt2 - rt7(4) -2001:db8::7/128 IP6 internal 90 rt2 - rt7(4) -2001:db8::4/128 IP6 internal 100 rt2 - rt4(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt1 + 2001:db8::1/128 IP6 internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt3 TE-IS 20 rt3 - rt1(4) + rt5 TE-IS 20 rt2 - rt2(4) + 2001:db8::2/128 IP6 internal 20 rt2 - rt2(4) + rt6 TE-IS 30 rt3 - rt3(4) + rt8 TE-IS 30 rt2 - rt5(4) + 2001:db8::3/128 IP6 internal 30 rt3 - rt3(4) + 2001:db8::5/128 IP6 internal 30 rt2 - rt5(4) + 2001:db8::6/128 IP6 internal 40 rt3 - rt6(4) + 2001:db8::8/128 IP6 internal 40 rt2 - rt8(4) + rt7 TE-IS 80 rt2 - rt8(4) + rt4 TE-IS 90 rt2 - rt7(4) + 2001:db8::7/128 IP6 internal 90 rt2 - rt7(4) + 2001:db8::4/128 IP6 internal 100 rt2 - rt4(4) + IS-IS L1 IPv6 routing table: @@ -4633,20 +4851,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt2 -10.0.255.2/32 IP internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -10.0.255.1/32 IP TE 60 rt1 - rt1(4) -10.0.255.3/32 IP TE 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -10.0.255.5/32 IP TE 70 rt3 - rt5(4) -10.0.255.4/32 IP TE 80 rt3 - rt4(4) -10.0.255.6/32 IP TE 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt2 + 10.0.255.2/32 IP internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 10.0.255.1/32 IP TE 60 rt1 - rt1(4) + 10.0.255.3/32 IP TE 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 10.0.255.5/32 IP TE 70 rt3 - rt5(4) + 10.0.255.4/32 IP TE 80 rt3 - rt4(4) + 10.0.255.6/32 IP TE 80 rt3 - rt6(4) + IS-IS L1 IPv4 routing table: @@ -4679,20 +4899,22 @@ Q-space: rt6 IS-IS paths to level-1 routers that speak IPv6 -Vertex Type Metric Next-Hop Interface Parent -rt2 -2001:db8::2/128 IP6 internal 0 rt2(4) -rt1 TE-IS 50 rt1 - rt2(4) -rt3 TE-IS 50 rt3 - rt2(4) -rt2 -rt5 TE-IS 60 rt3 - rt3(4) -2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) -2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) -rt4 TE-IS 70 rt3 - rt5(4) -rt6 TE-IS 70 rt3 - rt5(4) -2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) -2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) -2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + Vertex Type Metric Next-Hop Interface Parent + -------------------------------------------------------------------- + rt2 + 2001:db8::2/128 IP6 internal 0 rt2(4) + rt1 TE-IS 50 rt1 - rt2(4) + rt3 TE-IS 50 rt3 - rt2(4) + rt2 + rt5 TE-IS 60 rt3 - rt3(4) + 2001:db8::1/128 IP6 internal 60 rt1 - rt1(4) + 2001:db8::3/128 IP6 internal 60 rt3 - rt3(4) + rt4 TE-IS 70 rt3 - rt5(4) + rt6 TE-IS 70 rt3 - rt5(4) + 2001:db8::5/128 IP6 internal 70 rt3 - rt5(4) + 2001:db8::4/128 IP6 internal 80 rt3 - rt4(4) + 2001:db8::6/128 IP6 internal 80 rt3 - rt6(4) + IS-IS L1 IPv6 routing table: @@ -4723,27 +4945,29 @@ Q-space: rt3 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt6 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt8 TE-IS 40 rt2 - rt6(4) -10.0.255.6/32 IP TE 40 rt2 - rt6(4) -rt10 TE-IS 50 rt2 - rt8(4) -10.0.255.8/32 IP TE 50 rt2 - rt8(4) -10.0.255.10/32 IP TE 60 rt2 - rt10(4) -rt7 TE-IS 140 rt2 - rt8(4) -rt9 TE-IS 150 rt2 - rt7(4) -10.0.255.7/32 IP TE 150 rt2 - rt7(4) -10.0.255.9/32 IP TE 160 rt2 - rt9(4) -rt5 TE-IS 340 rt2 - rt7(4) -10.0.255.5/32 IP TE 350 rt2 - rt5(4) -rt3 TE-IS 740 rt2 - rt5(4) -10.0.255.3/32 IP TE 750 rt2 - rt3(4) + Vertex Type Metric Next-Hop Interface Parent + ------------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt6 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt8 TE-IS 40 rt2 - rt6(4) + 10.0.255.6/32 IP TE 40 rt2 - rt6(4) + rt10 TE-IS 50 rt2 - rt8(4) + 10.0.255.8/32 IP TE 50 rt2 - rt8(4) + 10.0.255.10/32 IP TE 60 rt2 - rt10(4) + rt7 TE-IS 140 rt2 - rt8(4) + rt9 TE-IS 150 rt2 - rt7(4) + 10.0.255.7/32 IP TE 150 rt2 - rt7(4) + 10.0.255.9/32 IP TE 160 rt2 - rt9(4) + rt5 TE-IS 340 rt2 - rt7(4) + 10.0.255.5/32 IP TE 350 rt2 - rt5(4) + rt3 TE-IS 740 rt2 - rt5(4) + 10.0.255.3/32 IP TE 750 rt2 - rt3(4) + IS-IS L1 IPv4 routing table: @@ -4770,22 +4994,24 @@ Q-space: rt7 IS-IS paths to level-1 routers that speak IP -Vertex Type Metric Next-Hop Interface Parent -rt1 -10.0.255.1/32 IP internal 0 rt1(4) -rt2 TE-IS 10 rt2 - rt1(4) -rt4 TE-IS 20 rt2 - rt2(4) -10.0.255.2/32 IP TE 20 rt2 - rt2(4) -rt3 TE-IS 30 rt2 - rt4(4) -10.0.255.4/32 IP TE 30 rt2 - rt4(4) -rt5 TE-IS 40 rt2 - rt3(4) -rt6 TE-IS 40 rt2 - rt3(4) -10.0.255.3/32 IP TE 40 rt2 - rt3(4) -rt7 TE-IS 50 rt2 - rt5(4) - rt6(4) -10.0.255.5/32 IP TE 50 rt2 - rt5(4) -10.0.255.6/32 IP TE 50 rt2 - rt6(4) -10.0.255.7/32 IP TE 60 rt2 - rt7(4) + Vertex Type Metric Next-Hop Interface Parent + ----------------------------------------------------------------- + rt1 + 10.0.255.1/32 IP internal 0 rt1(4) + rt2 TE-IS 10 rt2 - rt1(4) + rt4 TE-IS 20 rt2 - rt2(4) + 10.0.255.2/32 IP TE 20 rt2 - rt2(4) + rt3 TE-IS 30 rt2 - rt4(4) + 10.0.255.4/32 IP TE 30 rt2 - rt4(4) + rt5 TE-IS 40 rt2 - rt3(4) + rt6 TE-IS 40 rt2 - rt3(4) + 10.0.255.3/32 IP TE 40 rt2 - rt3(4) + rt7 TE-IS 50 rt2 - rt5(4) + rt6(4) + 10.0.255.5/32 IP TE 50 rt2 - rt5(4) + 10.0.255.6/32 IP TE 50 rt2 - rt6(4) + 10.0.255.7/32 IP TE 60 rt2 - rt7(4) + IS-IS L1 IPv4 routing table: @@ -4796,5 +5022,5 @@ IS-IS L1 IPv4 routing table: 10.0.255.6/32 50 - rt2 16040/16060 10.0.255.7/32 60 - rt2 16040/16070 -test# -end. +test# +end. diff --git a/tests/lib/subdir.am b/tests/lib/subdir.am index 185b895079..1a21684f16 100644 --- a/tests/lib/subdir.am +++ b/tests/lib/subdir.am @@ -100,7 +100,7 @@ check_PROGRAMS += tests/lib/cli/test_commands tests_lib_cli_test_commands_CFLAGS = $(TESTS_CFLAGS) tests_lib_cli_test_commands_CPPFLAGS = $(TESTS_CPPFLAGS) tests_lib_cli_test_commands_LDADD = $(ALL_TESTS_LDADD) -nodist_tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands_defun.c +nodist_tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands_defun.c $(vtysh_cmd_split) tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands.c tests/helpers/c/prng.c tests/lib/cli/test_commands_defun.c: vtysh/vtysh_cmd.c @$(MKDIR_P) tests/lib/cli diff --git a/tests/lib/test_atomlist.c b/tests/lib/test_atomlist.c index b50216cf92..afcfa98791 100644 --- a/tests/lib/test_atomlist.c +++ b/tests/lib/test_atomlist.c @@ -62,7 +62,7 @@ static struct asort_head shead; static struct testthread { pthread_t pt; struct seqlock sqlo; - size_t counter, nullops; + _Atomic size_t counter, nullops; } thr[NTHREADS]; struct testrun { @@ -97,10 +97,10 @@ static void trfunc_##name(unsigned int offset) \ { \ size_t i = 0, n = 0; -#define endtestrun \ - thr[offset].counter = i; \ - thr[offset].nullops = n; \ -} +#define endtestrun \ + atomic_store_explicit(&thr[offset].counter, i, memory_order_seq_cst); \ + atomic_store_explicit(&thr[offset].nullops, n, memory_order_seq_cst); \ + } deftestrun(add, "add vs. add", 0, false) for (; i < NITEM / NTHREADS; i++) @@ -288,10 +288,10 @@ static void run_tr(struct testrun *tr) sv = seqlock_bump(&sqlo) - SEQLOCK_INCR; for (size_t i = 0; i < NTHREADS; i++) { seqlock_wait(&thr[i].sqlo, seqlock_cur(&sqlo)); - s += thr[i].counter; - n += thr[i].nullops; - thr[i].counter = 0; - thr[i].nullops = 0; + s += atomic_load_explicit(&thr[i].counter, memory_order_seq_cst); + n += atomic_load_explicit(&thr[i].nullops, memory_order_seq_cst); + atomic_store_explicit(&thr[i].counter, 0, memory_order_seq_cst); + atomic_store_explicit(&thr[i].nullops, 0, memory_order_seq_cst); } delta = monotime_since(&tv, NULL); diff --git a/tests/lib/test_darr.c b/tests/lib/test_darr.c index 74aedac4b7..87f9e3e564 100644 --- a/tests/lib/test_darr.c +++ b/tests/lib/test_darr.c @@ -20,6 +20,8 @@ * [x] - darr_foreach_i * [x] - darr_foreach_p * [x] - darr_free + * [x] - darr_free_free + * [x] - darr_free_func * [x] - darr_insert * [ ] - darr_insertz * [x] - darr_insert_n @@ -318,6 +320,8 @@ static void test_string(void) uint addlen = strlen(add); char *da1 = NULL; char *da2 = NULL; + const char **strings = NULL; + uint sum = 0; assert(darr_strlen(da1) == 0); @@ -412,6 +416,29 @@ static void test_string(void) da1 = darr_in_strcatf(da1, "0123456789: %08x", 0xDEADBEEF); assert(!strcmp("0123456789: deadbeef", da1)); darr_free(da1); + + sum = 0; + *darr_append(strings) = "1"; + *darr_append(strings) = "2"; + *darr_append(strings) = "3"; +#define adder(x) (sum += atoi(x)) + darr_free_func(strings, adder); + assert(sum == 6); + assert(strings == NULL); + + sum = 0; + darr_free_func(strings, adder); + assert(sum == 0); + assert(strings == NULL); + + *darr_append(strings) = NULL; + *darr_append(strings) = darr_strdup("2"); + *darr_append(strings) = darr_strdup("3"); + darr_free_free(strings); + assert(strings == NULL); + + darr_free_free(strings); + assert(strings == NULL); } int main(int argc, char **argv) diff --git a/tests/lib/test_seqlock.c b/tests/lib/test_seqlock.c index 288d4a8c25..937b3f34f5 100644 --- a/tests/lib/test_seqlock.c +++ b/tests/lib/test_seqlock.c @@ -82,11 +82,11 @@ int main(int argc, char **argv) assert(seqlock_held(&sqlo)); assert(seqlock_cur(&sqlo) == 1); - assert(seqlock_bump(&sqlo) == 1); - assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 5); + assert(seqlock_cur(&sqlo) == 5); assert(seqlock_bump(&sqlo) == 9); assert(seqlock_bump(&sqlo) == 13); + assert(seqlock_bump(&sqlo) == 17); assert(seqlock_cur(&sqlo) == 17); assert(seqlock_held(&sqlo)); @@ -111,4 +111,5 @@ int main(int argc, char **argv) writestr("main @release\n"); seqlock_release(&sqlo); sleep(1); + pthread_join(thr1, NULL); } diff --git a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref index f52b51d9d8..e4e3290111 100644 --- a/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref +++ b/tests/topotests/all_protocol_startup/r1/show_ip_ospf_interface.ref @@ -11,6 +11,7 @@ r1-eth0 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 r1-eth3 is up ifindex X, MTU 1500 bytes, BW XX Mbit Internet Address 192.168.3.1/26, Broadcast 192.168.3.63, Area 0.0.0.0 @@ -24,3 +25,4 @@ r1-eth3 is up Hello due in XX.XXXs Neighbor Count is 0, Adjacent neighbor count is 0 Graceful Restart hello delay: 10s + LSA retransmissions: 0 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 b4bc1e14ad..80bd2505a7 100644 --- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py +++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py @@ -38,9 +38,10 @@ required_linux_kernel_version, ) -from lib.topolog import logger import json +import functools +# Global that must be set on a failure to stop subsequent tests from being run fatal_error = "" @@ -153,7 +154,6 @@ def test_error_messages_vtysh(): print("\n\n** Check for error messages on VTYSH") print("******************************************\n") - failures = 0 for i in range(1, 2): # # First checking Standard Output @@ -402,17 +402,27 @@ def test_converge_protocols(): def route_get_nhg_id(route_str): - net = get_topogen().net - output = net["r1"].cmd( - 'vtysh -c "show ip route {} nexthop-group"'.format(route_str) - ) - match = re.search(r"Nexthop Group ID: (\d+)", output) - assert match is not None, "Nexthop Group ID not found for sharpd route {}".format( - route_str - ) + global fatal_error + + def get_func(route_str): + net = get_topogen().net + output = net["r1"].cmd( + 'vtysh -c "show ip route {} nexthop-group"'.format(route_str) + ) + match = re.search(r"Nexthop Group ID: (\d+)", output) + if match is not None: + nhg_id = int(match.group(1)) + return nhg_id + else: + return None - nhg_id = int(match.group(1)) - return nhg_id + test_func = functools.partial(get_func, route_str) + _, nhg_id = topotest.run_and_expect_type(test_func, int, count=30, wait=1) + if nhg_id == None: + fatal_error = "Nexthop Group ID not found for route {}".format(route_str) + assert nhg_id != None, fatal_error + else: + return nhg_id def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): @@ -489,8 +499,12 @@ def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): def verify_route_nexthop_group(route_str, recursive=False, ecmp=0): + global fatal_error + # Verify route and that zebra created NHGs for and they are valid/installed + nhg_id = route_get_nhg_id(route_str) + verify_nexthop_group(nhg_id, recursive, ecmp) @@ -1650,8 +1664,13 @@ def test_mpls_interfaces(): def test_resilient_nexthop_group(): + global fatal_error net = get_topogen().net + # Skip if previous fatal error condition is raised + if fatal_error != "": + pytest.skip(fatal_error) + result = required_linux_kernel_version("5.19") if result is not True: pytest.skip("Kernel requirements are not met, kernel version should be >= 5.19") @@ -1660,8 +1679,18 @@ def test_resilient_nexthop_group(): 'vtysh -c "conf" -c "nexthop-group resilience" -c "resilient buckets 64 idle-timer 128 unbalanced-timer 256" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"' ) - output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"') - buckets = re.findall(r"Buckets", output) + # Temporary helper function + def _show_func(): + output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp"') + buckets = re.findall(r"Buckets", output) + + return len(buckets) + + _, result = topotest.run_and_expect(_show_func, 1, count=30, wait=1) + if result != 1: + fatal_error = "Resilient NHG not created in zebra" + + assert result == 1, fatal_error output = net["r1"].cmd('vtysh -c "show nexthop-group rib sharp json"') @@ -1674,8 +1703,14 @@ def test_resilient_nexthop_group(): if "buckets" in n: break + if "buckets" not in n: + fatal_error = "Resilient NHG not found in json output" + assert "buckets" in n, fatal_error + verify_nexthop_group(int(nhgid)) - assert len(buckets) == 1, "Resilient NHG not created in zebra" + + # Remove NHG + net["r1"].cmd('vtysh -c "conf" -c "no nexthop-group resilience"') def test_shutdown_check_stderr(): diff --git a/tests/topotests/babel_topo1/test_babel_topo1.py b/tests/topotests/babel_topo1/test_babel_topo1.py index decf0c2a6f..13bbe5bd4e 100644 --- a/tests/topotests/babel_topo1/test_babel_topo1.py +++ b/tests/topotests/babel_topo1/test_babel_topo1.py @@ -15,7 +15,6 @@ """ import os -import re import sys import pytest import json @@ -130,7 +129,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: assertmsg = "Zebra IPv4 Routing Table verification failed for router {}".format( diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf index f8ad1f3a66..054b12832a 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf @@ -7,6 +7,7 @@ router bgp 101 bgp graceful-restart neighbor 2001:db8:4::1 remote-as 102 neighbor 2001:db8:4::1 timers 3 10 + neighbor 2001:db8:4::1 timers connect 1 neighbor 2001:db8:4::1 remote-as external neighbor 2001:db8:4::1 bfd neighbor 2001:db8:4::1 bfd check-control-plane-failure diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf index 42953a075c..d7e10210f3 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf @@ -11,6 +11,7 @@ router bgp 102 bgp graceful-restart restart-time 900 neighbor 2001:db8:1::1 remote-as 101 neighbor 2001:db8:1::1 timers 3 10 + neighbor 2001:db8:1::1 timers connect 1 neighbor 2001:db8:1::1 remote-as external neighbor 2001:db8:1::1 update-source 2001:db8:4::1 neighbor 2001:db8:1::1 bfd diff --git a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py index b9e8b73c1d..6919371ac5 100755 --- a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py +++ b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py @@ -59,7 +59,6 @@ import sys import pytest import json -from time import sleep from functools import partial # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bfd_topo3/test_bfd_topo3.py b/tests/topotests/bfd_topo3/test_bfd_topo3.py index d7b2542f9f..a899a2b464 100644 --- a/tests/topotests/bfd_topo3/test_bfd_topo3.py +++ b/tests/topotests/bfd_topo3/test_bfd_topo3.py @@ -95,7 +95,7 @@ def expect_route_missing(router, iptype, route): "show {} route json".format(iptype), {route: None}, ) - rv, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assertmsg = '"{}" convergence failure'.format(router) assert result is None, assertmsg diff --git a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py index 9e5a68f0a3..f6adff61d0 100644 --- a/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py +++ b/tests/topotests/bfd_vrf_topo1/test_bfd_vrf_topo1.py @@ -61,7 +61,7 @@ def setup_module(mod): router_list = tgen.routers() # check for zebra capability - for rname, router in router_list.items(): + for _, router in router_list.items(): if router.check_capability(TopoRouter.RD_ZEBRA, "--vrfwnetns") == False: return pytest.skip( "Skipping BFD Topo1 VRF NETNS feature. VRF NETNS backend not available on FRR" diff --git a/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py b/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py index cbed8f0896..477cfa206b 100644 --- a/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py +++ b/tests/topotests/bgp_6vpe_ebgp_topo1/test_bgp_6vpe_ebgp_topo1.py @@ -12,7 +12,6 @@ import os import sys import json -import functools from functools import partial import pytest diff --git a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py index d294da0934..11b24baa82 100644 --- a/tests/topotests/bgp_accept_own/test_bgp_accept_own.py +++ b/tests/topotests/bgp_accept_own/test_bgp_accept_own.py @@ -68,7 +68,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py index 2a610c901e..3d17a2b709 100644 --- a/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py +++ b/tests/topotests/bgp_addpath_best_selected/test_bgp_addpath_best_selected.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py index b7a1cfbb27..fb863e454f 100644 --- a/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py +++ b/tests/topotests/bgp_addpath_paths_limit/test_bgp_addpath_paths_limit.py @@ -20,7 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py index 5a4a5fb657..0520b5e136 100644 --- a/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py +++ b/tests/topotests/bgp_aggregate_address_matching_med/test_bgp_aggregate_address_matching_med.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py b/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py index 739685d417..188bbd0b98 100644 --- a/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py +++ b/tests/topotests/bgp_aggregate_address_origin/test_bgp_aggregate-address_origin.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -89,12 +89,12 @@ def _bgp_aggregate_address_has_metric(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_aggregate_address_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py index eeac7146b1..2343440aaf 100644 --- a/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py +++ b/tests/topotests/bgp_aggregate_address_route_map/test_bgp_aggregate-address_route-map.py @@ -52,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py b/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py index d9ef3e1ce1..1a52f8c90e 100644 --- a/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py +++ b/tests/topotests/bgp_aggregator_zero/test_bgp_aggregator_zero.py @@ -73,7 +73,7 @@ def _bgp_converge(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r1"]) @@ -99,7 +99,7 @@ def _bgp_has_correct_aggregator_route_with_good_asn(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_has_correct_aggregator_route_with_good_asn) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Aggregator AS attribute not found in "{}"'.format( tgen.gears["r1"] diff --git a/tests/topotests/bgp_aigp/test_bgp_aigp.py b/tests/topotests/bgp_aigp/test_bgp_aigp.py index 655e9ad184..b81c543297 100644 --- a/tests/topotests/bgp_aigp/test_bgp_aigp.py +++ b/tests/topotests/bgp_aigp/test_bgp_aigp.py @@ -29,7 +29,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] @@ -73,7 +72,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py index c49a2e5384..537ccc9df6 100644 --- a/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py +++ b/tests/topotests/bgp_as_allow_in/test_bgp_as_allow_in.py @@ -28,7 +28,6 @@ import os import sys import time -import json import pytest # Save the Current Working Directory to find configuration files. @@ -59,7 +58,7 @@ create_router_bgp, verify_bgp_rib, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_as_override/test_bgp_as_override.py b/tests/topotests/bgp_as_override/test_bgp_as_override.py index 7cb4f81cfc..dbbdf2c88f 100644 --- a/tests/topotests/bgp_as_override/test_bgp_as_override.py +++ b/tests/topotests/bgp_as_override/test_bgp_as_override.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py index 5c09a6b0e0..e8e3b4171a 100644 --- a/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py +++ b/tests/topotests/bgp_as_wide_bgp_identifier/test_bgp_as_wide_bgp_identifier.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -85,12 +85,12 @@ def _bgp_failed(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, tgen.gears["r1"]) - success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Failed to converge: "{}"'.format(tgen.gears["r1"]) test_func = functools.partial(_bgp_failed, tgen.gears["r3"]) - success, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=260, wait=0.5) assert result is None, 'Bad BGP Identifier notification not sent: "{}"'.format( tgen.gears["r3"] diff --git a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py index 4883e847c9..09803dfa84 100644 --- a/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py +++ b/tests/topotests/bgp_asdot_regex/test_bgp_asdot_regex.py @@ -60,7 +60,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -97,7 +97,7 @@ def _bgp_converge(router): logger.info("Check if neighbor sessions are up in {}".format(router1.name)) test_func = partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) logger.info("BGP neighbor session is up in {}".format(router1.name)) diff --git a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py index 0f1a08308f..fe89a87621 100644 --- a/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py +++ b/tests/topotests/bgp_aspath_zero/test_bgp_aspath_zero.py @@ -73,7 +73,7 @@ def _bgp_converge(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "More than one prefix seen at r1, SHOULD be only one." def _bgp_has_correct_routes_without_asn_0(): @@ -82,7 +82,7 @@ def _bgp_has_correct_routes_without_asn_0(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_has_correct_routes_without_asn_0) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed listing 192.168.100.101/32, SHOULD be accepted." diff --git a/tests/topotests/bgp_auth/bgp_auth_common.py b/tests/topotests/bgp_auth/bgp_auth_common.py index 824498ef90..7ba3169caf 100644 --- a/tests/topotests/bgp_auth/bgp_auth_common.py +++ b/tests/topotests/bgp_auth/bgp_auth_common.py @@ -34,16 +34,9 @@ import json import os -import platform -import sys -from time import sleep - -from lib import common_config, topotest -from lib.common_config import ( - save_initial_config_on_routers, - reset_with_new_configs, -) -from lib.topogen import Topogen, TopoRouter, get_topogen + +from lib import common_config +from lib.topogen import get_topogen CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp_auth/test_bgp_auth1.py b/tests/topotests/bgp_auth/test_bgp_auth1.py index 9d47106c07..b0389474d4 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth1.py +++ b/tests/topotests/bgp_auth/test_bgp_auth1.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -156,7 +154,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth2.py b/tests/topotests/bgp_auth/test_bgp_auth2.py index 6b92036727..2b8f4673ea 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth2.py +++ b/tests/topotests/bgp_auth/test_bgp_auth2.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -156,7 +154,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth3.py b/tests/topotests/bgp_auth/test_bgp_auth3.py index 2237c6b1b6..d103d8075d 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth3.py +++ b/tests/topotests/bgp_auth/test_bgp_auth3.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -155,7 +153,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_auth/test_bgp_auth4.py b/tests/topotests/bgp_auth/test_bgp_auth4.py index d6fe42504b..792aa80d50 100644 --- a/tests/topotests/bgp_auth/test_bgp_auth4.py +++ b/tests/topotests/bgp_auth/test_bgp_auth4.py @@ -32,14 +32,12 @@ """ # pylint: disable=C0413 -import json import os import platform import sys -from time import sleep import pytest -from lib import common_config, topotest +from lib import topotest from lib.common_config import ( save_initial_config_on_routers, reset_with_new_configs, @@ -155,7 +153,7 @@ def setup_module(mod): router_list = tgen.routers() # For all registered routers, load the zebra configuration file - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_OSPF, "") router.load_config(TopoRouter.RD_BGP, "") diff --git a/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf index 0ae384eb53..1033b27c56 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf +++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bfdd.conf @@ -1,5 +1,9 @@ bfd + profile r1 + exit + ! peer 192.168.255.2 interface r1-eth0 + profile r1 exit ! exit diff --git a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf index e855f75c20..58a90d1a49 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf +++ b/tests/topotests/bgp_bfd_down_cease_notification/r1/bgpd.conf @@ -3,7 +3,7 @@ router bgp 65001 neighbor 192.168.255.2 remote-as external neighbor 192.168.255.2 timers 3 10 neighbor 192.168.255.2 timers connect 1 - neighbor 192.168.255.2 bfd + neighbor 192.168.255.2 bfd profile r1 neighbor 192.168.255.2 passive address-family ipv4 redistribute connected diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py index 00142981c5..f18e8bd388 100644 --- a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py +++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -89,6 +89,9 @@ def _bgp_bfd_down_notification(): "192.168.255.1": { "lastNotificationReason": "Cease/BFD Down", "lastNotificationHardReset": True, + "peerBfdInfo": { + "status": "Up", + }, } } return topotest.json_cmp(output, expected) diff --git a/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py new file mode 100644 index 0000000000..5ffeed5033 --- /dev/null +++ b/tests/topotests/bgp_bfd_down_cease_notification/test_bgp_bfd_down_cease_notification_shutdown.py @@ -0,0 +1,122 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# bgp_bfd_down_cease_notification_shutdown.py +# +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Check if Cease/BFD Down notification message is sent/received +when the BFD is down (administratively). +""" + +import os +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import kill_router_daemons, step + +pytestmark = [pytest.mark.bfdd, pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 3): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + +def setup_module(mod): + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.items(), 1): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_BFD, os.path.join(CWD, "{}/bfdd.conf".format(rname)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_bfd_down_notification_shutdown(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "bgpState": "Established", + "addressFamilyInfo": {"ipv4Unicast": {"acceptedPrefixCounter": 2}}, + "peerBfdInfo": {"status": "Up"}, + } + } + return topotest.json_cmp(output, expected) + + def _bgp_bfd_down_notification(): + output = json.loads(r2.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + "192.168.255.1": { + "lastNotificationReason": "Cease/BFD Down", + "lastNotificationHardReset": True, + "peerBfdInfo": { + "status": "Down", + }, + } + } + return topotest.json_cmp(output, expected) + + step("Initial BGP converge") + test_func = functools.partial(_bgp_converge) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see BGP convergence on R2" + + r1.vtysh_cmd( + """ + configure + bfd + profile r1 + shutdown + """ + ) + + step("Check if we received Cease/BFD Down notification message") + test_func = functools.partial(_bgp_bfd_down_notification) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Failed to see BGP Cease/BFD Down notification message on R2" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py index 9f5c0ef924..05a9a1e7f6 100644 --- a/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py +++ b/tests/topotests/bgp_blackhole_community/test_bgp_blackhole_community.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -125,14 +125,14 @@ def _bgp_verify_nexthop_validity(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"]) step("Check if 172.16.255.254/32 is not advertised to eBGP peers") test_func = functools.partial(_bgp_no_advertise_ebgp) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None @@ -142,7 +142,7 @@ def _bgp_verify_nexthop_validity(): step("Check if 172.16.255.254/32 is advertised to iBGP peers") test_func = functools.partial(_bgp_no_advertise_ibgp) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None @@ -152,7 +152,7 @@ def _bgp_verify_nexthop_validity(): step("Verify if the nexthop set via route-map on r4 is marked valid") test_func = functools.partial(_bgp_verify_nexthop_validity) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Nexthops are not valid "{}"'.format(tgen.gears["r4"]) diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp.py b/tests/topotests/bgp_bmp/test_bgp_bmp.py index 02de805068..80e291b2bd 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp.py @@ -26,7 +26,6 @@ from ipaddress import ip_network import json import os -import platform import pytest import sys diff --git a/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py b/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py index e0c1b4953e..09091198a8 100644 --- a/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py +++ b/tests/topotests/bgp_color_extcommunities/test_bgp_color_extcommunities.py @@ -16,7 +16,6 @@ import sys import json import functools -from functools import partial import pytest # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py index efc8f200a3..2064dac6e6 100644 --- a/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py +++ b/tests/topotests/bgp_comm_list_delete/test_bgp_comm-list_delete.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py index de69ea9387..d0cab26e1a 100644 --- a/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py +++ b/tests/topotests/bgp_comm_list_match/test_bgp_comm_list_match.py @@ -56,7 +56,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py index 324f53f3a6..82a67a0b84 100644 --- a/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py +++ b/tests/topotests/bgp_communities_topo1/test_bgp_communities_topo2.py @@ -171,7 +171,6 @@ def test_bgp_no_export_local_as_communities_p0(request): ) for comm_type in ["no-export", "local-AS"]: - step("Create a route-map on R1 to set community as {}".format(comm_type)) seq_id = 10 diff --git a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py index fdae9a3aa7..9df73a51ba 100644 --- a/tests/topotests/bgp_community_alias/test_bgp-community-alias.py +++ b/tests/topotests/bgp_community_alias/test_bgp-community-alias.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -92,7 +92,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP community aliases at r1" def _bgp_show_prefixes_by_alias(router): @@ -118,7 +118,7 @@ def _bgp_show_prefixes_by_alias(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_show_prefixes_by_alias, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP prefixes by community alias at r1" def _bgp_show_prefixes_by_large_community_list(router): @@ -129,7 +129,7 @@ def _bgp_show_prefixes_by_large_community_list(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_show_prefixes_by_large_community_list, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Cannot see BGP prefixes by large community list at r1" diff --git a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py index 5ad15e0645..c0a92efba9 100644 --- a/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py +++ b/tests/topotests/bgp_community_change_update/test_bgp_community_change_update.py @@ -97,7 +97,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -133,7 +133,7 @@ def _bgp_converge_initial(): step("Check if an initial topology is converged") test_func = functools.partial(_bgp_converge_initial) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in c1" step("Disable link between y1 and y2") @@ -146,7 +146,7 @@ def _bgp_converge_link_disabled(): step("Check if a topology is converged after a link down between y1 and y2") test_func = functools.partial(_bgp_converge_link_disabled) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in y1" def _bgp_check_for_duplicate_updates(): @@ -193,7 +193,7 @@ def _bgp_converge_link_enabled(): step("Check if a topology is converged after a link up between y1 and y2") test_func = functools.partial(_bgp_converge_link_enabled) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see bgp convergence in y1" step( diff --git a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py index 0128c88349..577bf9fd76 100644 --- a/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py +++ b/tests/topotests/bgp_conditional_advertisement/test_bgp_conditional_advertisement.py @@ -159,7 +159,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -426,7 +426,7 @@ def test_bgp_conditional_advertisement_tc_2_1(): ) test_func = functools.partial(exist_map_routes_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC21: exist-map routes present in "router2" BGP table - ' assert result is None, msg + failed @@ -455,7 +455,7 @@ def test_bgp_conditional_advertisement_tc_2_2(): ) test_func = functools.partial(exist_map_routes_not_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC22: exist-map routes not present in "router2" BGP table - ' assert result is None, msg + failed @@ -484,7 +484,7 @@ def test_bgp_conditional_advertisement_tc_2_3(): ) test_func = functools.partial(default_route_withdrawn, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC23: advertise-map with exist-map configuration is removed from peer - " assert result is None, msg + failed @@ -513,7 +513,7 @@ def test_bgp_conditional_advertisement_tc_3_1(): ) test_func = functools.partial(non_exist_map_routes_not_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC31: non-exist-map routes not present in "router2" BGP table - ' assert result is None, msg + failed @@ -542,7 +542,7 @@ def test_bgp_conditional_advertisement_tc_3_2(): ) test_func = functools.partial(non_exist_map_routes_present, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC32: non-exist-map routes present in "router2" BGP table - ' assert result is None, msg + failed @@ -571,7 +571,7 @@ def test_bgp_conditional_advertisement_tc_3_3(): ) test_func = functools.partial(all_routes_advertised, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = ( "TC33: advertise-map with non-exist-map configuration is removed from a peer - " @@ -603,7 +603,7 @@ def test_bgp_conditional_advertisement_tc_4_1(): ) test_func = functools.partial(non_exist_map_no_condition_route_map, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC41: non-exist-map route-map removed in "router2" - ' assert result is None, msg + failed @@ -632,7 +632,7 @@ def test_bgp_conditional_advertisement_tc_4_2(): ) test_func = functools.partial(exist_map_no_condition_route_map, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = 'TC42: exist-map route-map removed in "router2" - ' assert result is None, msg + failed @@ -665,7 +665,7 @@ def test_bgp_conditional_advertisement_tc_5_1(): ) test_func = functools.partial(exist_map_routes_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC51: exist-map routes present with route-map filter - " assert result is None, msg + failed @@ -694,7 +694,7 @@ def test_bgp_conditional_advertisement_tc_5_2(): ) test_func = functools.partial(exist_map_routes_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC52: exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -724,7 +724,7 @@ def test_bgp_conditional_advertisement_tc_5_3(): ) test_func = functools.partial(non_exist_map_routes_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC53: non-exist-map routes present, with route-map filter - " assert result is None, msg + failed @@ -753,7 +753,7 @@ def test_bgp_conditional_advertisement_tc_5_4(): ) test_func = functools.partial(non_exist_map_routes_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC54: non-exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -791,7 +791,7 @@ def test_bgp_conditional_advertisement_tc_6_1(): ) test_func = functools.partial(exist_map_routes_not_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC61: exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -820,7 +820,7 @@ def test_bgp_conditional_advertisement_tc_6_2(): ) test_func = functools.partial(exist_map_routes_not_present_no_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC62: exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -850,7 +850,7 @@ def test_bgp_conditional_advertisement_tc_6_3(): ) test_func = functools.partial(non_exist_map_routes_not_present_rmap_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC63: non-exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -881,7 +881,7 @@ def test_bgp_conditional_advertisement_tc_6_4(): test_func = functools.partial( non_exist_map_routes_not_present_no_rmap_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC64: non-exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -919,7 +919,7 @@ def test_bgp_conditional_advertisement_tc_7_1(): ) test_func = functools.partial(exist_map_routes_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC71: exist-map routes present, route-map filter - " assert result is None, msg + failed @@ -948,7 +948,7 @@ def test_bgp_conditional_advertisement_tc_7_2(): ) test_func = functools.partial(exist_map_routes_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC72: exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -978,7 +978,7 @@ def test_bgp_conditional_advertisement_tc_7_3(): ) test_func = functools.partial(non_exist_map_routes_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC73: non-exist-map routes present, route-map filter - " assert result is None, msg + failed @@ -1007,7 +1007,7 @@ def test_bgp_conditional_advertisement_tc_7_4(): ) test_func = functools.partial(non_exist_map_routes_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC74: non-exist-map routes present, no route-map filter - " assert result is None, msg + failed @@ -1045,7 +1045,7 @@ def test_bgp_conditional_advertisement_tc_8_1(): ) test_func = functools.partial(exist_map_routes_not_present_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC81: exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -1074,7 +1074,7 @@ def test_bgp_conditional_advertisement_tc_8_2(): ) test_func = functools.partial(exist_map_routes_not_present_no_rmap2_filter, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC82: exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -1106,7 +1106,7 @@ def test_bgp_conditional_advertisement_tc_8_3(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC83: non-exist-map routes not present, route-map filter - " assert result is None, msg + failed @@ -1137,7 +1137,7 @@ def test_bgp_conditional_advertisement_tc_8_4(): test_func = functools.partial( non_exist_map_routes_not_present_no_rmap2_filter, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC84: non-exist-map routes not present, no route-map filter - " assert result is None, msg + failed @@ -1175,7 +1175,7 @@ def test_bgp_conditional_advertisement_tc_9_1(): ) test_func = functools.partial(exist_map_routes_present_rmap2_network, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC91: exist-map routes present, route-map filter and network - " assert result is None, msg + failed @@ -1204,7 +1204,7 @@ def test_bgp_conditional_advertisement_tc_9_2(): ) test_func = functools.partial(exist_map_routes_present_rmap2_no_network, router3) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC92: exist-map routes present, route-map filter and no network - " assert result is None, msg + failed @@ -1244,7 +1244,7 @@ def test_bgp_conditional_advertisement_tc_9_3(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_network, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC93: non-exist-map routes not present, route-map filter and network - " assert result is None, msg + failed @@ -1275,7 +1275,7 @@ def test_bgp_conditional_advertisement_tc_9_4(): test_func = functools.partial( non_exist_map_routes_not_present_rmap2_no_network, router3 ) - success, result = topotest.run_and_expect(test_func, None, count=90, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=90, wait=1) msg = "TC94: non-exist-map routes not present, route-map filter and no network - " assert result is None, msg + failed diff --git a/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py index e9114bdbab..ea0f53cc97 100644 --- a/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py +++ b/tests/topotests/bgp_conditional_advertisement_static_route/test_bgp_conditional_advertisement_static_route.py @@ -11,7 +11,6 @@ """ import os -import re import sys import json import pytest @@ -24,7 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py index e76307291e..bb98e2fad0 100644 --- a/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py +++ b/tests/topotests/bgp_conditional_advertisement_track_peer/test_bgp_conditional_advertisement_track_peer.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py index 7bc0050109..44b1a2f704 100644 --- a/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py +++ b/tests/topotests/bgp_confederation_astype/test_bgp_confederation_astype.py @@ -35,7 +35,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py b/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py index 2066d848d3..f8916e1c4d 100644 --- a/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py +++ b/tests/topotests/bgp_dampening_per_peer/test_bgp_dampening_per_peer.py @@ -6,7 +6,6 @@ # import os -import re import sys import json import pytest diff --git a/tests/topotests/bgp_dampening_per_safi/__init__.py b/tests/topotests/bgp_dampening_per_safi/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_dampening_per_safi/r1/frr.conf b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf new file mode 100644 index 0000000000..b4e82f581d --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/r1/frr.conf @@ -0,0 +1,13 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + address-family ipv4 unicast + bgp dampening 1 1 1 1 + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_safi/r2/frr.conf b/tests/topotests/bgp_dampening_per_safi/r2/frr.conf new file mode 100644 index 0000000000..d68d13d075 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/r2/frr.conf @@ -0,0 +1,17 @@ +! +int lo + ip address 10.10.10.10/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 + ! + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py new file mode 100644 index 0000000000..c8d7e675d1 --- /dev/null +++ b/tests/topotests/bgp_dampening_per_safi/test_bgp_dampening_per_safi.py @@ -0,0 +1,194 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_dampening_per_peer(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _show_dampening_parameters(): + output = json.loads(r1.vtysh_cmd("show ip bgp dampening parameters json")) + expected = { + "halfLifeSecs": 60, + "reusePenalty": 1, + "suppressPenalty": 1, + "maxSuppressTimeSecs": 60, + "maxSuppressPenalty": 2, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _show_dampening_parameters, + ) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=1) + assert result is None, "Can't show BGP per-safi dampening parameters" + + def _converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + #### + # Withdraw 10.10.10.10/32, and check if it's flagged as history. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + no redistribute connected + """ + ) + + def _check_bgp_dampening_history(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "dampeningHistoryEntry": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_history, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as history entry" + + #### + # Reannounce 10.10.10.10/32, and check if it's flagged as dampened. + #### + r2.vtysh_cmd( + """ + configure terminal + router bgp + address-family ipv4 unicast + redistribute connected + """ + ) + + def _check_bgp_dampening_dampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningSuppressed": True, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_dampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "10.10.10.10/32 is not flagged as dampened entry" + + #### + # Check if the route becomes non-dampened again after some time. + #### + def _check_bgp_dampening_undampened(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast 10.10.10.10/32 json")) + expected = { + "paths": [ + { + "valid": True, + "dampeningHistoryEntry": None, + "dampeningSuppressed": None, + "nexthops": [ + { + "hostname": "r2", + "accessible": True, + } + ], + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _check_bgp_dampening_undampened, + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=10) + assert result is None, "10.10.10.10/32 is flagged as history/dampened" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py index 05e07486ae..48dddb4648 100644 --- a/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py +++ b/tests/topotests/bgp_default_afi_safi/test_bgp-default-afi-safi.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py index 75e66566b7..f4f874f942 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_2links.py @@ -17,7 +17,6 @@ import time import pytest import datetime -from copy import deepcopy from lib.topolog import logger from time import sleep @@ -214,7 +213,6 @@ def get_rib_route_uptime(tgen, addr_type, dut, input_dict): logger.info("Entering lib API: get_rib_route_uptime()") route_time = [] - out_route_dict = {} router_list = tgen.routers() for routerInput in input_dict.keys(): for router, rnode in router_list.items(): @@ -234,7 +232,6 @@ def get_rib_route_uptime(tgen, addr_type, dut, input_dict): for static_route in static_routes: if "vrf" in static_route and static_route["vrf"] is not None: - logger.info( "[DUT: {}]: Verifying routes for VRF:" " {}".format(router, static_route["vrf"]) @@ -307,7 +304,6 @@ def get_best_path_route_in_FIB(tgen, topo, dut, network): on failure : return error message with boolean False """ is_ipv4_best_path_found = False - is_ipv6_best_path_found = False rnode = tgen.routers()[dut] ipv4_show_bgp_json = run_frr_cmd(rnode, "sh ip bgp json ", isjson=True) ipv6_show_bgp_json = run_frr_cmd( @@ -1575,7 +1571,7 @@ def ping_router(): ipv_dict = get_best_path_route_in_FIB(tgen, topo, dut="r2", network=network) dut_links = topo["routers"]["r1"]["links"] active_interface = None - for key, values in dut_links.items(): + for key, _ in dut_links.items(): ipv4_address = dut_links[key]["ipv4"].split("/")[0] ipv6_address = dut_links[key]["ipv6"].split("/")[0] if ipv_dict["ipv4"] == ipv4_address and ipv_dict["ipv6"] == ipv6_address: diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py index 50a1938ae3..142b3e430f 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_1.py @@ -18,8 +18,6 @@ import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -30,32 +28,18 @@ from lib.bgp import ( verify_bgp_convergence, - verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, get_prefix_count_route, get_dut_as_number, verify_rib_default_route, - verify_fib_default_route, - verify_bgp_advertised_routes_from_neighbor, - verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_fib_routes, - kill_router_daemons, - start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, diff --git a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py index 4e8bda55cf..a6918916df 100644 --- a/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py +++ b/tests/topotests/bgp_default_originate/test_bgp_default_originate_topo1_2.py @@ -17,8 +17,6 @@ import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -31,13 +29,8 @@ verify_bgp_convergence, verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, - get_prefix_count_route, get_dut_as_number, verify_rib_default_route, verify_fib_default_route, @@ -45,16 +38,12 @@ verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_fib_routes, kill_router_daemons, start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, @@ -65,7 +54,6 @@ reset_config_on_routers, create_static_routes, check_router_status, - delete_route_maps, ) diff --git a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py index 4dedac5535..1506b02e5d 100644 --- a/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py +++ b/tests/topotests/bgp_default_originate/test_default_orginate_vrf.py @@ -10,8 +10,6 @@ import sys import time import pytest -from time import sleep -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 @@ -22,32 +20,17 @@ from lib.bgp import ( verify_bgp_convergence, - verify_graceful_restart, create_router_bgp, - verify_router_id, modify_as_number, - verify_as_numbers, - clear_bgp_and_verify, - clear_bgp, verify_bgp_rib, get_prefix_count_route, get_dut_as_number, - verify_rib_default_route, - verify_fib_default_route, - verify_bgp_advertised_routes_from_neighbor, - verify_bgp_received_routes_from_neighbor, ) from lib.common_config import ( - interface_status, verify_prefix_lists, verify_rib, - kill_router_daemons, - start_router_daemons, - shutdown_bringup_interface, step, required_linux_kernel_version, - stop_router, - start_router, create_route_maps, create_prefix_lists, get_frr_ipv6_linklocal, @@ -58,7 +41,6 @@ reset_config_on_routers, create_static_routes, check_router_status, - delete_route_maps, ) pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py index f67a431c7e..97a7e62e7c 100644 --- a/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py +++ b/tests/topotests/bgp_default_originate/test_default_originate_conditional_routemap.py @@ -19,7 +19,6 @@ import sys import time import pytest -from copy import deepcopy from lib.topolog import logger # pylint: disable=C0413 diff --git a/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py b/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py index b2ba936fb1..c7c40c1bfb 100644 --- a/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py +++ b/tests/topotests/bgp_default_originate_timer/test_bgp_default_originate_timer.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py index e25f85af85..cd4acc9aa4 100644 --- a/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py +++ b/tests/topotests/bgp_default_originate_withdraw/test_bgp_default_originate_withdraw.py @@ -49,7 +49,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_default_route/test_bgp_default-originate.py b/tests/topotests/bgp_default_route/test_bgp_default-originate.py index 333beb067c..e805d06a6a 100644 --- a/tests/topotests/bgp_default_route/test_bgp_default-originate.py +++ b/tests/topotests/bgp_default_route/test_bgp_default-originate.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -85,19 +85,19 @@ def _bgp_route_is_valid(router, prefix): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_check_if_received) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "No 0.0.0.0/0 at r2 from r1" test_func = functools.partial(_bgp_check_if_originated) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "No 0.0.0.0/0 from r1 to r2" test_func = functools.partial(_bgp_route_is_valid, tgen.gears["r2"], "0.0.0.0/0") - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see 0.0.0.0/0 in r2" test_func = functools.partial(_bgp_route_is_valid, tgen.gears["r2"], "0.0.0.0/1") - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see 0.0.0.0/1 in r2" diff --git a/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py b/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py index 9dcb5a1eef..d866b95f7b 100644 --- a/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py +++ b/tests/topotests/bgp_default_route_route_map_match/test_bgp_default-originate_route-map_match.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -80,12 +80,12 @@ def _bgp_default_route_is_valid(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py b/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py index 965d348bd7..5a99878b88 100644 --- a/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py +++ b/tests/topotests/bgp_default_route_route_map_match2/test_bgp_default-originate_route-map_match2.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -84,7 +84,7 @@ def _bgp_default_route_is_valid(router): step("Converge network") test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed to see bgp convergence at r2" step("Withdraw 10.0.0.0/22 from R2") @@ -94,7 +94,7 @@ def _bgp_default_route_is_valid(router): step("Check if we don't have 0.0.0.0/0 at R2") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) assert result is not None, "0.0.0.0/0 exists at r2" step("Announce 10.0.0.0/22 from R2") @@ -102,7 +102,7 @@ def _bgp_default_route_is_valid(router): step("Check if we have 0.0.0.0/0 at R2") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "0.0.0.0/0 does not exist at r2" step("Withdraw 10.0.0.0/22 from R2 again") @@ -112,7 +112,7 @@ def _bgp_default_route_is_valid(router): step("Check if we don't have 0.0.0.0/0 at R2 again") test_func = functools.partial(_bgp_default_route_is_valid, router) - success, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, not None, count=30, wait=0.5) assert result is not None, "0.0.0.0/0 exists at r2" diff --git a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py index f94620b2c9..3a374c6e9a 100644 --- a/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py +++ b/tests/topotests/bgp_default_route_route_map_match_set/test_bgp_default-originate_route-map_match_set.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -90,12 +90,12 @@ def _bgp_default_route_has_metric(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) test_func = functools.partial(_bgp_default_route_has_metric, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py b/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py index e633b61d1b..ba278295a6 100644 --- a/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py +++ b/tests/topotests/bgp_default_route_route_map_set/test_bgp_default-originate_route-map_set.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py b/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py index 70562ce31f..6978008740 100644 --- a/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py +++ b/tests/topotests/bgp_disable_addpath_rx/test_disable_addpath_rx.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -98,7 +98,7 @@ def check_bgp_advertised_routes(router): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_advertised_routes, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "AddPath TX not working." step("Check if AddPath RX is disabled on r1 and we receive only 2 paths.") @@ -120,7 +120,7 @@ def check_bgp_disabled_addpath_rx(router): return topotest.json_cmp(output, expected) test_func = functools.partial(check_bgp_disabled_addpath_rx, r1) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "AddPath RX advertised, but should not." diff --git a/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py b/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py index 0bd3d2814b..0307ee2f4e 100755 --- a/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py +++ b/tests/topotests/bgp_distance_change/test_bgp_admin_dist.py @@ -215,7 +215,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Configure static route in R4 and R5, redistribute in bgp") for addr_type in ADDR_TYPES: - input_dict = { "r4": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -228,7 +227,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): ) for addr_type in ADDR_TYPES: - input_dict = { "r5": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -268,7 +266,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Configure the static route in R3 (Dut).") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -305,7 +302,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step(" Configure the admin distance of 254 to static route in R3.") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -571,7 +567,6 @@ def test_bgp_admin_distance_ebgp_ecmp_p0(): step("Reconfigure the static route without admin distance") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -993,7 +988,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Configure static route Without any admin distance") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -1009,7 +1003,6 @@ def test_bgp_admin_distance_ibgp_p0(): protocol = "static" for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [{"network": NETWORK[addr_type], "next_hop": "Null0"}] @@ -1023,7 +1016,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Configure static route with admin distance of 253") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ @@ -1086,7 +1078,6 @@ def test_bgp_admin_distance_ibgp_p0(): step("Delete the static route.") for addr_type in ADDR_TYPES: - input_dict = { "r3": { "static_routes": [ diff --git a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py index 2ca50aa56e..87802511b5 100644 --- a/tests/topotests/bgp_distance_change/test_bgp_distance_change.py +++ b/tests/topotests/bgp_distance_change/test_bgp_distance_change.py @@ -51,7 +51,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -101,14 +101,14 @@ def _bgp_check_distance_change(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) _bgp_distance_change(router) test_func = functools.partial(_bgp_check_distance_change, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see applied BGP distance in RIB "{}"'.format( router diff --git a/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py b/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py index 8269322215..28d6b56303 100644 --- a/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py +++ b/tests/topotests/bgp_dont_capability_negotiate/test_bgp_dont_capability_negotiate.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf new file mode 100644 index 0000000000..8084962587 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/bgpd.conf @@ -0,0 +1,14 @@ +router bgp 64500 + bgp router-id 192.0.2.1 + timers bgp 3 9 + no bgp ebgp-requires-policy + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver timers connect 2 + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + neighbor rrserver next-hop-self + neighbor rrserver activate + exit-address-family +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf new file mode 100644 index 0000000000..9660577f4e --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/isisd.conf @@ -0,0 +1,26 @@ +hostname r1 +interface lo + ip router isis 1 + isis passive +! +interface r1-eth1 + ip router isis 1 + isis network point-to-point +! +interface r1-eth2 + ip router isis 1 + isis network point-to-point +! +interface r1-eth4 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0001.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.1/32 index 1 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf new file mode 100644 index 0000000000..2e3549a574 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r1/zebra.conf @@ -0,0 +1,24 @@ +log stdout +interface lo + ip address 192.0.2.1/32 +! +interface r1-eth0 + ip address 172.31.10.1/24 +! +interface r1-eth1 + ip address 172.31.0.1/24 + mpls enable +! +interface r1-eth2 + ip address 172.31.2.1/24 + mpls enable +! +interface r1-eth3 + ip address 172.31.11.1/24 + mpls enable +! +interface r1-eth4 + ip address 172.31.8.1/24 + mpls enable +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf new file mode 100644 index 0000000000..7312dba407 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/bgpd.conf @@ -0,0 +1,17 @@ +router bgp 64500 view one + timers bgp 3 9 + bgp router-id 192.0.2.3 + neighbor rr peer-group + neighbor rr remote-as 64500 + neighbor rr update-source lo + neighbor 192.0.2.1 peer-group rr + neighbor 192.0.2.5 peer-group rr + neighbor 192.0.2.6 peer-group rr + neighbor 192.0.2.8 peer-group rr + ! + address-family ipv4 unicast + neighbor rr activate + neighbor rr route-reflector-client + neighbor rr addpath-tx-all-paths + exit-address-family +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf new file mode 100644 index 0000000000..ae6bddee92 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/isisd.conf @@ -0,0 +1,38 @@ +hostname r3 +interface lo + ip router isis 1 + isis passive +! +interface r3-eth0 + ip router isis 1 + isis network point-to-point +! +interface r3-eth1 + ip router isis 1 + isis network point-to-point +! +interface r3-eth2 + ip router isis 1 + isis network point-to-point +! +interface r3-eth3 + ip router isis 1 + isis network point-to-point +! +interface r3-eth4 + ip router isis 1 + isis network point-to-point +! +interface r3-eth5 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0003.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.3/32 index 3 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf new file mode 100644 index 0000000000..05b3769fb8 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r3/zebra.conf @@ -0,0 +1,16 @@ +log stdout +interface lo + ip address 192.0.2.3/32 +! +interface r3-eth0 + ip address 172.31.0.3/24 + mpls enable +! +interface r3-eth1 + ip address 172.31.4.3/24 + mpls enable +! +interface r3-eth2 + ip address 172.31.5.3/24 + mpls enable +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf new file mode 100644 index 0000000000..4d49d0de0a --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r4/isisd.conf @@ -0,0 +1,30 @@ +hostname r4 +interface lo + ip router isis 1 + isis passive +! +interface r4-eth0 + ip router isis 1 + isis network point-to-point +! +interface r4-eth1 + ip router isis 1 + isis network point-to-point +! +interface r4-eth2 + ip router isis 1 + isis network point-to-point +! +interface r4-eth3 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0004.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.4/32 index 4 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf new file mode 100644 index 0000000000..9ea1b7ec43 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r4/zebra.conf @@ -0,0 +1,20 @@ +log stdout +interface lo + ip address 192.0.2.4/32 +! +interface r4-eth0 + ip address 172.31.2.4/24 + mpls enable +! +interface r4-eth1 + ip address 172.31.6.4/24 + mpls enable +! +interface r4-eth2 + ip address 172.31.7.4/24 + mpls enable +! +interface r4-eth3 + mpls enable +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf new file mode 100644 index 0000000000..e46d7c5ed4 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/bgpd.conf @@ -0,0 +1,20 @@ +router bgp 64500 + timers bgp 3 9 + bgp router-id 192.0.2.5 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver timers connect 2 + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + network 192.0.2.9/32 + network 192.0.2.8/32 route-map rmap + neighbor rrserver activate + neighbor rrserver addpath-tx-all-paths + exit-address-family +! +route-map rmap permit 1 + set ip next-hop 192.0.2.9 +exit diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf new file mode 100644 index 0000000000..46556d9a56 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/isisd.conf @@ -0,0 +1,26 @@ +hostname r5 +interface lo + ip router isis 1 + isis passive +! +interface r5-eth1 + ip router isis 1 + isis network point-to-point +! +interface r5-eth2 + ip router isis 1 + isis network point-to-point +! +interface r5-eth3 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0005.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.5/32 index 55 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf new file mode 100644 index 0000000000..6f326561e7 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r5/zebra.conf @@ -0,0 +1,19 @@ +log stdout +mpls label dynamic-block 5000 5999 +interface lo + ip address 192.0.2.5/32 +! +interface r5-eth0 + ip address 172.31.12.5/24 +! +interface r5-eth1 + ip address 172.31.4.5/24 + mpls enable +! +interface r5-eth2 + ip address 172.31.7.5/24 + mpls enable +! +interface r5-eth3 + ip address 172.31.21.5/24 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf new file mode 100644 index 0000000000..3aa9adb18b --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/bgpd.conf @@ -0,0 +1,20 @@ +router bgp 64500 + timers bgp 3 9 + bgp router-id 192.0.2.6 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor rrserver peer-group + neighbor rrserver remote-as 64500 + neighbor rrserver update-source lo + neighbor rrserver bfd + neighbor 192.0.2.3 peer-group rrserver + address-family ipv4 unicast + network 192.0.2.9/32 + network 192.0.2.8/32 route-map rmap + neighbor rrserver activate + neighbor rrserver addpath-tx-all-paths + exit-address-family +! +route-map rmap permit 1 + set ip next-hop 192.0.2.9 +exit diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf b/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf new file mode 100644 index 0000000000..5126a64858 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/isisd.conf @@ -0,0 +1,22 @@ +hostname r6 +interface lo + ip router isis 1 + isis passive +! +interface r6-eth1 + ip router isis 1 + isis network point-to-point +! +interface r6-eth2 + ip router isis 1 + isis network point-to-point +! +router isis 1 + net 49.0123.6452.0006.00 + is-type level-2-only + mpls-te on + segment-routing on + segment-routing global-block 16000 17000 + segment-routing node-msd 10 + segment-routing prefix 192.0.2.6/32 index 6 +! diff --git a/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf b/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf new file mode 100644 index 0000000000..cda62d7e87 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/r6/zebra.conf @@ -0,0 +1,20 @@ +log stdout +mpls label dynamic-block 6000 6999 +interface lo + ip address 192.0.2.6/32 +! +interface r6-eth0 + ip address 172.31.13.6/24 +! +interface r6-eth1 + ip address 172.31.5.6/24 + mpls enable +! +interface r6-eth2 + ip address 172.31.6.6/24 + mpls enable +! +interface r6-eth3 + ip address 172.31.22.6/24 +! + diff --git a/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py new file mode 100644 index 0000000000..5c125869e2 --- /dev/null +++ b/tests/topotests/bgp_duplicate_nexthop/test_bgp_duplicate_nexthop.py @@ -0,0 +1,458 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_bgp_duplicate_nexthop.py +# +# Copyright 2024 6WIND S.A. +# + +r""" + test_bgp_nhg_duplicate_nexthop.py: + Check that the FRR BGP daemon on r1 selects updates with same nexthops + + ++---+----+ +---+----+ +--------+ +| | | + | | +| r1 +----------+ r3 +----------+ r5 + +| | | rr + +-----+ | ++++-+----+ +--------+\ / +--------+ + | \/ + | /\ + | +--------+/ \ +--------+ + | | + +-----+ + + +---------------+ r4 +----------+ r6 + + | | | | + +--------+ +--------+ +""" + +import os +import sys +import json +from functools import partial +import pytest +import functools + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.common_check import ip_check_path_selection, iproute2_check_path_selection +from lib.common_config import step +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + "Build function" + + # Create 7 PE routers. + tgen.add_router("r1") + tgen.add_router("r3") + tgen.add_router("r4") + tgen.add_router("r5") + tgen.add_router("r6") + + # switch + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s6") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s7") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s8") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s9") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s10") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s11") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s12") + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s13") + switch.add_link(tgen.gears["r6"]) + + switch = tgen.add_switch("s14") + switch.add_link(tgen.gears["r1"]) + + +def setup_module(mod): + "Sets up the pytest environment" + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for rname, router in router_list.items(): + router.load_config( + TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) + ) + router.load_config( + TopoRouter.RD_ISIS, os.path.join(CWD, "{}/isisd.conf".format(rname)) + ) + if rname in ("r1", "r3", "r5", "r6"): + router.load_config( + TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + # Initialize all routers. + tgen.start_router() + + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + tgen.stop_topology() + + +def check_ipv4_prefix_with_multiple_nexthops(prefix, multipath=True): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info( + f"Check that {prefix} unicast entry is installed with paths for r5 and r6" + ) + + r5_nh = [ + { + "ip": "192.0.2.5", + "active": True, + "recursive": True, + }, + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16055, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16055, + ], + }, + ] + + r6_nh = [ + { + "ip": "192.0.2.6", + "active": True, + "recursive": True, + }, + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16006, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16006, + ], + }, + ] + + expected = { + prefix: [ + { + "prefix": prefix, + "protocol": "bgp", + "metric": 0, + "table": 254, + "nexthops": [], + } + ] + } + for nh in r5_nh: + expected[prefix][0]["nexthops"].append(nh) + if multipath: + for nh in r6_nh: + expected[prefix][0]["nexthops"].append(nh) + + test_func = functools.partial( + ip_check_path_selection, tgen.gears["r1"], prefix, expected + ) + _, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} uses the IGP label 16055 and 16006" + + +def get_nh_formatted(nexthop, fib=True, duplicate=False): + nh = dict(nexthop) + if duplicate: + nh.update({"duplicate": True}) + if fib: + nh.update({"fib": True}) + return nh + + +def check_ipv4_prefix_recursive_with_multiple_nexthops( + prefix, recursive_nexthop, multipath=True +): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + logger.info( + f"Check that {prefix} unicast entry is correctly recursive via {recursive_nexthop} with paths for r5 and r6" + ) + + r5_nh = [ + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16055, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16055, + ], + }, + ] + + r6_nh = [ + { + "ip": "172.31.0.3", + "interfaceName": "r1-eth1", + "active": True, + "labels": [ + 16006, + ], + }, + { + "ip": "172.31.2.4", + "interfaceName": "r1-eth2", + "active": True, + "labels": [ + 16006, + ], + }, + ] + + expected = { + prefix: [ + { + "prefix": prefix, + "protocol": "bgp", + "metric": 0, + "table": 254, + "nexthops": [], + } + ] + } + + recursive_nh = [ + { + "ip": recursive_nexthop, + "active": True, + "recursive": True, + }, + ] + for nh in recursive_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh, fib=False)) + + for nh in r5_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh)) + + if multipath: + for nh in r6_nh: + expected[prefix][0]["nexthops"].append(get_nh_formatted(nh)) + + for nh in recursive_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + for nh in r5_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + for nh in r6_nh: + expected[prefix][0]["nexthops"].append( + get_nh_formatted(nh, fib=False, duplicate=True) + ) + + test_func = functools.partial( + ip_check_path_selection, tgen.gears["r1"], prefix, expected, check_fib=True + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} is correctly recursive via {recursive_nexthop}" + + +def check_ipv4_prefix_with_multiple_nexthops_linux(prefix): + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step( + f"Check that {prefix} unicast entry is installed with paths for r5 and r6 on Linux" + ) + + r5_nh = [ + { + "encap": "mpls", + "dst": "16055", + "gateway": "172.31.0.3", + "dev": "r1-eth1", + }, + { + "encap": "mpls", + "dst": "16055", + "gateway": "172.31.2.4", + "dev": "r1-eth2", + }, + ] + + r6_nh = [ + { + "encap": "mpls", + "dst": "16006", + "gateway": "172.31.0.3", + "dev": "r1-eth1", + }, + { + "encap": "mpls", + "dst": "16006", + "gateway": "172.31.2.4", + "dev": "r1-eth2", + }, + ] + + expected = [ + { + "dst": prefix, + "protocol": "bgp", + "metric": 20, + "nexthops": [], + } + ] + + # only one path + for nh in r5_nh: + expected[0]["nexthops"].append(nh) + for nh in r6_nh: + expected[0]["nexthops"].append(nh) + + test_func = functools.partial( + iproute2_check_path_selection, tgen.routers()["r1"], prefix, expected + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), f"Failed to check that {prefix} unicast entry is installed with paths for r5 and r6 on Linux" + + +def test_bgp_ipv4_convergence(): + """ + Check that R1 has received the 192.0.2.9/32 prefix from R5, and R6 + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Ensure that the 192.0.2.9/32 route is available") + check_ipv4_prefix_with_multiple_nexthops("192.0.2.9/32") + + check_ipv4_prefix_with_multiple_nexthops_linux("192.0.2.9") + + +def test_bgp_ipv4_recursive_routes(): + """ + Check that R1 has received the recursive routes, and duplicate nexthops are in zebra, but are not installed + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + check_ipv4_prefix_recursive_with_multiple_nexthops("192.0.2.8/32", "192.0.2.9") + + check_ipv4_prefix_with_multiple_nexthops_linux("192.0.2.8") + + +def test_bgp_ipv4_recursive_routes_when_no_mpath(): + """ + Unconfigure multipath ibgp + Check that duplicate nexthops are not in zebra + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + router bgp + address family ipv4 unicast + maximum-paths ibgp 1 + """, + isjson=False, + ) + tgen.gears["r1"].vtysh_cmd("clear bgp ipv4 *") + check_ipv4_prefix_with_multiple_nexthops("192.0.2.9/32", multipath=False) + + check_ipv4_prefix_recursive_with_multiple_nexthops( + "192.0.2.8/32", "192.0.2.9", multipath=False + ) + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py index 4d7d46c3e8..91df89b1b5 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py @@ -14,7 +14,6 @@ """ import os -import re import sys import json import pytest @@ -27,7 +26,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen def setup_module(mod): diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py index 26fae17c5e..bf05ce8edd 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_fqdn.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py index d67bfea45e..514b29cd70 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_graceful_restart.py @@ -12,7 +12,6 @@ """ import os -import re import sys import json import pytest @@ -25,7 +24,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py index 9e1f26f21e..39e7ded1e6 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_orf.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py index f6c1e25fd6..7d36634728 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_role.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py index 128283bbc3..591fc5a817 100644 --- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py +++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_software_version.py @@ -23,7 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step diff --git a/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py b/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py index d9ccd6979c..a4ac249cb7 100644 --- a/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py +++ b/tests/topotests/bgp_ebgp_common_subnet_nexthop_unchanged/test_bgp-ebgp-common-subnet-nexthop-unchanged.py @@ -52,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -90,7 +90,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, r3) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(r3) @@ -100,7 +100,7 @@ def _bgp_nh_unchanged(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_nh_unchanged, r2) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Wrong next-hop in "{}"'.format(r2) diff --git a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py index 6e3b2859c4..f7c0f70445 100644 --- a/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py +++ b/tests/topotests/bgp_ebgp_requires_policy/test_bgp_ebgp_requires_policy.py @@ -71,7 +71,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -125,31 +125,31 @@ def _bgp_advertised_routes(router): # Scenario 1. logger.info("Scenario 1: r2 receives 192.168.255.1/32 from r1") test_func = functools.partial(_bgp_converge, "r2") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r2)" test_func = functools.partial(_bgp_has_routes, "r2") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r2 does not receive 192.168.255.1/32" # Scenario 2. logger.info("Scenario 2: r3 must not send 192.168.255.1/32 to r4") test_func = functools.partial(_bgp_converge, "r4") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r4)" test_func = functools.partial(_bgp_advertised_routes, "r3") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r3 announced 192.168.255.1/32 to r4" # Scenario 3. logger.info("Scenario 3: r6 receives 192.168.255.1/32 from r5 (iBGP)") test_func = functools.partial(_bgp_converge, "r6") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "Failed bgp convergence (r6)" test_func = functools.partial(_bgp_has_routes, "r6") - success, result = topotest.run_and_expect(test_func, None, count=120, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=120, wait=0.5) assert success is True, "r6 does not receive 192.168.255.1/32" diff --git a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py index b347042dcf..5991f2e7ca 100644 --- a/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py +++ b/tests/topotests/bgp_ecmp_topo2/test_ibgp_ecmp_topo2.py @@ -106,7 +106,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format( BGP_CONVERGENCE @@ -153,7 +153,6 @@ def teardown_module(): def static_or_nw(tgen, topo, tc_name, test_type, dut): - if test_type == "redist_static": input_dict_static = { dut: { @@ -363,7 +362,6 @@ def test_ecmp_remove_redistribute_static(request): reset_config_on_routers(tgen) static_or_nw(tgen, topo, tc_name, "redist_static", "r2") for addr_type in ADDR_TYPES: - # Verifying RIB routes dut = "r3" protocol = "bgp" @@ -406,7 +404,6 @@ def test_ecmp_remove_redistribute_static(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) for addr_type in ADDR_TYPES: - # Verifying RIB routes dut = "r3" protocol = "bgp" diff --git a/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py b/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py index 5469eff144..876c205f19 100644 --- a/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py +++ b/tests/topotests/bgp_evpn_maximum_prefix/test_bgp_evpn_maximum_prefix.py @@ -6,7 +6,6 @@ # import os -import re import sys import json import pytest @@ -17,7 +16,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py index b033e9c2eb..ba2fb62661 100644 --- a/tests/topotests/bgp_evpn_mh/test_evpn_mh.py +++ b/tests/topotests/bgp_evpn_mh/test_evpn_mh.py @@ -455,7 +455,7 @@ def check_remote_es(esi, vtep_ips, dut_name, down_vteps): else: tor_ips_rack = tor_ips_rack_1 - for tor_name, tor_ip in tor_ips_rack.items(): + for _, tor_ip in tor_ips_rack.items(): remote_ips.append(tor_ip) # remove down VTEPs from the remote check list diff --git a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py index 603f069fe3..d441a256fd 100755 --- a/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py +++ b/tests/topotests/bgp_evpn_overlay_index_gateway/test_bgp_evpn_overlay_index_gateway.py @@ -241,7 +241,7 @@ def evpn_gateway_ip_show_op_check(trigger=" "): expected_op = json.loads(open(expected_op_file).read()) test_func = partial(topotest.router_json_cmp, pe, command, expected_op) - ret, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assertmsg = '"{0}" JSON output mismatch for {1}'.format(name, command) if result is not None: return result, assertmsg diff --git a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py index 2df0fd0e6c..36c79d6b2b 100644 --- a/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py +++ b/tests/topotests/bgp_evpn_route_map_match/test_bgp_evpn_route_map_match.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,8 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step +from lib.topogen import Topogen, get_topogen def setup_module(mod): diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf index ccbeae6ed7..c8c4faf222 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf @@ -20,7 +20,11 @@ router bgp 65000 vrf r1-vrf-101 address-family ipv4 unicast network 192.168.102.21/32 exit-address-family + address-family ipv6 unicast + network fd00::1/128 + exit-address-family address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! diff --git a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf index 4f1804c676..c3d508c2b6 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf @@ -17,6 +17,7 @@ interface r1-eth0 ! interface loop101 vrf r1-vrf-101 ip address 192.168.102.21/32 + ipv6 address fd00::1/128 ! diff --git a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf index 744c259d9a..de5a0efc44 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf @@ -21,7 +21,11 @@ router bgp 65000 vrf r2-vrf-101 address-family ipv4 unicast network 192.168.101.41/32 exit-address-family + address-family ipv6 unicast + network fd00::2/128 + exit-address-family address-family l2vpn evpn advertise ipv4 unicast + advertise ipv6 unicast exit-address-family ! diff --git a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf index 7d19a5b381..7db40cb59c 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf @@ -11,6 +11,7 @@ vrf r2-vrf-101 ! interface loop101 vrf r2-vrf-101 ip address 192.168.101.41/32 + ipv6 address fd00::2/128 ! interface r2-eth0 ip address 192.168.100.41/24 diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py index d9177b4d25..2d027081cb 100644 --- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py +++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py @@ -25,6 +25,8 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest +from lib.bgp import verify_bgp_rib +from lib.common_config import apply_raw_config from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger @@ -179,12 +181,18 @@ def test_protocols_convergence(): output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101 ipv4", isjson=False) logger.info("==== result from show bgp vrf r1-vrf-101 ipv4") logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101 ipv6", isjson=False) + logger.info("==== result from show bgp vrf r1-vrf-101 ipv6") + logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show bgp vrf r1-vrf-101", isjson=False) logger.info("==== result from show bgp vrf r1-vrf-101 ") logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show ip route vrf r1-vrf-101", isjson=False) logger.info("==== result from show ip route vrf r1-vrf-101") logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show ipv6 route vrf r1-vrf-101", isjson=False) + logger.info("==== result from show ipv6 route vrf r1-vrf-101") + logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show evpn vni detail", isjson=False) logger.info("==== result from show evpn vni detail") logger.info(output) @@ -192,8 +200,49 @@ def test_protocols_convergence(): logger.info("==== result from show evpn next-hops vni all") logger.info(output) output = tgen.gears["r1"].vtysh_cmd("show evpn rmac vni all", isjson=False) - logger.info("==== result from show evpn next-hops vni all") + logger.info("==== result from show evpn rmac vni all") logger.info(output) + + expected = { + "fd00::2/128": [ + { + "prefix": "fd00::2/128", + "vrfName": "r1-vrf-101", + "nexthops": [ + { + "ip": "::ffff:c0a8:6429", + } + ], + } + ] + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show ipv6 route vrf r1-vrf-101 fd00::2/128 json", expected + ) + assert result is None, "ipv6 route check failed" + + expected = { + "101": { + "numNextHops": 2, + "192.168.100.41": { + "nexthopIp": "192.168.100.41", + }, + "::ffff:c0a8:6429": { + "nexthopIp": "::ffff:c0a8:6429", + }, + } + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn next-hops vni all json", expected + ) + assert result is None, "evpn next-hops check failed" + + expected = {"101": {"numRmacs": 1}} + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn rmac vni all json", expected + ) + assert result is None, "evpn rmac number check failed" + # Check IPv4 and IPv6 connectivity between r1 and r2 ( routing vxlan evpn) pingrouter = tgen.gears["r1"] logger.info( @@ -209,6 +258,80 @@ def test_protocols_convergence(): else: logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK") + logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(r2-vrf-101 = fd00::2)") + output = pingrouter.run("ip netns exec r1-vrf-101 ping fd00::2 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assert 0, "expected ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) should be ok" + else: + logger.info("Check Ping IPv6 from R1(r1-vrf-101) to R2(fd00::2) OK") + + config_no_ipv6 = { + "r2": { + "raw_config": [ + "router bgp 65000 vrf r2-vrf-101", + "address-family ipv6 unicast", + "no network fd00::2/128", + ] + } + } + + logger.info("==== Remove IPv6 network on R2") + result = apply_raw_config(tgen, config_no_ipv6) + assert result is True, "Failed to remove IPv6 network on R2, Error: {} ".format( + result + ) + ipv6_routes = { + "r1": { + "static_routes": [ + { + "vrf": "r1-vrf-101", + "network": ["fd00::2/128"], + } + ] + } + } + result = verify_bgp_rib(tgen, "ipv6", "r1", ipv6_routes, expected=False) + assert result is not True, "expect IPv6 route fd00::2/128 withdrawn" + output = tgen.gears["r1"].vtysh_cmd("show evpn next-hops vni all", isjson=False) + logger.info("==== result from show evpn next-hops vni all") + logger.info(output) + output = tgen.gears["r1"].vtysh_cmd("show evpn rmac vni all", isjson=False) + logger.info("==== result from show evpn next-hops vni all") + logger.info(output) + + expected = { + "101": { + "numNextHops": 1, + "192.168.100.41": { + "nexthopIp": "192.168.100.41", + }, + } + } + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn next-hops vni all json", expected + ) + assert result is None, "evpn next-hops check failed" + + expected = {"101": {"numRmacs": 1}} + result = topotest.router_json_cmp( + tgen.gears["r1"], "show evpn rmac vni all json", expected + ) + assert result is None, "evpn rmac number check failed" + + logger.info( + "Check Ping IPv4 from R1(r1-vrf-101) to R2(r2-vrf-101 = 192.168.101.41)" + ) + output = pingrouter.run("ip netns exec r1-vrf-101 ping 192.168.101.41 -f -c 1000") + logger.info(output) + if "1000 packets transmitted, 1000 received" not in output: + assertmsg = ( + "expected ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) should be ok" + ) + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1(r1-vrf-101) to R2(192.168.101.41) OK") + def test_memory_leak(): "Run the memory leak test and report results." diff --git a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py index a5e5bdcee9..e4d330e13c 100644 --- a/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py +++ b/tests/topotests/bgp_extcomm_list_delete/test_bgp_extcomm-list_delete.py @@ -25,7 +25,6 @@ # pylint: disable=C0413 from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from lib import topotest @@ -47,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py index e7058f5392..e9006b81c9 100644 --- a/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py +++ b/tests/topotests/bgp_extended_link_bandwidth/test_bgp_extended_link_bandwidth.py @@ -6,7 +6,6 @@ # import os -import re import sys import json import pytest @@ -17,7 +16,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py index a5db20e474..c67bc91f63 100644 --- a/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py +++ b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py index 43f4905d41..0f5d9dea42 100644 --- a/tests/topotests/bgp_features/test_bgp_features.py +++ b/tests/topotests/bgp_features/test_bgp_features.py @@ -18,7 +18,6 @@ import os import sys import pytest -import re import time # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py index 5e2b2f37b2..2e2c8119a2 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py @@ -102,7 +102,6 @@ verify_graceful_restart, create_router_bgp, verify_r_bit, - verify_f_bit, verify_bgp_convergence, verify_bgp_convergence_from_running_config, ) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py index 13c5ba538c..9f79c52e3a 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py @@ -117,8 +117,6 @@ check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py index 1a8f8302ff..0873c24b7f 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py @@ -117,7 +117,6 @@ check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, step, get_frr_ipv6_linklocal, required_linux_kernel_version, diff --git a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py index 31aaa0b8a6..710514b056 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py @@ -81,6 +81,8 @@ import sys import time import pytest +import functools +import json # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -91,6 +93,7 @@ # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen from lib.topolog import logger +from lib import topotest # Required to instantiate the topology builder class. @@ -101,8 +104,6 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, - verify_f_bit, verify_bgp_convergence, verify_bgp_convergence_from_running_config, ) @@ -117,7 +118,6 @@ check_address_types, write_test_footer, check_router_status, - shutdown_bringup_interface, step, get_frr_ipv6_linklocal, required_linux_kernel_version, @@ -1680,6 +1680,304 @@ def BGP_GR_TC_52_p1(request): write_test_footer(tc_name) +def test_BGP_GR_TC_53_p1(request): + """ + Test Objective : Peer-level inherit from BGP wide Restarting + Global Mode : GR Restart + PerPeer Mode : None + GR Mode effective : GR Restart + + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + # Check router status + check_router_status(tgen) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Creating configuration from JSON + reset_config_on_routers(tgen) + + step("Configure R1 as GR restarting node in global level") + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart + ! + """ + ) + + step("Verify that R2 receives GR restarting capabilities" " from R1") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGPd on router R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step( + "Verify that R1 keeps the stale entries in FIB and R2 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Configure graceful-restart-disable at config global level verify that the functionality works + step("Bring up BGP on R1 and configure graceful-restart-disable") + + start_router_daemons(tgen, "r1", ["bgpd"]) + + input_dict = { + "r1": {"graceful-restart": {"graceful-restart-disable": True}}, + "r2": {"graceful-restart": {"graceful-restart-helper": True}}, + } + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + bgp graceful-restart-disable + ! + """ + ) + + step("Verify on R2 that R1 does't advertise any GR capabilities") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Kill BGP on R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step("Verify on R2 and R1 that none of the routers keep stale entries") + + for addr_type in ADDR_TYPES: + dut = "r1" + peer = "r2" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + dut = "r2" + peer = "r1" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib( + tgen, addr_type, dut, input_topo, next_hop, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} BGP RIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "Expected: Routes should not be present in {} FIB \n " + "Found: {}".format(tc_name, dut, result) + ) + + step( + "Bring up BGP on R1, enable GR and configure bgp graceful-restart restart-time at global level" + ) + + start_router_daemons(tgen, "r1", ["bgpd"]) + + output = tgen.gears["r1"].vtysh_cmd( + """ + configure terminal + no bgp graceful-restart-disable + bgp graceful-restart + bgp graceful-restart stalepath-time 420 + bgp graceful-restart restart-time 240 + bgp graceful-restart select-defer-time 420 + ! + """ + ) + + step("Verify on R2 that R1 sent the updated GR restart-time") + + def _bgp_check_if_gr_restart_time_was_updated(): + output = json.loads(tgen.gears["r2"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + "fd00::1": { + "gracefulRestartInfo": { + "localGrMode": "Helper*", + "remoteGrMode": "Restart", + "timers": { + "configuredRestartTimer": 120, + "receivedRestartTimer": 240, + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_restart_time_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "R2 did not receive the updated GR restart-time of 240s" + + def _bgp_check_if_gr_timer_on_restarting_node_was_updated(): + output = json.loads(tgen.gears["r1"].vtysh_cmd("show bgp neighbor json")) + + expected = { + "192.168.0.2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv4Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + "fd00::2": { + "gracefulRestartInfo": { + "localGrMode": "Restart*", + "remoteGrMode": "Helper", + "timers": { + "configuredRestartTimer": 240, + "receivedRestartTimer": 120, + }, + "ipv6Unicast": { + "timers": {"stalePathTimer": 420, "selectionDeferralTimer": 420} + }, + }, + }, + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_check_if_gr_timer_on_restarting_node_was_updated, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert ( + result is None + ), "R1 did not update the GR select-deferral and stale-path timer to 420s" + + write_test_footer(tc_name) + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py index cb6bf56967..01ab10b82f 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py @@ -94,13 +94,10 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, verify_eor, - verify_f_bit, verify_bgp_convergence, verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -169,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py index cf9a474a81..989d2d554a 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py @@ -95,7 +95,6 @@ verify_graceful_restart, create_router_bgp, verify_r_bit, - verify_eor, verify_f_bit, verify_bgp_convergence, verify_gr_address_family, @@ -114,7 +113,6 @@ check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -169,7 +167,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py index 4746d71a32..05fb8bf796 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py @@ -98,9 +98,7 @@ verify_eor, verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -114,7 +112,6 @@ check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -169,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py index 1c41df98e1..950733c3af 100644 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py @@ -96,13 +96,9 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, verify_eor, - verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) @@ -116,7 +112,6 @@ check_address_types, write_test_footer, check_router_status, - step, get_frr_ipv6_linklocal, required_linux_kernel_version, ) @@ -171,7 +166,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py b/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py index 593a8d6417..e24f31d862 100644 --- a/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py +++ b/tests/topotests/bgp_gr_functionality_topo3/test_bgp_gr_functionality_topo3.py @@ -12,7 +12,6 @@ import pytest from time import sleep -import traceback import ipaddress # Save the Current Working Directory to find configuration files. @@ -34,37 +33,21 @@ verify_bgp_rib, verify_graceful_restart, create_router_bgp, - verify_r_bit, - verify_eor, - verify_f_bit, verify_bgp_convergence, - verify_gr_address_family, - modify_bgp_config_when_bgpd_down, - verify_graceful_restart_timers, verify_bgp_convergence_from_running_config, ) # Import common_config to use commomnly used APIs from lib.common_config import ( - create_common_configuration, - InvalidCLIError, - retry, generate_ips, - FRRCFG_FILE, - find_interface_with_greater_ip, check_address_types, validate_ip_address, run_frr_cmd, - get_frr_ipv6_linklocal, ) from lib.common_config import ( write_test_header, - reset_config_on_routers, start_topology, - kill_router_daemons, - start_router_daemons, - verify_rib, check_address_types, write_test_footer, check_router_status, @@ -154,9 +137,6 @@ def verify_stale_routes_list(tgen, addr_type, dut, input_dict): """ logger.debug("Entering lib API: verify_stale_routes_list()") router_list = tgen.routers() - additional_nexthops_in_required_nhs = [] - list1 = [] - list2 = [] found_hops = [] for routerInput in input_dict.keys(): for router, rnode in router_list.items(): @@ -266,7 +246,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( BGP_CONVERGENCE @@ -442,7 +422,7 @@ def test_bgp_gr_stale_routes(request): ) assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - for iteration in range(5): + for _ in range(5): step("graceful-restart-disable:True at R3") input_dict = { "r3": { diff --git a/tests/topotests/bgp_gr_notification/r1/bgpd.conf b/tests/topotests/bgp_gr_notification/r1/bgpd.conf index 6119f67436..0af042f6be 100644 --- a/tests/topotests/bgp_gr_notification/r1/bgpd.conf +++ b/tests/topotests/bgp_gr_notification/r1/bgpd.conf @@ -3,7 +3,7 @@ router bgp 65001 bgp graceful-restart neighbor 192.168.255.2 remote-as external neighbor 192.168.255.2 timers 1 3 - neighbor 192.168.255.2 timers connect 1 + neighbor 192.168.255.2 timers delayopen 10 address-family ipv4 redistribute connected exit-address-family diff --git a/tests/topotests/bgp_gr_notification/r2/bgpd.conf b/tests/topotests/bgp_gr_notification/r2/bgpd.conf index 05e17f0564..8325e21d2c 100644 --- a/tests/topotests/bgp_gr_notification/r2/bgpd.conf +++ b/tests/topotests/bgp_gr_notification/r2/bgpd.conf @@ -4,7 +4,7 @@ router bgp 65002 bgp graceful-restart neighbor 192.168.255.1 remote-as external neighbor 192.168.255.1 timers 1 3 - neighbor 192.168.255.1 timers connect 1 + neighbor 192.168.255.1 timers delayopen 10 address-family ipv4 redistribute connected exit-address-family diff --git a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py index 2ffcb723ec..5d8338d6eb 100644 --- a/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py +++ b/tests/topotests/bgp_gr_notification/test_bgp_gr_notification.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -195,16 +195,16 @@ def _bgp_clear_r1_and_shutdown(): step("Reset and shutdown R1") _bgp_clear_r1_and_shutdown() - step("Check if Hard Reset notification wasn't sent from R2") - test_func = functools.partial(_bgp_check_hard_reset) - _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) - assert result is None, "Failed to send Administrative Reset notification from R2" - step("Check if stale routes are retained on R1") test_func = functools.partial(_bgp_check_gr_notification_stale) _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to see retained stale routes on R1" + step("Check if Hard Reset notification wasn't sent from R2") + test_func = functools.partial(_bgp_check_hard_reset) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Failed to send Administrative Reset notification from R2" + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py index 2354c0cd3d..e61efefa5a 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py +++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_per_neighbor_restart_retain_routes.py @@ -22,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step, stop_router pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py index abf737ff34..d7ae43338a 100644 --- a/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py +++ b/tests/topotests/bgp_gr_restart_retain_routes/test_bgp_gr_restart_retain_routes.py @@ -21,7 +21,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step, stop_router pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_gshut/test_bgp_gshut.py b/tests/topotests/bgp_gshut/test_bgp_gshut.py index 61a0fe63c1..cfe63d20ba 100644 --- a/tests/topotests/bgp_gshut/test_bgp_gshut.py +++ b/tests/topotests/bgp_gshut/test_bgp_gshut.py @@ -108,7 +108,7 @@ def setup_module(mod): r2.run("ip link set r2-eth3 master vrf1") # Load FRR config and initialize all routers - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py index c7cb213de5..66eeeb468d 100644 --- a/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py +++ b/tests/topotests/bgp_ipv4_class_e_peer/test_bgp_ipv4_class_e_peer.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py index 395ef2d919..803b51c043 100644 --- a/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py +++ b/tests/topotests/bgp_ipv4_over_ipv6/test_rfc5549_ebgp_unnumbered_nbr.py @@ -23,7 +23,7 @@ from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import ( write_test_header, diff --git a/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py b/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py index ea974b5302..aaa68ea340 100644 --- a/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py +++ b/tests/topotests/bgp_ipv6_ll_peering/test_bgp_ipv6_ll_peering.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py index 7c23a3e899..a0871a4922 100644 --- a/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py +++ b/tests/topotests/bgp_l3vpn_label_export/test_bgp_l3vpn_label_export.py @@ -56,7 +56,7 @@ def setup_module(mod): ) tgen.gears["r{}".format(rtr)].run("sysctl -w net.mpls.conf.vrf1.input=1") - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -146,7 +146,7 @@ def check_mpls_table(label, protocol): if label == "auto" and protocol: output_copy = deepcopy(output) - for key, data in output_copy.items(): + for _, data in output_copy.items(): for nexthop in data.get("nexthops", []): if nexthop.get("type", None) != protocol: continue diff --git a/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py b/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py index f4bb487e40..25fd0dbb71 100644 --- a/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py +++ b/tests/topotests/bgp_labeled_unicast_addpath/test_bgp_labeled_unicast_addpath.py @@ -57,7 +57,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py index 34c23d9b6f..009b39eef0 100644 --- a/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py +++ b/tests/topotests/bgp_labeled_unicast_default_originate/test_bgp_labeled_unicast_default_originate.py @@ -22,7 +22,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] @@ -42,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py index 7023e3a503..49681c6a69 100644 --- a/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py +++ b/tests/topotests/bgp_large_comm_list_match/test_bgp_large_comm_list_match.py @@ -61,7 +61,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_llgr/test_bgp_llgr.py b/tests/topotests/bgp_llgr/test_bgp_llgr.py index d7897cfcb9..547c998c2b 100644 --- a/tests/topotests/bgp_llgr/test_bgp_llgr.py +++ b/tests/topotests/bgp_llgr/test_bgp_llgr.py @@ -32,7 +32,6 @@ from lib.common_config import ( kill_router_daemons, - start_router_daemons, step, ) @@ -65,7 +64,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as/test_bgp_local_as.py b/tests/topotests/bgp_local_as/test_bgp_local_as.py index 9e5f146b47..e61bb0d155 100644 --- a/tests/topotests/bgp_local_as/test_bgp_local_as.py +++ b/tests/topotests/bgp_local_as/test_bgp_local_as.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py index 930fd791b0..c58322a4c0 100644 --- a/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py +++ b/tests/topotests/bgp_local_as_dotplus_private_remove/test_bgp_local_as_dotplus_private_remove.py @@ -63,7 +63,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py index 9d22a799a6..23eb80f316 100644 --- a/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py +++ b/tests/topotests/bgp_local_as_private_remove/test_bgp_local_as_private_remove.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py index c84fce6a9d..214b24eed8 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_agg.py @@ -25,7 +25,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py index 8a1157052e..ce448329eb 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_ecmp.py @@ -21,7 +21,6 @@ import sys import time import pytest -import platform # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -31,7 +30,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py index 25c9bee93c..ff1a81472d 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo1.py @@ -39,7 +39,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py index 0c10c6409f..5d290ce427 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_topo2.py @@ -31,7 +31,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py index ea6ab59b3f..0c7e7cf5c1 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo1.py @@ -26,7 +26,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py index b1204bf583..5a0f34132a 100644 --- a/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py +++ b/tests/topotests/bgp_local_asn/test_bgp_local_asn_vrf_topo2.py @@ -24,7 +24,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py index cfaab9bbe2..453f058223 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_agg.py @@ -38,7 +38,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py index 6937a61c33..d52ed4c334 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_ecmp.py @@ -34,7 +34,6 @@ import sys import time import pytest -import platform # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -44,7 +43,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py index bacef47664..4ee112ebbf 100644 --- a/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py +++ b/tests/topotests/bgp_local_asn_dot/test_bgp_local_asn_dot_topo1.py @@ -52,7 +52,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.topotest import version_cmp from lib.common_config import ( start_topology, diff --git a/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py b/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py index 0656e1ed41..18ffc6a17d 100644 --- a/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py +++ b/tests/topotests/bgp_lu_explicitnull/test_bgp_lu_explicitnull.py @@ -142,7 +142,7 @@ def test_converge_bgplu(): "192.168.2.2/32", "0", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, prefix 192.168.2.2/32 from r2 not present" # Check r2 gets prefix 192.168.2.1/32 @@ -153,7 +153,7 @@ def test_converge_bgplu(): "192.168.2.1/32", "0", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, prefix 192.168.2.1/32 from r1 not present" @@ -178,7 +178,7 @@ def _check_ping(name, dest_addr, src_addr): tgen = get_topogen() func = functools.partial(_check_ping, "r1", "192.168.2.2", "192.168.2.1") # tgen.mininet_cli() - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "r1, ping to 192.168.2.2 from 192.168.2.1 fails" diff --git a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py index a9810ba264..545d7bd245 100644 --- a/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py +++ b/tests/topotests/bgp_max_med_on_startup/test_bgp_max_med_on_startup.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -82,17 +82,17 @@ def _bgp_has_routes(router, metric): # Check session is established test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed bgp convergence on r2" # Check metric has value of max-med test_func = functools.partial(_bgp_has_routes, router2, 777) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 777" # Check that when the max-med timer expires, metric is updated test_func = functools.partial(_bgp_has_routes, router2, 0) - success, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=16, wait=0.5) assert result is None, "r2 does not receive routes with metric 0" diff --git a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py index c6bdbc3c1c..5edc0b55ff 100644 --- a/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py +++ b/tests/topotests/bgp_maximum_prefix_invalid_update/test_bgp_maximum_prefix_invalid_update.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py index 0b346f63d5..aad5f36480 100644 --- a/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py +++ b/tests/topotests/bgp_maximum_prefix_out/test_bgp_maximum_prefix_out.py @@ -45,7 +45,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -177,7 +177,7 @@ def _bgp_converge(router, nb_prefixes): router1.vtysh_cmd(cmd) test_func = functools.partial(_bgp_converge, router2, exp_prfxs) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(router2) diff --git a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py index 9f4d968277..c9ff2ffc7e 100755 --- a/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py +++ b/tests/topotests/bgp_minimum_holdtime/test_bgp_minimum_holdtime.py @@ -40,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -76,7 +76,7 @@ def _bgp_neighbor_check_if_notification_sent(): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_neighbor_check_if_notification_sent) - success, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=0.5) assert result is None, "Failed to send notification message\n" diff --git a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py index 40a28fbcf4..012b643dde 100644 --- a/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py +++ b/tests/topotests/bgp_multi_vrf_topo2/test_bgp_multi_vrf_topo2.py @@ -1845,7 +1845,7 @@ def test_vrf_vlan_routing_table_p1(request): dut = "r3" vrf = "RED_A" - for c_link, c_data in topo["routers"][dut]["links"].items(): + for _, c_data in topo["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue @@ -2634,7 +2634,7 @@ def test_delete_and_re_add_vrf_p1(request): vrfs = ["RED_A", "BLUE_A"] for vrf in vrfs: - for c_link, c_data in topo["routers"][dut]["links"].items(): + for _, c_data in topo["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue @@ -3584,7 +3584,7 @@ def test_vrf_name_significance_p1(request): vrfs = ["GREY_A", "PINK_A"] for vrf in vrfs: - for c_link, c_data in topo_modify["routers"][dut]["links"].items(): + for _, c_data in topo_modify["routers"][dut]["links"].items(): if c_data["vrf"] != vrf: continue diff --git a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py index 23e820b4fc..32f78c44f9 100644 --- a/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py +++ b/tests/topotests/bgp_node_target_extcommunities/test_bgp_node_target_extcommunities.py @@ -24,7 +24,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_oad/test_bgp_oad.py b/tests/topotests/bgp_oad/test_bgp_oad.py index a2ca37a2b7..6dd46fbdaa 100644 --- a/tests/topotests/bgp_oad/test_bgp_oad.py +++ b/tests/topotests/bgp_oad/test_bgp_oad.py @@ -11,7 +11,6 @@ """ import os -import re import sys import json import pytest @@ -24,8 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step +from lib.topogen import Topogen, get_topogen def setup_module(mod): @@ -46,7 +44,7 @@ def teardown_module(mod): tgen.stop_topology() -def test_bgp_dynamic_capability_role(): +def test_bgp_oad(): tgen = get_topogen() if tgen.routers_have_failure(): diff --git a/tests/topotests/bgp_orf/test_bgp_orf.py b/tests/topotests/bgp_orf/test_bgp_orf.py index 47c0556884..bc6a85b4b9 100644 --- a/tests/topotests/bgp_orf/test_bgp_orf.py +++ b/tests/topotests/bgp_orf/test_bgp_orf.py @@ -37,7 +37,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py index bd8cd8e18a..adc92f59fe 100644 --- a/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py +++ b/tests/topotests/bgp_path_attribute_discard/test_bgp_path_attribute_discard.py @@ -23,7 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_path_selection/test_bgp_path_selection.py b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py index 30083b4de2..d486a87e9c 100644 --- a/tests/topotests/bgp_path_selection/test_bgp_path_selection.py +++ b/tests/topotests/bgp_path_selection/test_bgp_path_selection.py @@ -57,7 +57,7 @@ def setup_module(mod): tgen.gears["r2"].cmd("ip address add dev vrf1 192.0.2.8/32") tgen.gears["r3"].cmd("ip address add dev vrf1 192.0.2.8/32") - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py index 9269826233..c6ee9aa73c 100644 --- a/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py +++ b/tests/topotests/bgp_peer_graceful_shutdown/test_bgp_peer_graceful_shutdown.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py index 5cbcd19be9..7d476b0538 100644 --- a/tests/topotests/bgp_peer_group/test_bgp_peer-group.py +++ b/tests/topotests/bgp_peer_group/test_bgp_peer-group.py @@ -47,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json index 22ec2c298b..483165c0f3 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-confed.json @@ -23,7 +23,7 @@ "recursive":true }, { - "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } diff --git a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json index facddcda46..638a825395 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json +++ b/tests/topotests/bgp_peer_type_multipath_relax/r1/prefix1-eBGP-iBGP.json @@ -23,7 +23,7 @@ "recursive":true }, { - "fib":true, + "duplicate":true, "ip":"10.0.3.2", "active":true } diff --git a/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf b/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf index 14c28ca906..593442a42a 100644 --- a/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf +++ b/tests/topotests/bgp_prefix_list_any/r1/bgpd.conf @@ -4,6 +4,10 @@ router bgp 65001 no bgp network import-check neighbor 192.168.1.2 remote-as external neighbor 2001:db8:1::2 remote-as external + neighbor 192.168.1.2 timers 3 10 + neighbor 192.168.1.2 timers connect 1 + neighbor 2001:db8:1::2 timers 3 10 + neighbor 2001:db8:1::2 timers connect 1 address-family ipv4 unicast network 192.168.0.1/32 no neighbor 2001:db8:1::2 activate diff --git a/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf b/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf index 733205928f..0de5bd3355 100644 --- a/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf +++ b/tests/topotests/bgp_prefix_list_any/r2/bgpd.conf @@ -6,6 +6,10 @@ router bgp 65002 no bgp network import-check neighbor 192.168.1.1 remote-as external neighbor 2001:db8:1::1 remote-as external + neighbor 192.168.1.1 timers 3 10 + neighbor 192.168.1.1 timers connect 1 + neighbor 2001:db8:1::1 timers 3 10 + neighbor 2001:db8:1::1 timers connect 1 address-family ipv4 unicast network 10.10.10.1/32 network 10.10.10.2/32 diff --git a/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py b/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py index 5d6440ce6a..1871d3efc8 100644 --- a/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py +++ b/tests/topotests/bgp_prefix_list_any/test_bgp_prefix_list_any.py @@ -33,7 +33,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py index 1e6e731a18..fca60e8cea 100644 --- a/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py +++ b/tests/topotests/bgp_prefix_sid/test_bgp_prefix_sid.py @@ -93,11 +93,11 @@ def _check_type1_r1(router, prefix, remoteLabel, labelIndex): return topotest.json_cmp(output, expected) test_func = functools.partial(_check_type1_r1, router, "3.0.0.1/32", 800001, 1) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router) test_func = functools.partial(_check_type1_r1, router, "3.0.0.2/32", 800002, 2) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_r1 in "{}"'.format(router) @@ -160,11 +160,11 @@ def _check_type1_peer2(prefix, label): return topotest.json_cmp(output, expected) test_func = functools.partial(_check_type1_peer2, "3.0.0.1/32", label=8001) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_peer2 in "{}"'.format("peer2") test_func = functools.partial(_check_type1_peer2, "3.0.0.2/32", label=8002) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert result is None, 'Failed _check_type1_peer2 in "{}"'.format("peer2") diff --git a/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py index d6b94329e4..cf0c9fea2e 100755 --- a/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py +++ b/tests/topotests/bgp_prefix_sid2/test_bgp_prefix_sid2.py @@ -90,7 +90,7 @@ def check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" check("r1", "show bgp ipv6 vpn 2001:1::/64 json", "r1/vpnv6_rib_entry1.json") diff --git a/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py b/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py index 08b70ae0da..614610ccd6 100644 --- a/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py +++ b/tests/topotests/bgp_redistribute_table/test_bgp_redistribute_table.py @@ -86,7 +86,7 @@ def _router_json_cmp_exact_filter(router, cmd, expected): json_output = json.loads(output) # filter out tableVersion, version, nhVrfId and vrfId - for route, attrs in json_output.items(): + for _, attrs in json_output.items(): for attr in attrs: if "table" in attr: attr.pop("table") diff --git a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py index 97366ebd53..b9d8ce6819 100644 --- a/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py +++ b/tests/topotests/bgp_reject_as_sets/test_bgp_reject_as_sets.py @@ -56,7 +56,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -114,19 +114,19 @@ def _bgp_announce_route_without_as_sets(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed bgp convergence in "{}"'.format(router) test_func = functools.partial( _bgp_has_aggregated_route_with_stripped_as_set, router ) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Failed to see an aggregated route in "{}"'.format(router) test_func = functools.partial(_bgp_announce_route_without_as_sets, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert ( result is None diff --git a/tests/topotests/bgp_remote_as_auto/__init__.py b/tests/topotests/bgp_remote_as_auto/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_remote_as_auto/r1/frr.conf b/tests/topotests/bgp_remote_as_auto/r1/frr.conf new file mode 100644 index 0000000000..2f1bcd275f --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r1/frr.conf @@ -0,0 +1,23 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! +int r1-eth1 + ip address 192.168.14.1/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.1.2 remote-as auto + neighbor 192.168.1.2 timers 1 3 + neighbor 192.168.1.2 timers connect 1 + neighbor 192.168.1.3 remote-as auto + neighbor 192.168.1.3 timers 1 3 + neighbor 192.168.1.3 timers connect 1 + neighbor r1-eth1 interface remote-as auto + neighbor r1-eth1 timers 1 3 + neighbor r1-eth1 timers connect 1 + address-family ipv4 unicast + network 10.0.0.1/32 + exit-address-family +! diff --git a/tests/topotests/bgp_remote_as_auto/r2/frr.conf b/tests/topotests/bgp_remote_as_auto/r2/frr.conf new file mode 100644 index 0000000000..f8d19a0bfd --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r2/frr.conf @@ -0,0 +1,10 @@ +! +int r2-eth0 + ip address 192.168.1.2/24 +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/r3/frr.conf b/tests/topotests/bgp_remote_as_auto/r3/frr.conf new file mode 100644 index 0000000000..fc6862764f --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r3/frr.conf @@ -0,0 +1,10 @@ +! +int r3-eth0 + ip address 192.168.1.3/24 +! +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as auto + neighbor 192.168.1.1 timers 1 3 + neighbor 192.168.1.1 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/r4/frr.conf b/tests/topotests/bgp_remote_as_auto/r4/frr.conf new file mode 100644 index 0000000000..e280a6c6e8 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/r4/frr.conf @@ -0,0 +1,10 @@ +! +int r4-eth0 + ip address 192.168.14.4/24 +! +router bgp 65004 + no bgp ebgp-requires-policy + neighbor r4-eth0 interface remote-as auto + neighbor r4-eth0 timers 1 3 + neighbor r4-eth0 timers connect 1 +! diff --git a/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py new file mode 100644 index 0000000000..1db6d98a42 --- /dev/null +++ b/tests/topotests/bgp_remote_as_auto/test_bgp_remote_as_auto.py @@ -0,0 +1,161 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +import os +import re +import sys +import json +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, get_topogen + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2", "r3"), "s2": ("r1", "r4")} + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_remote_as_auto(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + r4 = tgen.gears["r4"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json")) + expected = { + "peers": { + "r1-eth1": { + "hostname": "r4", + "remoteAs": 65004, + "localAs": 65001, + "state": "Established", + }, + "192.168.1.2": { + "hostname": "r2", + "remoteAs": 65001, + "localAs": 65001, + "state": "Established", + }, + "192.168.1.3": { + "hostname": "r3", + "remoteAs": 65003, + "localAs": 65001, + "state": "Established", + }, + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic iBGP/eBGP peerings" + + def _bgp_converge_internal(): + output = json.loads(r2.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "Local", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "internal", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_internal, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic iBGP peering" + + def _bgp_converge_external(): + output = json.loads(r3.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic eBGP peering" + + def _bgp_converge_external_unnumbered(): + output = json.loads(r4.vtysh_cmd("show bgp ipv4 unicast 10.0.0.1/32 json")) + expected = { + "paths": [ + { + "aspath": { + "string": "65001", + }, + "valid": True, + "peer": { + "hostname": "r1", + "type": "external", + }, + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge_external_unnumbered, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't see automatic unnumbered eBGP peering" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py index e48f81c53d..8b965a1614 100644 --- a/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py +++ b/tests/topotests/bgp_remove_private_as/test_bgp_remove_private_as.py @@ -32,7 +32,6 @@ import os import sys import json -import time import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -109,7 +108,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, f"{rname}/zebra.conf") ) diff --git a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py index d9402f2743..10896e2b22 100644 --- a/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py +++ b/tests/topotests/bgp_remove_private_as_route_map/test_bgp_remove_private_as_route_map.py @@ -10,7 +10,6 @@ """ import os -import re import sys import json import pytest @@ -23,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen def build_topo(tgen): @@ -41,7 +40,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py b/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py index ef7c94bbab..2e5592e2ab 100644 --- a/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py +++ b/tests/topotests/bgp_rmap_extcommunity_none/test_bgp_rmap_extcommunity_none.py @@ -43,7 +43,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -86,7 +86,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "BGP Converge failed" def _bgp_extcommunity_strip(router): @@ -111,7 +111,7 @@ def _bgp_extcommunity_strip(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_extcommunity_strip, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Failed to strip incoming extended communities from r2" diff --git a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py index 52fda695c3..9223cbd759 100644 --- a/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py +++ b/tests/topotests/bgp_roles_capability/test_bgp_roles_capability.py @@ -24,8 +24,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.bgpd] @@ -38,7 +37,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_BGP, "bgpd.conf") tgen.start_router() @@ -82,9 +81,7 @@ def test_correct_pair(tgen): check_r2_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( - check_r2_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r2_established, True, count=20, wait=3) assert success, "Session with r2 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -100,7 +97,7 @@ def test_role_pair_mismatch(tgen): router = tgen.gears["r3"] neighbor_ip = "192.168.3.1" check_r3_mismatch = functools.partial(check_role_mismatch, router, neighbor_ip) - success, result = topotest.run_and_expect(check_r3_mismatch, True, count=20, wait=3) + success, _ = topotest.run_and_expect(check_r3_mismatch, True, count=20, wait=3) assert success, "Session between r1 and r3 was not correctly closed" @@ -111,9 +108,7 @@ def test_single_role_advertising(tgen): check_r4_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( - check_r4_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r4_established, True, count=20, wait=3) assert success, "Session with r4 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -129,9 +124,7 @@ def test_single_role_receiving(tgen): check_r1_established = functools.partial( check_session_established, router, neighbor_ip ) - success, result = topotest.run_and_expect( - check_r1_established, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(check_r1_established, True, count=20, wait=3) assert success, "Session with r1 is not Established" neighbor_status = find_neighbor_status(router, neighbor_ip) @@ -145,7 +138,7 @@ def test_role_strict_mode(tgen): router = tgen.gears["r5"] neighbor_ip = "192.168.5.1" check_r5_mismatch = functools.partial(check_role_mismatch, router, neighbor_ip) - success, result = topotest.run_and_expect(check_r5_mismatch, True, count=20, wait=3) + success, _ = topotest.run_and_expect(check_r5_mismatch, True, count=20, wait=3) assert success, "Session between r1 and r5 was not correctly closed" diff --git a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py index b3715863b5..ffbf454ded 100644 --- a/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py +++ b/tests/topotests/bgp_roles_filtering/test_bgp_roles_filtering.py @@ -16,7 +16,6 @@ import json import os import sys -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -24,9 +23,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.bgp import verify_bgp_convergence_from_running_config -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.bgpd] @@ -39,7 +36,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_BGP, "bgpd.conf") tgen.start_router() @@ -69,9 +66,7 @@ def _routes_half_converged(): ] return output == expected - success, result = topotest.run_and_expect( - _routes_half_converged, True, count=20, wait=3 - ) + success, _ = topotest.run_and_expect(_routes_half_converged, True, count=20, wait=3) assert success, "Routes did not converged" routes_with_otc = list() diff --git a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py index d50d67b60e..94bf092c76 100644 --- a/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py +++ b/tests/topotests/bgp_route_aggregation/test_bgp_aggregation.py @@ -119,7 +119,7 @@ def setup_module(mod): # Api call verify whether BGP is converged ADDR_TYPES = check_address_types() - for addr_type in ADDR_TYPES: + for _ in ADDR_TYPES: BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error:" " {}".format( BGP_CONVERGENCE diff --git a/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py b/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py index f7a66fdad1..d791ef486b 100644 --- a/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py +++ b/tests/topotests/bgp_route_map_delay_timer/test_bgp_route_map_delay_timer.py @@ -32,7 +32,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf index 8b743bd320..11e57ca932 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf @@ -11,6 +11,8 @@ router bgp 65001 bgp router-id 10.10.10.1 no bgp ebgp-requires-policy neighbor 2001:db8::2 remote-as external + neighbor 2001:db8::2 timers 3 10 + neighbor 2001:db8::2 timers connect 1 address-family ipv6 unicast neighbor 2001:db8::2 activate neighbor 2001:db8::2 route-map r2 in diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf index 61c36d366b..abd0ab9a41 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf @@ -5,6 +5,8 @@ router bgp 65002 bgp router-id 10.10.10.2 no bgp ebgp-requires-policy neighbor 2001:db8::1 remote-as external + neighbor 2001:db8::1 timers 3 10 + neighbor 2001:db8::1 timers connect 1 address-family ipv6 unicast redistribute connected neighbor 2001:db8::1 activate diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py index 93a514bf6a..35ce092697 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -97,7 +97,7 @@ def _bgp_converge(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, "Can't match routes using ipv6 next-hop access-list" diff --git a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py index 2828796405..7116deaea4 100644 --- a/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py +++ b/tests/topotests/bgp_route_map_match_source_protocol/test_bgp_route_map_match_source_protocol.py @@ -22,7 +22,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py b/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py index 7dd63fdac0..6ffa078f0c 100644 --- a/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py +++ b/tests/topotests/bgp_route_map_match_tag_untagged/test_bgp_route_map_match_tag_untagged.py @@ -17,7 +17,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py index 8fe45a3498..5b5256f43d 100644 --- a/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py +++ b/tests/topotests/bgp_route_map_on_match_next/test_bgp_route_map_on_match_next.py @@ -42,7 +42,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -83,12 +83,12 @@ def _bgp_has_routes(router, metric, weight): # Check thst session is established test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "Failed bgp convergence on r2" # Check that metric is 0 and weight is 100 for the received prefix test_func = functools.partial(_bgp_has_routes, router2, 0, 100) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 0 and weight 100" # Update the route-map and add "on-match next" to entry 10 @@ -102,7 +102,7 @@ def _bgp_has_routes(router, metric, weight): # Check that metric is 20 and weight is 100 for the received prefix test_func = functools.partial(_bgp_has_routes, router2, 20, 100) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) assert result is None, "r2 does not receive routes with metric 20 and weight 100" diff --git a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py index 37082b484c..a6641348f7 100644 --- a/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py +++ b/tests/topotests/bgp_route_map_vpn_import/test_bgp_route_map_vpn_import.py @@ -24,7 +24,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] @@ -61,7 +60,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py b/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py index 673efc2c73..16afda8bcc 100644 --- a/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py +++ b/tests/topotests/bgp_route_origin_parser/test_bgp_route_origin_parser.py @@ -11,7 +11,6 @@ import os import sys -import json import pytest import functools diff --git a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py index 18b7831a4a..29d9842d59 100644 --- a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py +++ b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py @@ -44,7 +44,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py index f52b28a062..7b40bbdae8 100644 --- a/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py +++ b/tests/topotests/bgp_rpki_topo1/test_bgp_rpki_topo1.py @@ -44,7 +44,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py index 9984abaa85..5022a4a4a3 100644 --- a/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py +++ b/tests/topotests/bgp_rr_ibgp/test_bgp_rr_ibgp_topo1.py @@ -132,7 +132,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: output = router.vtysh_cmd("show ip route json", isjson=True) diff --git a/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py index db6dbc61d2..6983a35173 100644 --- a/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py +++ b/tests/topotests/bgp_sender_as_path_loop_detection/test_bgp_sender-as-path-loop-detection.py @@ -50,7 +50,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py index 85e7b9676d..63f1719e1d 100644 --- a/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py +++ b/tests/topotests/bgp_set_aspath_exclude/test_bgp_set_aspath_exclude.py @@ -46,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py index c0e19fa356..fe4eda60f5 100644 --- a/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py +++ b/tests/topotests/bgp_set_aspath_replace/test_bgp_set_aspath_replace.py @@ -48,7 +48,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py b/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py index 292cf70d36..e201ec9ff7 100644 --- a/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py +++ b/tests/topotests/bgp_set_local_preference_add_subtract/test_bgp_set_local-preference_add_subtract.py @@ -47,7 +47,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -100,12 +100,12 @@ def _bgp_check_local_preference(router): return topotest.json_cmp(output, expected) test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router) test_func = functools.partial(_bgp_check_local_preference, router) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see applied BGP local-preference in "{}"'.format( router diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py index 0131e12579..09eef51338 100755 --- a/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py +++ b/tests/topotests/bgp_snmp_mplsl3vpn/test_bgp_snmp_mplsvpn.py @@ -325,7 +325,6 @@ def router_interface_get_ifindex(router, interface): def generate_vrf_ifindex_oid(vrf, ifindex): - intoid = snmp_uint32_to_oid(int(ifindex)) vrfoid = snmp_str_to_oid(vrf) oid = "{}.{}".format(vrfoid, intoid) diff --git a/tests/topotests/bgp_software_version/test_bgp_software_version.py b/tests/topotests/bgp_software_version/test_bgp_software_version.py index c867208d39..9aff53a030 100644 --- a/tests/topotests/bgp_software_version/test_bgp_software_version.py +++ b/tests/topotests/bgp_software_version/test_bgp_software_version.py @@ -34,7 +34,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_soo/test_bgp_soo.py b/tests/topotests/bgp_soo/test_bgp_soo.py index 967bed0213..b0c70f208e 100644 --- a/tests/topotests/bgp_soo/test_bgp_soo.py +++ b/tests/topotests/bgp_soo/test_bgp_soo.py @@ -73,7 +73,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py index 92315bce04..f8385401c5 100755 --- a/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py +++ b/tests/topotests/bgp_srv6_sid_reachability/test_bgp_srv6_sid_reachability.py @@ -8,10 +8,7 @@ # import os -import re import sys -import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -19,9 +16,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from lib.common_config import required_linux_kernel_version from lib.checkping import check_ping diff --git a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py index 14b9ba8498..0b52c87d27 100755 --- a/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py +++ b/tests/topotests/bgp_srv6l3vpn_over_ipv6/test_bgp_srv6l3vpn_over_ipv6.py @@ -9,10 +9,7 @@ # import os -import re import sys -import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,9 +17,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from lib.common_config import required_linux_kernel_version from lib.checkping import check_ping diff --git a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py index f0c9144248..4bd5fdf165 100755 --- a/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py +++ b/tests/topotests/bgp_srv6l3vpn_route_leak/test_bgp_srv6l3vpn_route_leak.py @@ -6,10 +6,8 @@ # import os -import re import sys import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,7 +18,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py index 984cf97e28..8d303a774b 100755 --- a/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py +++ b/tests/topotests/bgp_srv6l3vpn_sid/test_bgp_srv6l3vpn_sid.py @@ -20,7 +20,6 @@ # import os -import re import sys import json import functools @@ -106,7 +105,7 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() router_list = tgen.routers() - for i, (rname, router) in enumerate(tgen.routers().items(), 1): + for _, (rname, router) in enumerate(tgen.routers().items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -180,7 +179,7 @@ def _check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py index 4afaeaf78a..a6938668ad 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/test_bgp_srv6l3vpn_to_bgp_vrf.py @@ -92,7 +92,8 @@ def setup_module(mod): tgen.start_topology() router_list = tgen.routers() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -147,7 +148,7 @@ def _check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py index 914c29f0c1..c47980744a 100755 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf2/test_bgp_srv6l3vpn_to_bgp_vrf2.py @@ -9,7 +9,6 @@ # import os -import re import sys import json import functools @@ -56,7 +55,8 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -109,7 +109,7 @@ def _check(name, dest_addr, match): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py index 8a7b558be3..2400cd2853 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf3/test_bgp_srv6l3vpn_to_bgp_vrf3.py @@ -53,7 +53,8 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() for rname, router in tgen.routers().items(): - router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) + if os.path.exists("{}/{}/setup.sh".format(CWD, rname)): + router.run("/bin/bash {}/{}/setup.sh".format(CWD, rname)) router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -106,7 +107,7 @@ def _check(name, dest_addr, match): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = functools.partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py index ec14ef065f..f7ac827e26 100644 --- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py +++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py @@ -15,7 +15,6 @@ import json import pytest from functools import partial -from time import sleep from lib.topolog import logger CWD = os.path.dirname(os.path.realpath(__file__)) @@ -47,7 +46,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py index 4855d5c7d2..37949cdc99 100644 --- a/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py +++ b/tests/topotests/bgp_tcp_mss/test_bgp_tcp_mss.py @@ -52,7 +52,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -108,7 +108,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): logger.info("Check if neighbor sessions are up in {}".format(router1.name)) test_func = functools.partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence in "{}"'.format(router1.name) logger.info("BGP neighbor session is up in {}".format(router1.name)) @@ -129,7 +129,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): "Check if neighbor session is up after reset in {}".format(router1.name) ) test_func = functools.partial(_bgp_converge, router1) - success, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=15, wait=0.5) assert result is None, 'Failed to see BGP convergence after reset in "{}"'.format( router1.name ) @@ -138,7 +138,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): "Verify if TCP MSS value is synced with neighbor in {}".format(router1.name) ) test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router1, "192.168.255.2") - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( result is None ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router1.name) @@ -148,7 +148,7 @@ def _bgp_check_neighbor_tcp_mss(router, neigh): "Verify if TCP MSS value is synced with neighbor in {}".format(router2.name) ) test_func = functools.partial(_bgp_check_neighbor_tcp_mss, router2, "192.168.255.1") - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( result is None ), 'Failed to sync TCP MSS value over BGP session in "{}"'.format(router2.name) diff --git a/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py b/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py index aeb9bf529d..4a03cb0a6d 100644 --- a/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py +++ b/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py @@ -17,12 +17,7 @@ import os import sys -import json import pytest -import functools -import platform -import socket -import subprocess # add after imports, before defining classes or functions: pytestmark = [pytest.mark.bgpd] @@ -31,43 +26,27 @@ sys.path.append(os.path.join(CWD, "../")) # pylint: disable=C0413 -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topojson import build_config_from_json -from lib.topolog import logger import time from lib.bgp import ( clear_bgp, - clear_bgp_and_verify, create_router_bgp, - modify_as_number, - verify_as_numbers, verify_bgp_convergence, verify_bgp_rib, - verify_bgp_timers_and_functionality, - verify_router_id, verify_tcp_mss, ) from lib.common_config import ( kill_router_daemons, start_router_daemons, - addKernelRoute, apply_raw_config, check_address_types, check_router_status, - create_prefix_lists, - create_route_maps, create_static_routes, required_linux_kernel_version, - reset_config_on_routers, start_topology, step, - verify_admin_distance_for_static_routes, - verify_bgp_community, - verify_fib_routes, - verify_rib, write_test_footer, - write_test_header, ) # Global variables diff --git a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py index cd405f7b22..44336efed2 100644 --- a/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py +++ b/tests/topotests/bgp_tcp_mss_passive/test_bgp_tcp_mss_passive.py @@ -21,7 +21,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.bgpd] @@ -41,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) tgen.start_router() diff --git a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py index 2a53547f59..09b13e6a2f 100644 --- a/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py +++ b/tests/topotests/bgp_unnumbered/test_bgp_unnumbered.py @@ -27,7 +27,6 @@ def build_topo(tgen): - tgen.add_router("r1") tgen.add_router("r2") @@ -42,7 +41,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -84,7 +83,7 @@ def _bgp_converge(): step("Ensure Convergence of BGP") test_func = functools.partial(_bgp_converge) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) assert result is None, 'Failed bgp convergence in "{}"'.format(tgen.gears["r2"]) @@ -109,7 +108,7 @@ def _bgp_converge(): step("Ensure that BGP does not crash") test_func = functools.partial(_bgp_nexthop_cache) - success, result = topotest.run_and_expect(test_func, True, count=10, wait=1) + _, result = topotest.run_and_expect(test_func, True, count=10, wait=1) assert result is True, "BGP did not crash on r1" diff --git a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py index 4e66cf5548..59f4bcd385 100644 --- a/tests/topotests/bgp_update_delay/test_bgp_update_delay.py +++ b/tests/topotests/bgp_update_delay/test_bgp_update_delay.py @@ -90,7 +90,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -169,7 +169,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): # Check r2 initial convergence in default table test_func = functools.partial(_bgp_converge, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed bgp convergence in "{}"'.format(router2) @@ -195,7 +195,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_update_delay_in_progress, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay max-delay timer "{}"'.format( router2 @@ -203,7 +203,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): # Check that r2 only installs route learned from r4 after the max-delay timer expires test_func = functools.partial(_bgp_check_route_install, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to install route after update-delay "{}"'.format( router2 @@ -219,7 +219,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): ) test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None @@ -229,7 +229,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router3) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None @@ -250,7 +250,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to remove update-delay delay timing "{}"'.format( router2 @@ -266,14 +266,14 @@ def _bgp_check_vrf_update_delay_and_wait(router): # Check that r2 default instance and vrf1 have the max-delay and establish set test_func = functools.partial(_bgp_check_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay in default instance "{}"'.format( router2 ) test_func = functools.partial(_bgp_check_vrf_update_delay_and_wait, router2) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert result is None, 'Failed to set update-delay in vrf1 "{}"'.format(router2) @@ -281,7 +281,7 @@ def _bgp_check_vrf_update_delay_and_wait(router): router2.vtysh_cmd("""clear ip bgp *""") test_func = functools.partial(_bgp_check_route_install, router3) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) assert ( result is None diff --git a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py index eb29875d50..08d6e140a1 100644 --- a/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py +++ b/tests/topotests/bgp_vpn_5549_route_map/test_bgp_vpn_5549_route_map.py @@ -22,7 +22,6 @@ # pylint: disable=C0413 from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step pytestmark = [pytest.mark.bgpd] @@ -67,7 +66,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) diff --git a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py index 39865eb189..5467cf4d84 100644 --- a/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py +++ b/tests/topotests/bgp_vpnv4_asbr/test_bgp_vpnv4_asbr.py @@ -203,7 +203,7 @@ def _check(router, prefix, rd, label, nexthop): ) func = functools.partial(_check, router, prefix, rd, label, nexthop) - success, result = topotest.run_and_expect(func, None, count=20, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=20, wait=0.5) assert_msg = "{}, show bgp ipv4 vpn {}, rd {}, label {} nexthop {}".format( router.name, prefix, rd, label, nexthop ) @@ -312,7 +312,7 @@ def _check_nexthop_available(router, prefix): return "{0}, {1}, route distinguisher not present".format( router.name, prefix ) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: if "remoteLabel" not in path.keys(): return "{0}, {1}, remoteLabel not present".format( @@ -324,7 +324,7 @@ def _check_nexthop_available(router, prefix): for prefix, rname_to_test in vpnv4_entries.items(): func = functools.partial(_check_nexthop_available, router, prefix) - success, result = topotest.run_and_expect(func, None, count=20, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=20, wait=0.5) assert result is None, "Failed to detect prefix {} on router {}".format( prefix, router.name ) @@ -456,7 +456,7 @@ def test_r3_prefixes_removed(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) # diagnostic @@ -491,7 +491,7 @@ def test_r3_prefixes_removed(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) logger.info( @@ -502,7 +502,7 @@ def test_r3_prefixes_removed(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, label_ip_entries[prefix] ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with in_label {} still present".format( label_ip_entries[prefix] ) @@ -536,7 +536,7 @@ def test_r3_prefixes_added_back(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} not present".format(router.name, prefix) logger.info( @@ -564,7 +564,7 @@ def test_r3_prefixes_added_back(): prefix, "444:3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} not present".format(router.name, prefix) # diagnostic @@ -611,7 +611,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, label ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry for {} with in_label {} still present".format( prefix, label ) @@ -626,7 +626,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): "444:3", label=label, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, mpls vpn update {} label {} is present".format( router.name, prefix, label ) @@ -639,7 +639,7 @@ def test_unconfigure_nexthop_change_nexthop_self(): "444:3", nexthop="192.168.1.3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, mpls vpn update {} label {} is present".format( router.name, prefix, label ) @@ -727,7 +727,7 @@ def test_declare_vpn_network_with_different_label(): label=label, nexthop="192.168.1.3", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, label {} not present".format( router.name, prefix, label ) @@ -787,7 +787,7 @@ def test_filter_vpn_network_from_r1(): "172.31.0.0/24", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, is still present".format( router.name, prefix ) @@ -804,7 +804,7 @@ def test_filter_vpn_network_from_r1(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, int(label) ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry for {} with in_label {} still present".format( prefix, label ) @@ -833,7 +833,7 @@ def test_unfilter_vpn_network_from_r1(): test_func = functools.partial( check_show_bgp_vpn_prefix_found, router, "ipv4", prefix, "444:1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {}, is not present".format(router.name, prefix) vpnv4_checks = { diff --git a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py index 189824311d..dd9d54742b 100644 --- a/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py +++ b/tests/topotests/bgp_vpnv4_ebgp/test_bgp_vpnv4_ebgp.py @@ -245,7 +245,7 @@ def test_export_route_target_empty(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) @@ -279,7 +279,7 @@ def test_export_route_target_with_routemap_with_export_route_target(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) @@ -309,7 +309,7 @@ def test_export_route_target_with_routemap_without_export_route_target(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) @@ -339,7 +339,7 @@ def test_export_route_target_with_default_command(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) @@ -371,7 +371,7 @@ def test_export_suppress_route_target_with_route_map_command(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still present".format(router.name, prefix) @@ -400,7 +400,7 @@ def test_export_add_route_target_to_route_map_command(): prefix, "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, vpnv4 update {} still not present".format(router.name, prefix) @@ -482,7 +482,7 @@ def test_adj_rib_in_label_change(): expected, exact=True, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.1 still present" diff --git a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py index 037dd40390..6237decfc3 100644 --- a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py +++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py @@ -141,7 +141,7 @@ def router_json_cmp_exact_filter(router, cmd, expected): # filter out tableVersion, version and nhVrfID json_output.pop("tableVersion") for rd, data in json_output["routes"]["routeDistinguishers"].items(): - for prefix, attrs in data.items(): + for _, attrs in data.items(): for attr in attrs: if "nhVrfId" in attr: attr.pop("nhVrfId") @@ -171,7 +171,7 @@ def router_vrf_json_cmp_exact_filter(router, cmd, expected): data.pop("tableVersion") if "routes" not in data: continue - for route, attrs in data["routes"].items(): + for _, attrs in data["routes"].items(): for attr in attrs: if "nhVrfId" in attr: attr.pop("nhVrfId") diff --git a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py index d4c355a44a..146687d588 100644 --- a/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv4_per_nexthop_label/test_bgp_vpnv4_per_nexthop_label.py @@ -151,17 +151,28 @@ def teardown_module(_mod): tgen.stop_topology() -def check_bgp_vpnv4_prefix_presence(router, prefix): +def check_bgp_vpnv4_prefix_presence(router, prefix, table_version): "Check the presence of a prefix" tgen = get_topogen() dump = router.vtysh_cmd("show bgp ipv4 vpn {} json".format(prefix), isjson=True) if not dump: return "{}, prefix ipv4 vpn {} is not installed yet".format(router.name, prefix) + + for _, paths in dump.items(): + for path in paths["paths"]: + new_version = path["version"] + if new_version <= table_version: + return "{}, prefix ipv4 vpn {} has not been updated yet".format( + router.name, prefix + ) + return None -def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=None): +def bgp_vpnv4_table_check( + router, group, label_list=None, label_value_expected=None, table_version=0 +): """ Dump and check that vpnv4 entries have the same MPLS label value * 'router': the router to check @@ -173,8 +184,10 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: - test_func = functools.partial(check_bgp_vpnv4_prefix_presence, router, prefix) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + test_func = functools.partial( + check_bgp_vpnv4_prefix_presence, router, prefix, table_version + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv4 vpn {} is not installed yet".format( router.name, prefix ) @@ -183,7 +196,7 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N assert dump, "{0}, {1}, route distinguisher not present".format( router.name, prefix ) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: assert ( "remoteLabel" in path.keys() @@ -218,7 +231,7 @@ def bgp_vpnv4_table_check(router, group, label_list=None, label_value_expected=N ) -def bgp_vpnv4_table_check_all(router, label_list=None, same=False): +def bgp_vpnv4_table_check_all(router, label_list=None, same=False, table_version=0): """ Dump and check that vpnv4 entries are correctly configured with specific label values * 'router': the router to check @@ -236,6 +249,7 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False): + PREFIXES_REDIST + PREFIXES_CONNECTED, label_list=label_list, + table_version=table_version, ) else: for group in ( @@ -245,7 +259,9 @@ def bgp_vpnv4_table_check_all(router, label_list=None, same=False): PREFIXES_REDIST, PREFIXES_CONNECTED, ): - bgp_vpnv4_table_check(router, group=group, label_list=label_list) + bgp_vpnv4_table_check( + router, group=group, label_list=label_list, table_version=table_version + ) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -350,6 +366,11 @@ def check_show_mpls_table_entry_label_not_found(router, inlabel): return None +def get_table_version(router): + table = router.vtysh_cmd("show bgp ipv4 vpn json", isjson=True) + return table["tableVersion"] + + def mpls_entry_get_interface(router, label): """ Assert that the label is in MPLS table @@ -450,7 +471,7 @@ def _bgp_prefix_not_found(router, vrf, ipversion, prefix): test_func = functools.partial( _bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv4", "172.31.0.11/32" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r1, prefix 172.31.0.11/32 from r11 did not disappear. r11 still connected to rr ?" @@ -488,7 +509,7 @@ def test_flapping_bgp_vrf_up(): "172.31.0.11/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, prefix 172.31.0.11/32 from r11 not present. r11 still disconnected from rr ?" @@ -518,7 +539,7 @@ def test_recursive_route(): "172.31.0.30/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.30 not found" bgp_vpnv4_table_check(tgen.gears["r2"], group=PREFIXES_R11 + ["172.31.0.30/32"]) @@ -544,7 +565,7 @@ def test_recursive_route(): "172.31.0.30/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.30 still present" @@ -570,7 +591,7 @@ def test_prefix_changes_interface(): "172.31.0.50/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.50 not found" # diagnostic @@ -616,7 +637,7 @@ def test_prefix_changes_interface(): "444:1", label=oldlabel, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, vpnv4 update 172.31.0.50 with old label {0} still present".format(oldlabel) @@ -633,7 +654,7 @@ def test_prefix_changes_interface(): "172.31.0.50/32", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv4 update 172.31.0.50 not found" label_list = set() @@ -686,6 +707,7 @@ def test_changing_default_label_value(): old_len != 1 ), "r1, number of labels used should be greater than 1, oberved {} ".format(old_len) + table_version = get_table_version(router) logger.info("r1, vrf1, changing the default MPLS label value to export to 222") router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nlabel vpn export 222\n", @@ -699,13 +721,13 @@ def test_changing_default_label_value(): test_func = functools.partial( check_show_mpls_table_entry_label_found, router, 222, "vrf1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 222 not found" # check label repartition is ok logger.info("r1, vpnv4 table, check the number of labels used after modification") label_list = set() - bgp_vpnv4_table_check_all(router, label_list) + bgp_vpnv4_table_check_all(router, label_list, table_version=table_version) new_len = len(label_list) assert ( old_len == new_len @@ -734,6 +756,7 @@ def test_unconfigure_allocation_mode_nexthop(): logger.info("Unconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + table_version = get_table_version(router) router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nno label vpn export allocation-mode per-nexthop\n", isjson=False, @@ -746,13 +769,15 @@ def test_unconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list, same=True) + bgp_vpnv4_table_check_all( + router, label_list=label_list, same=True, table_version=table_version + ) assert len(label_list) == 1, "r1, multiple Label values found for vpnv4 updates" new_label = label_list.pop() @@ -782,6 +807,8 @@ def test_reconfigure_allocation_mode_nexthop(): logger.info("Reconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + + table_version = get_table_version(router) router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv4 unicast\nlabel vpn export allocation-mode per-nexthop\n", isjson=False, @@ -794,13 +821,15 @@ def test_reconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv4 routes from r1 logger.info("Checking vpnv4 routes on r1") label_list = set() - bgp_vpnv4_table_check_all(router, label_list=label_list) + bgp_vpnv4_table_check_all( + router, label_list=label_list, table_version=table_version + ) assert len(label_list) != 1, "r1, only 1 label values found for vpnv4 updates" # Check mpls table with all values diff --git a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py index 3d5f8f643b..5fef6e9e60 100644 --- a/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py +++ b/tests/topotests/bgp_vpnv6_per_nexthop_label/test_bgp_vpnv6_per_nexthop_label.py @@ -150,17 +150,28 @@ def teardown_module(_mod): tgen.stop_topology() -def check_bgp_vpnv6_prefix_presence(router, prefix): +def check_bgp_vpnv6_prefix_presence(router, prefix, table_version): "Check the presence of a prefix" tgen = get_topogen() dump = router.vtysh_cmd("show bgp ipv6 vpn {} json".format(prefix), isjson=True) if not dump: return "{}, prefix ipv6 vpn {} is not installed yet".format(router.name, prefix) + + for _, paths in dump.items(): + for path in paths["paths"]: + new_version = path["version"] + if new_version <= table_version: + return "{}, prefix ipv6 vpn {} has not been updated yet".format( + router.name, prefix + ) + return None -def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=None): +def bgp_vpnv6_table_check( + router, group, label_list=None, label_value_expected=None, table_version=0 +): """ Dump and check that vpnv6 entries have the same MPLS label value * 'router': the router to check @@ -172,14 +183,16 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N stored_label_inited = False for prefix in group: - test_func = functools.partial(check_bgp_vpnv6_prefix_presence, router, prefix) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + test_func = functools.partial( + check_bgp_vpnv6_prefix_presence, router, prefix, table_version + ) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "{}, prefix ipv6 vpn {} is not installed yet".format( router.name, prefix ) dump = router.vtysh_cmd("show bgp ipv6 vpn {} json".format(prefix), isjson=True) - for rd, pathes in dump.items(): + for _, pathes in dump.items(): for path in pathes["paths"]: assert ( "remoteLabel" in path.keys() @@ -214,7 +227,7 @@ def bgp_vpnv6_table_check(router, group, label_list=None, label_value_expected=N ) -def bgp_vpnv6_table_check_all(router, label_list=None, same=False): +def bgp_vpnv6_table_check_all(router, label_list=None, same=False, table_version=0): """ Dump and check that vpnv6 entries are correctly configured with specific label values * 'router': the router to check @@ -231,6 +244,7 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False): + PREFIXES_REDIST_R14 + PREFIXES_CONNECTED, label_list=label_list, + table_version=table_version, ) else: for group in ( @@ -239,7 +253,9 @@ def bgp_vpnv6_table_check_all(router, label_list=None, same=False): PREFIXES_REDIST_R14, PREFIXES_CONNECTED, ): - bgp_vpnv6_table_check(router, group=group, label_list=label_list) + bgp_vpnv6_table_check( + router, group=group, label_list=label_list, table_version=table_version + ) def check_show_mpls_table(router, blacklist=None, label_list=None, whitelist=None): @@ -345,6 +361,11 @@ def check_show_mpls_table_entry_label_not_found(router, inlabel): return None +def get_table_version(router): + table = router.vtysh_cmd("show bgp ipv6 vpn json", isjson=True) + return table["tableVersion"] + + def mpls_entry_get_interface(router, label): """ Assert that the label is in MPLS table @@ -446,7 +467,7 @@ def _bgp_prefix_not_found(router, vrf, ipversion, prefix): test_func = functools.partial( _bgp_prefix_not_found, tgen.gears["r1"], "vrf1", "ipv6", "172:31::11/128" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r1, prefix 172:31::11/128 from r11 did not disappear. r11 still connected to rr ?" @@ -488,7 +509,7 @@ def test_flapping_bgp_vrf_up(): "172:31::11/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, prefix 172:31::11/128 from r11 not present. r11 still disconnected from rr ?" @@ -526,7 +547,7 @@ def _prefix30_found(router): # Check r2 received vpnv6 update with 172:31::30 test_func = functools.partial(_prefix30_found, tgen.gears["r2"]) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::30 not found" # that route should be sent along with label for 192::2:11 @@ -549,7 +570,7 @@ def _prefix30_found(router): # Check r2 removed 172:31::30 vpnv6 update test_func = functools.partial(_prefix30_not_found, tgen.gears["r2"]) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::30 still present" @@ -575,7 +596,7 @@ def test_prefix_changes_interface(): "172:31::50/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, VPNv6 update 172:31::50 not found" # diagnostic @@ -621,7 +642,7 @@ def test_prefix_changes_interface(): "444:1", label=oldlabel, ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert ( success ), "r2, vpnv6 update 172:31::50 with old label {0} still present".format(oldlabel) @@ -638,7 +659,7 @@ def test_prefix_changes_interface(): "172:31::50/128", "444:1", ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r2, vpnv6 update 172:31::50 not found" label_list = set() @@ -691,6 +712,7 @@ def test_changing_default_label_value(): old_len != 1 ), "r1, number of labels used should be greater than 1, oberved {} ".format(old_len) + table_version = get_table_version(router) logger.info("r1, vrf1, changing the default MPLS label value to export to 222") router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export 222\n", @@ -704,13 +726,13 @@ def test_changing_default_label_value(): test_func = functools.partial( check_show_mpls_table_entry_label_found, router, 222, "vrf1" ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 222 not found" # check label repartition is ok logger.info("r1, VPNv6 table, check the number of labels used after modification") label_list = set() - bgp_vpnv6_table_check_all(router, label_list) + bgp_vpnv6_table_check_all(router, label_list, table_version=table_version) new_len = len(label_list) assert ( old_len == new_len @@ -750,7 +772,7 @@ def test_unconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv6 routes from r1 @@ -786,6 +808,7 @@ def test_reconfigure_allocation_mode_nexthop(): logger.info("Reconfiguring allocation mode per nexthop") router = tgen.gears["r1"] + table_version = get_table_version(router) dump = router.vtysh_cmd( "configure terminal\nrouter bgp 65500 vrf vrf1\naddress-family ipv6 unicast\nlabel vpn export allocation-mode per-nexthop\n", isjson=False, @@ -798,13 +821,15 @@ def test_reconfigure_allocation_mode_nexthop(): test_func = functools.partial( check_show_mpls_table_entry_label_not_found, router, 17 ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) assert success, "r1, mpls entry with label 17 still present" # Check vpnv6 routes from r1 logger.info("Checking VPNv6 routes on r1") label_list = set() - bgp_vpnv6_table_check_all(router, label_list=label_list) + bgp_vpnv6_table_check_all( + router, label_list=label_list, table_version=table_version + ) assert len(label_list) != 1, "r1, only 1 label values found for VPNv6 updates" # Check mpls table with all values diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py index 32643c27b8..8d73e5f8ac 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak/test_bgp_vrf_dynamic_route_leak_topo2.py @@ -18,7 +18,6 @@ import os import sys -import json import time import pytest import platform @@ -58,7 +57,7 @@ verify_best_path_as_per_bgp_attribute, verify_bgp_rib, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py index 726afcb6ae..25a73b58c7 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo3/test_bgp_vrf_dynamic_route_leak_topo3.py @@ -23,7 +23,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -49,7 +48,6 @@ create_static_routes, create_prefix_lists, create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py index 45d7b0309e..53f0239c4d 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-1.py @@ -24,7 +24,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py index d29edf59b8..7b0eac3f74 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-2.py @@ -24,7 +24,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py index c118ffc090..ec7b25c7cc 100644 --- a/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py +++ b/tests/topotests/bgp_vrf_dynamic_route_leak_topo4/test_bgp_vrf_dynamic_route_leak_topo4-3.py @@ -24,7 +24,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -46,18 +45,13 @@ reset_config_on_routers, verify_rib, step, - create_route_maps, create_static_routes, - create_prefix_lists, - create_bgp_community_lists, - get_frr_ipv6_linklocal, ) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py b/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py index b20819264d..3539d06ac3 100755 --- a/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py +++ b/tests/topotests/bgp_vrf_leaking_5549_routes/test_bgp_vrf_leaking.py @@ -6,10 +6,8 @@ # import os -import re import sys import json -import functools import pytest CWD = os.path.dirname(os.path.realpath(__file__)) @@ -20,7 +18,6 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version pytestmark = [pytest.mark.bgpd] diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py index f3521969d3..3790446dc9 100644 --- a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py @@ -49,9 +49,7 @@ from lib.bgp import ( verify_bgp_convergence, create_router_bgp, - verify_bgp_community, verify_bgp_rib, - clear_bgp, verify_best_path_as_per_bgp_attribute, ) from lib.topojson import build_config_from_json diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py index 3cb31809fe..262cacd147 100644 --- a/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py @@ -19,7 +19,6 @@ import time import pytest import platform -from time import sleep # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/__init__.py b/tests/topotests/bgp_weighted_ecmp_recursive/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf new file mode 100644 index 0000000000..f7c591f75f --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r1/frr.conf @@ -0,0 +1,16 @@ +! +int r1-eth0 + ip address 192.168.12.1/24 +! +int r1-eth1 + ip address 192.168.13.1/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.12.2 remote-as internal + neighbor 192.168.12.2 timers 1 3 + neighbor 192.168.12.2 timers connect 1 + neighbor 192.168.13.3 remote-as internal + neighbor 192.168.13.3 timers 1 3 + neighbor 192.168.13.3 timers connect 1 +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf new file mode 100644 index 0000000000..dc25d4781c --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r2/frr.conf @@ -0,0 +1,20 @@ +! +int r2-eth0 + ip address 192.168.12.2/24 +! +int r2-eth1 + ip address 192.168.24.2/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.12.1 remote-as internal + neighbor 192.168.12.1 timers 1 3 + neighbor 192.168.12.1 timers connect 1 + neighbor 192.168.24.4 remote-as internal + neighbor 192.168.24.4 timers 1 3 + neighbor 192.168.24.4 timers connect 1 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.12.1 route-reflector-client + exit-address-family +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf new file mode 100644 index 0000000000..bdeb35b50f --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r3/frr.conf @@ -0,0 +1,20 @@ +! +int r3-eth0 + ip address 192.168.13.3/24 +! +int r3-eth1 + ip address 192.168.35.3/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + neighbor 192.168.13.1 remote-as internal + neighbor 192.168.13.1 timers 1 3 + neighbor 192.168.13.1 timers connect 1 + neighbor 192.168.35.5 remote-as internal + neighbor 192.168.35.5 timers 1 3 + neighbor 192.168.35.5 timers connect 1 + address-family ipv4 unicast + redistribute connected + neighbor 192.168.13.1 route-reflector-client + exit-address-family +! diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf new file mode 100644 index 0000000000..0662a4dc49 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r4/frr.conf @@ -0,0 +1,17 @@ +! +int r4-eth0 + ip address 192.168.24.4/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.24.2 remote-as internal + neighbor 192.168.24.2 timers 1 3 + neighbor 192.168.24.2 timers connect 1 + address-family ipv4 unicast + network 10.10.10.10/32 route-map rmap + exit-address-family +! +route-map rmap permit 10 + set extcommunity bandwidth 4000 +exit diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf b/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf new file mode 100644 index 0000000000..bc24a96b51 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/r5/frr.conf @@ -0,0 +1,17 @@ +! +int r5-eth0 + ip address 192.168.35.5/24 +! +router bgp 65000 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 192.168.35.3 remote-as internal + neighbor 192.168.35.3 timers 1 3 + neighbor 192.168.35.3 timers connect 1 + address-family ipv4 unicast + network 10.10.10.10/32 route-map rmap + exit-address-family +! +route-map rmap permit 10 + set extcommunity bandwidth 5000 +exit diff --git a/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py b/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py new file mode 100644 index 0000000000..7a6d068e56 --- /dev/null +++ b/tests/topotests/bgp_weighted_ecmp_recursive/test_bgp_weighted_ecmp_recursive.py @@ -0,0 +1,109 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# Copyright (c) 2024 by +# Donatas Abraitis +# + +""" +Test if weighted ECMP works and recursive weight (link bandwidth) is +inherited to non-recursive next-hops. +""" + +import os +import re +import sys +import json +import pytest +import functools + +pytestmark = [pytest.mark.bgpd] + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.common_config import step + + +def setup_module(mod): + topodef = { + "s1": ("r1", "r2"), + "s2": ("r1", "r3"), + "s3": ("r2", "r4"), + "s4": ("r3", "r5"), + } + tgen = Topogen(topodef, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for _, (rname, router) in enumerate(router_list.items(), 1): + router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname))) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_weighted_ecmp_recursive(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + + def _bgp_converge(): + output = json.loads(r1.vtysh_cmd("show ip route 10.10.10.10/32 json")) + expected = { + "10.10.10.10/32": [ + { + "selected": True, + "installed": True, + "nexthops": [ + { + "ip": "192.168.24.4", + "active": True, + "recursive": True, + "weight": 204, + }, + { + "ip": "192.168.12.2", + "active": True, + "resolver": True, + "weight": 204, + }, + { + "ip": "192.168.35.5", + "active": True, + "recursive": True, + "weight": 255, + }, + { + "ip": "192.168.13.3", + "active": True, + "resolver": True, + "weight": 255, + }, + ], + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial( + _bgp_converge, + ) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert result is None, "Can't converge" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/eigrp_topo1/test_eigrp_topo1.py b/tests/topotests/eigrp_topo1/test_eigrp_topo1.py index b3152f43bc..7ab1572dae 100644 --- a/tests/topotests/eigrp_topo1/test_eigrp_topo1.py +++ b/tests/topotests/eigrp_topo1/test_eigrp_topo1.py @@ -143,7 +143,6 @@ def test_zebra_ipv4_routingTable(): if tgen.routers_have_failure(): pytest.skip(tgen.errors) - failures = 0 router_list = tgen.routers().values() for router in router_list: output = router.vtysh_cmd("show ip route json", isjson=True) diff --git a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py index 10d216ab1e..beb4de432e 100644 --- a/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py +++ b/tests/topotests/evpn_type5_test_topo1/test_evpn_type5_topo1.py @@ -22,7 +22,6 @@ import os import sys -import json import time import pytest import platform @@ -69,7 +68,7 @@ verify_attributes_for_evpn_routes, verify_evpn_routes, ) -from lib.topojson import build_topo_from_json, build_config_from_json +from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] diff --git a/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py b/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py index 22fc50b914..66cefcc2a0 100644 --- a/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py +++ b/tests/topotests/fpm_testing_topo1/test_fpm_topo1.py @@ -14,7 +14,6 @@ """ import os -import re import sys import pytest import json @@ -28,7 +27,6 @@ # Import topogen and topotest helpers from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger pytestmark = [pytest.mark.fpm, pytest.mark.sharpd] diff --git a/tests/topotests/grpc_basic/test_basic_grpc.py b/tests/topotests/grpc_basic/test_basic_grpc.py index cf1c6d0ec7..5ff2894fd1 100644 --- a/tests/topotests/grpc_basic/test_basic_grpc.py +++ b/tests/topotests/grpc_basic/test_basic_grpc.py @@ -19,7 +19,6 @@ from lib.common_config import step from lib.micronet import commander from lib.topogen import Topogen, TopoRouter -from lib.topolog import logger from lib.topotest import json_cmp CWD = os.path.dirname(os.path.realpath(__file__)) @@ -60,7 +59,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf", f"-M grpc:{GRPCP_ZEBRA}") router.load_config(TopoRouter.RD_STATIC, "", f"-M grpc:{GRPCP_STATICD}") # router.load_config(TopoRouter.RD_BFDD, "", f"-M grpc:{GRPCP_BFDD}") diff --git a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py index ada8c0f5fb..ad896b7422 100644 --- a/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py +++ b/tests/topotests/isis_advertise_high_metrics/test_isis_advertise_high_metrics.py @@ -30,8 +30,6 @@ import sys import pytest import json -from time import sleep -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -39,7 +37,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest from lib.common_config import ( retry, stop_router, diff --git a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py index 44b3dd0b79..af28dbdf3c 100755 --- a/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py +++ b/tests/topotests/isis_lfa_topo1/test_isis_lfa_topo1.py @@ -42,7 +42,6 @@ import sys import pytest import json -import time import tempfile from functools import partial @@ -169,7 +168,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -832,7 +831,7 @@ def _rt2_neigh_down(router): rname = "rt1" router = tgen.gears[rname] test_func = partial(_rt2_neigh_down, router) - success, result = topotest.run_and_expect(test_func, None, count=200, wait=0.05) + _, result = topotest.run_and_expect(test_func, None, count=200, wait=0.05) assert result is None, 'rt2 neighbor is still present on "{}"'.format(router) router_compare_json_output( @@ -1034,7 +1033,7 @@ def _bfd_down(router): rname = "rt1" router = tgen.gears[rname] test_func = partial(_bfd_down, router) - success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.3) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=0.3) assert result is None, 'BFD session is still up on "{}"'.format(router) router_compare_json_output( diff --git a/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py b/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py index c4ce6a30cd..6f4653d2c2 100755 --- a/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py +++ b/tests/topotests/isis_lsp_bits_topo1/test_isis_lsp_bits_topo1.py @@ -131,7 +131,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py b/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py index 15327fe03a..f97c7d2c9c 100755 --- a/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py +++ b/tests/topotests/isis_rlfa_topo1/test_isis_rlfa_topo1.py @@ -170,7 +170,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_snmp/test_isis_snmp.py b/tests/topotests/isis_snmp/test_isis_snmp.py index ddef08008b..81c96b3daf 100755 --- a/tests/topotests/isis_snmp/test_isis_snmp.py +++ b/tests/topotests/isis_snmp/test_isis_snmp.py @@ -147,7 +147,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py b/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py index c81f63942b..d1fc68291e 100755 --- a/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py +++ b/tests/topotests/isis_sr_flex_algo_topo1/test_isis_sr_flex_algo_topo1.py @@ -37,7 +37,6 @@ import sys import pytest import json -import tempfile from copy import deepcopy from functools import partial @@ -121,7 +120,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py index 6689cf4c5e..7d063910d0 100755 --- a/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py +++ b/tests/topotests/isis_sr_flex_algo_topo2/test_isis_sr_flex_algo_topo2.py @@ -47,7 +47,6 @@ import sys import pytest import json -import time from functools import partial # Save the Current Working Directory to find configuration files. @@ -67,7 +66,6 @@ def build_topo(tgen): "Build function" - routers = [] for i in range(0, 10): rt = tgen.add_router("rt{}".format(i)) rt.run("sysctl -w net.ipv4.fib_multipath_hash_policy=1") @@ -140,7 +138,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -174,7 +172,7 @@ def _check(name, cmd, expected_file): logger.info('[+] check {} "{}" {}'.format(name, cmd, expected_file)) tgen = get_topogen() func = partial(_check, name, cmd, expected_file) - success, result = topotest.run_and_expect(func, None, count=120, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=120, wait=0.5) assert result is None, "Failed" diff --git a/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py b/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py index fc2ce7cb4b..cb4f4ffa56 100755 --- a/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py +++ b/tests/topotests/isis_sr_te_topo1/test_isis_sr_te_topo1.py @@ -164,7 +164,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -641,7 +641,7 @@ def test_srte_route_map_with_sr_policy_check_nextop_step5(): ) # (re-)build the SR Policy two times to ensure that reinstalling still works - for i in [1, 2]: + for _ in [1, 2]: cmp_json_output( "rt1", "show ip route bgp json", "step5/show_ip_route_bgp_inactive_srte.ref" ) diff --git a/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py b/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py index 9a4085ab55..baf7e98ba1 100644 --- a/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py +++ b/tests/topotests/isis_sr_topo1/test_isis_sr_topo1.py @@ -137,7 +137,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref index bb10aba942..c4a5d7507b 100644 --- a/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt1/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:1::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref index f3399319f3..f8a5d93f3c 100644 --- a/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt2/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:2::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref index ffa626123d..c62870587b 100644 --- a/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt3/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:3::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref index 189943f737..cb052dbbb5 100644 --- a/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt4/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:4::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref index 54780fce8a..ec55f24d7b 100644 --- a/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt5/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:5::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step1/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step2/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step3/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step4/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step5/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step6/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step7/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step8/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref index 35aa61d8e6..abcdeddea4 100644 --- a/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref +++ b/tests/topotests/isis_srv6_topo1/rt6/step9/show_srv6_locator_table.ref @@ -9,10 +9,6 @@ "argumentBitsLength":0, "statusUp":true, "chunks":[ - { - "prefix":"fc00:0:6::/48", - "proto":"isis" - } ] } ] diff --git a/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py index 1a7505dd12..9c1a23f54f 100644 --- a/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py +++ b/tests/topotests/isis_srv6_topo1/test_isis_srv6_topo1.py @@ -60,7 +60,6 @@ """ import os -import re import sys import json import functools @@ -212,7 +211,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" # Teardown the topology @@ -250,7 +249,7 @@ def _check(name, dest_addr, match): logger.info("[+] check {} {} {}".format(name, dest_addr, match)) tgen = get_topogen() func = functools.partial(_check, name, dest_addr, match) - success, result = topotest.run_and_expect(func, None, count=10, wait=1) + _, result = topotest.run_and_expect(func, None, count=10, wait=1) assert result is None, "Failed" diff --git a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py index aaf6af0be4..c8e66befa5 100755 --- a/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py +++ b/tests/topotests/isis_tilfa_topo1/test_isis_tilfa_topo1.py @@ -54,7 +54,6 @@ import sys import pytest import json -import tempfile from functools import partial from time import sleep @@ -144,7 +143,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/isis_topo1/r1/r1_topology.json b/tests/topotests/isis_topo1/r1/r1_topology.json index 337d6bf5ef..6b3374cc4d 100644 --- a/tests/topotests/isis_topo1/r1/r1_topology.json +++ b/tests/topotests/isis_topo1/r1/r1_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r1" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r2/r2_topology.json b/tests/topotests/isis_topo1/r2/r2_topology.json index de90fb5a32..8720bc1cac 100644 --- a/tests/topotests/isis_topo1/r2/r2_topology.json +++ b/tests/topotests/isis_topo1/r2/r2_topology.json @@ -1,96 +1,98 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r2" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r3/r3_topology.json b/tests/topotests/isis_topo1/r3/r3_topology.json index 2d36f9b427..568b6dfeed 100644 --- a/tests/topotests/isis_topo1/r3/r3_topology.json +++ b/tests/topotests/isis_topo1/r3/r3_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.254.0.1/32" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "metric": "10", - "interface": "r3-eth0", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::1/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.254.0.1/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "metric": 10, + "interface": "r3-eth0", + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::1/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r4/r4_topology.json b/tests/topotests/isis_topo1/r4/r4_topology.json index e7d7841912..9a53955cc9 100644 --- a/tests/topotests/isis_topo1/r4/r4_topology.json +++ b/tests/topotests/isis_topo1/r4/r4_topology.json @@ -1,194 +1,196 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.254.0.5/32" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::5/128" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "type": "TE-IS", - "vertex": "r3" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.254.0.2/32" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "metric": "10", - "interface": "r4-eth0", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::2/128" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.254.0.5/32" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::5/128" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + } + ] + }, + "level-2": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.254.0.2/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "metric": 10, + "interface": "r4-eth0", + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::2/128" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1/r5/r5_topology.json b/tests/topotests/isis_topo1/r5/r5_topology.json index 3d887b7cea..64590d8eb2 100644 --- a/tests/topotests/isis_topo1/r5/r5_topology.json +++ b/tests/topotests/isis_topo1/r5/r5_topology.json @@ -1,156 +1,154 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.254.0.3/32" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.254.0.4/32" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.254.0.3/32" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.254.0.4/32" + } + ], + "ipv6-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::3/128" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:f::4/128" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::3/128" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:f::4/128" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index b388f52bd9..a574f43d89 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -104,7 +104,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() @@ -120,19 +120,13 @@ def test_isis_convergence(): pytest.skip(tgen.errors) logger.info("waiting for ISIS protocol to converge") - # Code to generate the json files. - # for rname, router in tgen.routers().items(): - # open('/tmp/{}_topology.json'.format(rname), 'w').write( - # json.dumps(show_isis_topology(router), indent=2, sort_keys=True) - # ) - for rname, router in tgen.routers().items(): filename = "{0}/{1}/{1}_topology.json".format(CWD, rname) expected = json.loads(open(filename).read()) def compare_isis_topology(router, expected): "Helper function to test ISIS topology convergence." - actual = show_isis_topology(router) + actual = json.loads(router.vtysh_cmd("show isis topology json")) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -160,7 +154,7 @@ def compare_isis_installed_routes(router, expected): return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_installed_routes, router, expected) - (result, diff) = topotest.run_and_expect(test_func, None, wait=1, count=10) + (result, _) = topotest.run_and_expect(test_func, None, wait=1, count=10) assertmsg = "Router '{}' routes mismatch".format(rname) assert result, assertmsg @@ -205,7 +199,7 @@ def compare_isis_v6_installed_routes(router, expected): test_func = functools.partial( compare_isis_v6_installed_routes, router, expected ) - (result, diff) = topotest.run_and_expect(test_func, None, wait=1, count=10) + (result, _) = topotest.run_and_expect(test_func, None, wait=1, count=10) assertmsg = "Router '{}' routes mismatch".format(rname) assert result, assertmsg @@ -237,7 +231,7 @@ def test_isis_summary_json(): pytest.skip(tgen.errors) logger.info("Checking 'show isis summary json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd("show isis summary json", isjson=True) assertmsg = "Test isis summary json failed in '{}' data '{}'".format( @@ -257,7 +251,7 @@ def test_isis_interface_json(): pytest.skip(tgen.errors) logger.info("Checking 'show isis interface json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis interface json", isjson=True @@ -294,7 +288,7 @@ def test_isis_neighbor_json(): # tgen.mininet_cli() logger.info("Checking 'show isis neighbor json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis neighbor json", isjson=True @@ -330,7 +324,7 @@ def test_isis_database_json(): # tgen.mininet_cli() logger.info("Checking 'show isis database json'") - for rname, router in tgen.routers().items(): + for rname, _ in tgen.routers().items(): logger.info("Checking router %s", rname) json_output = tgen.gears[rname].vtysh_cmd( "show isis database json", isjson=True @@ -685,6 +679,9 @@ def _check_lsp_overload_bit(router, overloaded_router_lsp, att_p_ol_expected): ) database_json = json.loads(isis_database_output) + if "lsps" not in database_json["areas"][0]["levels"][1]: + return "The LSP of {} has not been synchronized yet ".format(router.name) + att_p_ol = database_json["areas"][0]["levels"][1]["lsps"][0]["attPOl"] if att_p_ol == att_p_ol_expected: return True @@ -755,7 +752,7 @@ def dict_merge(dct, merge_dct): Source: https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 """ - for k, v in merge_dct.items(): + for k, _ in merge_dct.items(): if k in dct and isinstance(dct[k], dict) and topotest.is_mapping(merge_dct[k]): dict_merge(dct[k], merge_dct[k]) else: @@ -845,52 +842,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-1") - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis topology level-2") - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 diff --git a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json index 666fa52b19..da537c552b 100644 --- a/tests/topotests/isis_topo1_vrf/r1/r1_topology.json +++ b/tests/topotests/isis_topo1_vrf/r1/r1_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r1" - } - ], - "ipv6": [ - { - "vertex": "r1" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - } - ], - "ipv6": [ - { - "vertex": "r1" - }, - { - "metric": "0", - "parent": "r1(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r1-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r1(4)", - "type": "TE-IS", - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r1" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + } + ] }, - { - "metric": "10", - "interface": "r1-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r1" + }, + { + "metric": 0, + "parent": "r1(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r1-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r1(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 10, + "interface": "r1-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json index c26ad1ee37..bf965659be 100644 --- a/tests/topotests/isis_topo1_vrf/r2/r2_topology.json +++ b/tests/topotests/isis_topo1_vrf/r2/r2_topology.json @@ -1,80 +1,82 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r2" - } - ], - "ipv6": [ - { - "vertex": "r2" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - } - ], - "ipv6": [ - { - "vertex": "r2" - }, - { - "metric": "0", - "parent": "r2(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r2-eth0", - "metric": "10", - "next-hop": "r4", - "parent": "r2(4)", - "type": "TE-IS", - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r2" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + } + ] }, - { - "metric": "10", - "interface": "r2-eth0", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r2" + }, + { + "metric": 0, + "parent": "r2(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r2-eth0", + "metric": 10, + "nextHop": "r4", + "parent": "r2(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r2-eth0", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json index 044a6c0438..94592b50a7 100644 --- a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json +++ b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r3" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r3-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r3-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 20, + "interface": "r3-eth1", + "nextHop": "r5", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + } + ] }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r3-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "interface": "r3-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "metric": "20", - "interface": "r3-eth1", - "next-hop": "r5", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP internal", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r1(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r3" - }, - { - "metric": "0", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "interface": "r3-eth0", - "metric": "10", - "next-hop": "r1", - "parent": "r3(4)", - "type": "TE-IS", - "vertex": "r1" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP internal", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r1(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r3" + }, + { + "metric": 0, + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "interface": "r3-eth0", + "metric": 10, + "nextHop": "r1", + "parent": "r3(4)", + "type": "TE-IS", + "vertex": "r1" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json index d40008aa30..b8295e87b9 100644 --- a/tests/topotests/isis_topo1_vrf/r4/r4_topology.json +++ b/tests/topotests/isis_topo1_vrf/r4/r4_topology.json @@ -1,132 +1,148 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r4" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r4-eth1", + "metric": 10, + "nextHop": "r5", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r5" + }, + { + "metric": 10, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "interface": "r4-eth1", + "metric": 20, + "nextHop": "r5", + "type": "TE-IS", + "vertex": "r3" + }, + { + "metric": 20, + "interface": "r4-eth1", + "nextHop": "r5", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + } + ] }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r4-eth1", - "metric": "20", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r4-eth1", - "metric": "10", - "next-hop": "r5", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r5" - }, - { - "metric": "10", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "20", - "interface": "r4-eth1", - "next-hop": "r5", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - } - ] - }, - "level-2": { - "ipv4": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP internal", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r2(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - } - ], - "ipv6": [ - { - "vertex": "r4" - }, - { - "metric": "0", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - }, - { - "interface": "r4-eth0", - "metric": "10", - "next-hop": "r2", - "parent": "r4(4)", - "type": "TE-IS", - "vertex": "r2" + "level-2": { + "ipv4-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP internal", + "vertex": "10.0.21.0/24" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r2(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r4" + }, + { + "metric": 0, + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + }, + { + "interface": "r4-eth0", + "metric": 10, + "nextHop": "r2", + "parent": "r4(4)", + "type": "TE-IS", + "vertex": "r2" + } + ] } - ] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json index 2a088cae30..8b5159cbfb 100644 --- a/tests/topotests/isis_topo1_vrf/r5/r5_topology.json +++ b/tests/topotests/isis_topo1_vrf/r5/r5_topology.json @@ -1,124 +1,122 @@ -{ - "1": { - "level-1": { - "ipv4": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.10.0/24" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP internal", - "vertex": "10.0.11.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.20.0/24" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP TE", - "vertex": "10.0.10.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.21.0/24" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP TE", - "vertex": "10.0.11.0/24" +[ + { + "area": "1", + "algorithm": 0, + "level-1": { + "ipv4-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.10.0/24" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP internal", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.10.0/24" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP TE", + "vertex": "10.0.20.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.11.0/24" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP TE", + "vertex": "10.0.21.0/24" + } + ], + "ipv6-paths": [ + { + "vertex": "r5" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:1::/64" + }, + { + "metric": 0, + "parent": "r5(4)", + "type": "IP6 internal", + "vertex": "2001:db8:2:2::/64" + }, + { + "interface": "r5-eth0", + "metric": 10, + "nextHop": "r3", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r3" + }, + { + "interface": "r5-eth1", + "metric": 10, + "nextHop": "r4", + "parent": "r5(4)", + "type": "TE-IS", + "vertex": "r4" + }, + { + "metric": 10, + "interface": "r5-eth0", + "nextHop": "r3", + "parent": "r3(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:1::/64" + }, + { + "metric": 10, + "interface": "r5-eth1", + "nextHop": "r4", + "parent": "r4(4)", + "type": "IP6 internal", + "vertex": "2001:db8:1:2::/64" + } + ] } - ], - "ipv6": [ - { - "vertex": "r5" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:1::/64" - }, - { - "metric": "0", - "parent": "r5(4)", - "type": "IP6 internal", - "vertex": "2001:db8:2:2::/64" - }, - { - "interface": "r5-eth0", - "metric": "10", - "next-hop": "r3", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r3" - }, - { - "interface": "r5-eth1", - "metric": "10", - "next-hop": "r4", - "parent": "r5(4)", - "type": "TE-IS", - "vertex": "r4" - }, - { - "metric": "10", - "interface": "r5-eth0", - "next-hop": "r3", - "parent": "r3(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:1::/64" - }, - { - "metric": "10", - "interface": "r5-eth1", - "next-hop": "r4", - "parent": "r4(4)", - "type": "IP6 internal", - "vertex": "2001:db8:1:2::/64" - } - ] - }, - "level-2": { - "ipv4": [], - "ipv6": [] } - } -} +] diff --git a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py index 032319c446..afc6864b98 100644 --- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py @@ -118,7 +118,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() # move back rx-eth0 to default VRF @@ -141,8 +141,9 @@ def test_isis_convergence(): def compare_isis_topology(router, expected): "Helper function to test ISIS vrf topology convergence." - actual = show_isis_topology(router) - + actual = json.loads( + router.vtysh_cmd(f"show isis vrf {router.name}-cust1 topology json") + ) return topotest.json_cmp(actual, expected) test_func = functools.partial(compare_isis_topology, router, expected) @@ -287,7 +288,7 @@ def dict_merge(dct, merge_dct): Source: https://gist.github.com/angstwad/bf22d1822c38a92ec0a9 """ - for k, v in merge_dct.items(): + for k, _ in merge_dct.items(): if k in dct and isinstance(dct[k], dict) and topotest.is_mapping(merge_dct[k]): dict_merge(dct[k], merge_dct[k]) else: @@ -377,52 +378,3 @@ def parse_topology(lines, level): continue return areas - - -def show_isis_topology(router): - """ - Get the ISIS vrf topology in a dictionary format. - - Sample: - { - 'area-name': { - 'level-1': [ - { - 'vertex': 'r1' - } - ], - 'level-2': [ - { - 'vertex': '10.0.0.1/24', - 'type': 'IP', - 'parent': '0', - 'metric': 'internal' - } - ] - }, - 'area-name-2': { - 'level-2': [ - { - "interface": "rX-ethY", - "metric": "Z", - "next-hop": "rA", - "parent": "rC(B)", - "type": "TE-IS", - "vertex": "rD" - } - ] - } - } - """ - l1out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-1".format(router.name)) - ).splitlines() - l2out = topotest.normalize_text( - router.vtysh_cmd("show isis vrf {}-cust1 topology level-2".format(router.name)) - ).splitlines() - - l1 = parse_topology(l1out, "level-1") - l2 = parse_topology(l2out, "level-2") - - dict_merge(l1, l2) - return l1 diff --git a/tests/topotests/key_sendaccept/test_keychain.py b/tests/topotests/key_sendaccept/test_keychain.py index b11d31b981..1d24c17004 100644 --- a/tests/topotests/key_sendaccept/test_keychain.py +++ b/tests/topotests/key_sendaccept/test_keychain.py @@ -27,7 +27,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py index c2bcaa84ce..8123e04982 100644 --- a/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py +++ b/tests/topotests/ldp_oc_acl_topo1/test_ldp_oc_acl_topo1.py @@ -117,7 +117,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py index 387fd89c20..bfb93d5588 100644 --- a/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py +++ b/tests/topotests/ldp_oc_topo1/test_ldp_oc_topo1.py @@ -116,7 +116,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py b/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py index 52a67d8bb8..ea404beae4 100644 --- a/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py +++ b/tests/topotests/ldp_snmp/test_ldp_snmp_topo1.py @@ -136,7 +136,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py b/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py index cb6b784d6d..f2c41ebe30 100644 --- a/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py +++ b/tests/topotests/ldp_sync_isis_topo1/test_ldp_sync_isis_topo1.py @@ -129,7 +129,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py b/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py index 760b4e3df5..9e41e06c6a 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py +++ b/tests/topotests/ldp_sync_ospf_topo1/test_ldp_sync_ospf_topo1.py @@ -128,7 +128,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() 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 1f4a4b5fd5..c14c79e6d4 100644 --- a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py @@ -129,7 +129,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 3a16ed5a09..bcd1c74812 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -333,7 +333,7 @@ def __create_bgp_global(tgen, input_dict, router, build=False): else: del_action = False - for rs_timer, value in timer.items(): + for rs_timer, _ in timer.items(): rs_timer_value = timer.setdefault(rs_timer, None) if rs_timer_value and rs_timer != "delete": @@ -1229,7 +1229,7 @@ def modify_bgp_config_when_bgpd_down(tgen, topo, input_dict): # Copy bgp config file to /etc/frr for dut in input_dict.keys(): router_list = tgen.routers() - for router, rnode in router_list.items(): + for router, _ in router_list.items(): if router != dut: continue @@ -1750,7 +1750,7 @@ def verify_as_numbers(tgen, topo, input_dict, expected=True): for bgp_neighbor, peer_data in bgp_neighbors.items(): remote_as = input_dict[bgp_neighbor]["bgp"]["local_as"] - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): neighbor_ip = None data = topo["routers"][bgp_neighbor]["links"] @@ -1833,7 +1833,7 @@ def verify_bgp_convergence_from_running_config(tgen, dut=None, expected=True): return errormsg for vrf, addr_family_data in show_bgp_json.items(): - for address_family, neighborship_data in addr_family_data.items(): + for _, neighborship_data in addr_family_data.items(): total_peer = 0 no_of_peer = 0 @@ -1980,7 +1980,7 @@ def clear_bgp_and_verify(tgen, topo, router, rid=None): bgp_neighbors = bgp_addr_type[addr_type]["unicast"]["neighbor"] for bgp_neighbor, peer_data in bgp_neighbors.items(): - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3231,7 +3231,7 @@ def verify_graceful_restart( if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3266,27 +3266,43 @@ def verify_graceful_restart( lmode = None rmode = None + # Local GR mode - if "address_family" in input_dict[dut]["bgp"]: - bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ - "unicast" - ]["neighbor"][peer]["dest_link"] + if "bgp" not in input_dict[dut] and "graceful-restart" in input_dict[dut]: + if ( + "graceful-restart" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart"] + ): + lmode = "Restart*" + elif ( + "graceful-restart-disable" in input_dict[dut]["graceful-restart"] + and input_dict[dut]["graceful-restart"]["graceful-restart-disable"] + ): + lmode = "Disable*" + else: + lmode = "Helper*" - for dest_link, data in bgp_neighbors.items(): - if ( - "graceful-restart-helper" in data - and data["graceful-restart-helper"] - ): - lmode = "Helper" - elif "graceful-restart" in data and data["graceful-restart"]: - lmode = "Restart" - elif ( - "graceful-restart-disable" in data - and data["graceful-restart-disable"] - ): - lmode = "Disable" - else: - lmode = None + if lmode is None: + if "address_family" in input_dict[dut]["bgp"]: + bgp_neighbors = input_dict[dut]["bgp"]["address_family"][addr_type][ + "unicast" + ]["neighbor"][peer]["dest_link"] + + for dest_link, data in bgp_neighbors.items(): + if ( + "graceful-restart-helper" in data + and data["graceful-restart-helper"] + ): + lmode = "Helper" + elif "graceful-restart" in data and data["graceful-restart"]: + lmode = "Restart" + elif ( + "graceful-restart-disable" in data + and data["graceful-restart-disable"] + ): + lmode = "Disable" + else: + lmode = None if lmode is None: if "graceful-restart" in input_dict[dut]["bgp"]: @@ -3314,7 +3330,11 @@ def verify_graceful_restart( return True # Remote GR mode - if "address_family" in input_dict[peer]["bgp"]: + + if ( + "bgp" in input_dict[peer] + and "address_family" in input_dict[peer]["bgp"] + ): bgp_neighbors = input_dict[peer]["bgp"]["address_family"][addr_type][ "unicast" ]["neighbor"][dut]["dest_link"] @@ -3336,7 +3356,10 @@ def verify_graceful_restart( rmode = None if rmode is None: - if "graceful-restart" in input_dict[peer]["bgp"]: + if ( + "bgp" in input_dict[peer] + and "graceful-restart" in input_dict[peer]["bgp"] + ): if ( "graceful-restart" in input_dict[peer]["bgp"]["graceful-restart"] @@ -3355,6 +3378,27 @@ def verify_graceful_restart( rmode = "Disable" else: rmode = "Helper" + + if rmode is None: + if ( + "bgp" not in input_dict[peer] + and "graceful-restart" in input_dict[peer] + ): + if ( + "graceful-restart" in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"]["graceful-restart"] + ): + rmode = "Restart" + elif ( + "graceful-restart-disable" + in input_dict[peer]["graceful-restart"] + and input_dict[peer]["graceful-restart"][ + "graceful-restart-disable" + ] + ): + rmode = "Disable" + else: + rmode = "Helper" else: rmode = "Helper" @@ -3479,7 +3523,7 @@ def verify_r_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3597,7 +3641,7 @@ def verify_eor(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3762,7 +3806,7 @@ def verify_f_bit(tgen, topo, addr_type, input_dict, dut, peer, expected=True): if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: @@ -3890,7 +3934,7 @@ def verify_graceful_restart_timers(tgen, topo, addr_type, input_dict, dut, peer) if bgp_neighbor != peer: continue - for dest_link, peer_dict in peer_data["dest_link"].items(): + for dest_link, _ in peer_data["dest_link"].items(): data = topo["routers"][bgp_neighbor]["links"] if dest_link in data: diff --git a/tests/topotests/lib/bgprib.py b/tests/topotests/lib/bgprib.py index 699c7a4da6..f01a440b9e 100644 --- a/tests/topotests/lib/bgprib.py +++ b/tests/topotests/lib/bgprib.py @@ -64,10 +64,9 @@ def routes_include_wanted(self, pfxtbl, want, debug): self.log("missing route: pfx=" + want["p"] + ", nh=" + want["n"]) return 0 - def RequireVpnRoutes(self, target, title, wantroutes, debug=0): + def RequireVpnRoutesOne(self, target, title, wantroutes, debug=0): import json - logstr = "RequireVpnRoutes " + str(wantroutes) # non json form for humans luCommand( target, @@ -86,11 +85,18 @@ def RequireVpnRoutes(self, target, title, wantroutes, debug=0): if re.search(r"^\s*$", ret): # degenerate case: empty json means no routes if len(wantroutes) > 0: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False + return True rib = json.loads(ret) - rds = rib["routes"]["routeDistinguishers"] + try: + rds = rib["routes"]["routeDistinguishers"] + except KeyError as err: + # KeyError: 'routes' probably means missing/bad VRF + # This error also happens if we are too quick and the routing + # table has not been fully populated yet. + if debug: + self.log("KeyError, no routes") + return False for want in wantroutes: found = 0 if debug: @@ -105,11 +111,39 @@ def RequireVpnRoutes(self, target, title, wantroutes, debug=0): found = 1 break if not found: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False + return True + + def RequireVpnRoutes( + self, target, title, wantroutes, debug=0, wait=10, wait_time=0.5 + ): + import time + import math + + logstr = "RequireVpnRoutes " + str(wantroutes) + found = False + n = 0 + startt = time.time() + + # Calculate the amount of `sleep`s we are going to peform. + wait_count = int(math.ceil(wait / wait_time)) + 1 + + while wait_count > 0: + n += 1 + found = self.RequireVpnRoutesOne(target, title, wantroutes, debug) + if found is not False: + break - def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): + wait_count -= 1 + if wait_count > 0: + time.sleep(wait_time) + + delta = time.time() - startt + self.log("Done after %d loops, time=%s, Found=%s" % (n, delta, found)) + luResult(target, found, title, logstr) + return found + + def RequireUnicastRoutesOne(self, target, afi, vrf, title, wantroutes, debug=0): logstr = "RequireUnicastRoutes %s" % str(wantroutes) vrfstr = "" if vrf != "": @@ -129,9 +163,8 @@ def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): if re.search(r"^\s*$", ret): # degenerate case: empty json means no routes if len(wantroutes) > 0: - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False, "" + return True, "" rib = json.loads(ret) try: table = rib["routes"] @@ -141,25 +174,60 @@ def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): errstr = "-script ERROR: check if wrong vrf (%s)" % (vrf) else: errstr = "-script ERROR: check if vrf missing" - luResult(target, False, title + errstr, logstr) - return + self.log(errstr) + return False, errstr # if debug: # self.log("table=%s" % table) for want in wantroutes: if debug: self.log("want=%s" % want) if not self.routes_include_wanted(table, want, debug): - luResult(target, False, title, logstr) - return - luResult(target, True, title, logstr) + return False, "" + return True, "" + + def RequireUnicastRoutes( + self, target, afi, vrf, title, wantroutes, debug=0, wait=10, wait_time=0.5 + ): + import time + import math + + logstr = "RequireUnicastRoutes %s" % str(wantroutes) + found = False + n = 0 + startt = time.time() + errstr = "" + + # Calculate the amount of `sleep`s we are going to peform. + wait_count = int(math.ceil(wait / wait_time)) + 1 + + while wait_count > 0: + n += 1 + found, errstr = self.RequireUnicastRoutesOne( + target, afi, vrf, title, wantroutes, debug + ) + if found is not False: + break + + wait_count -= 1 + if wait_count > 0: + time.sleep(wait_time) + + delta = time.time() - startt + self.log("Done after %d loops, time=%s, Found=%s" % (n, delta, found)) + luResult(target, found, title + errstr, logstr) + return found BgpRib = BgpRib() -def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0): - BgpRib.RequireVpnRoutes(target, title, wantroutes, debug) +def bgpribRequireVpnRoutes(target, title, wantroutes, debug=0, wait=10, wait_time=0.5): + BgpRib.RequireVpnRoutes(target, title, wantroutes, debug, wait, wait_time) -def bgpribRequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug=0): - BgpRib.RequireUnicastRoutes(target, afi, vrf, title, wantroutes, debug) +def bgpribRequireUnicastRoutes( + target, afi, vrf, title, wantroutes, debug=0, wait=10, wait_time=0.5 +): + BgpRib.RequireUnicastRoutes( + target, afi, vrf, title, wantroutes, debug, wait, wait_time + ) diff --git a/tests/topotests/lib/checkping.py b/tests/topotests/lib/checkping.py index 5500807fab..aa95f45b29 100644 --- a/tests/topotests/lib/checkping.py +++ b/tests/topotests/lib/checkping.py @@ -33,5 +33,5 @@ def _check(name, dest_addr, source_addr, match): logger.info("[+] check {} {} {}".format(name, dest_addr, match)) tgen = get_topogen() func = functools.partial(_check, name, dest_addr, source_addr, match) - success, result = topotest.run_and_expect(func, None, count=count, wait=wait) + _, result = topotest.run_and_expect(func, None, count=count, wait=wait) assert result is None, "Failed" diff --git a/tests/topotests/lib/common_check.py b/tests/topotests/lib/common_check.py new file mode 100644 index 0000000000..19f02dbadc --- /dev/null +++ b/tests/topotests/lib/common_check.py @@ -0,0 +1,65 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC +# +# common_check.py +# +# Copyright 2024 6WIND S.A. + +# +import json +from lib import topotest + + +def ip_check_path_selection( + router, ipaddr_str, expected, vrf_name=None, check_fib=False +): + if vrf_name: + cmdstr = f"show ip route vrf {vrf_name} {ipaddr_str} json" + else: + cmdstr = f"show ip route {ipaddr_str} json" + try: + output = json.loads(router.vtysh_cmd(cmdstr)) + except: + output = {} + + ret = topotest.json_cmp(output, expected) + if ret is None: + num_nh_expected = len(expected[ipaddr_str][0]["nexthops"]) + num_nh_observed = len(output[ipaddr_str][0]["nexthops"]) + if num_nh_expected == num_nh_observed: + if check_fib: + # special case: when fib flag is unset, + # an extra test should be done to check that the flag is really unset + for nh_output, nh_expected in zip( + output[ipaddr_str][0]["nexthops"], + expected[ipaddr_str][0]["nexthops"], + ): + if ( + "fib" in nh_output.keys() + and nh_output["fib"] + and ("fib" not in nh_expected.keys() or not nh_expected["fib"]) + ): + return "{}, prefix {} nexthop {} has the fib flag set, whereas it is not expected".format( + router.name, ipaddr_str, nh_output["ip"] + ) + return ret + return "{}, prefix {} does not have the correct number of nexthops : observed {}, expected {}".format( + router.name, ipaddr_str, num_nh_observed, num_nh_expected + ) + return ret + + +def iproute2_check_path_selection(router, ipaddr_str, expected, vrf_name=None): + if not topotest.iproute2_is_json_capable(): + return None + + if vrf_name: + cmdstr = f"ip -json route show vrf {vrf_name} {ipaddr_str}" + else: + cmdstr = f"ip -json route show {ipaddr_str}" + try: + output = json.loads(cmdstr) + except: + output = [] + + return topotest.json_cmp(output, expected) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 7787b6f74b..e856c23d36 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -7,7 +7,6 @@ import functools import ipaddress -import json import os import platform import socket @@ -442,7 +441,7 @@ def check_router_status(tgen): try: router_list = tgen.routers() - for router, rnode in router_list.items(): + for _, rnode in router_list.items(): result = rnode.check_router_running() if result != "": daemons = [] @@ -686,7 +685,7 @@ def prep_load_config_to_routers(tgen, *config_name_list): """ routers = tgen.routers() - for rname, router in routers.items(): + for rname, _ in routers.items(): destname = "{}/{}/{}".format(tgen.logdir, rname, FRRCFG_FILE) wmode = "w" for cfbase in config_name_list: @@ -871,7 +870,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): """ router_list = tgen.routers() - for rname, rnode in router_list.items(): + for rname, _ in router_list.items(): if rname != router: continue @@ -887,7 +886,7 @@ def get_frr_ipv6_linklocal(tgen, router, intf=None, vrf=None): cmd = "show interface vrf {}".format(vrf) else: cmd = "show interface" - for chk_ll in range(0, 60): + for _ in range(0, 60): sleep(1 / 4) ifaces = router_list[router].run('vtysh -c "{}"'.format(cmd)) # Fix newlines (make them all the same) @@ -3095,7 +3094,7 @@ def configure_brctl(tgen, topo, input_dict): "{} dev {} master {}".format(ip_cmd, brctl_name, vrf) ) - for intf_name, data in topo["routers"][dut]["links"].items(): + for _, data in topo["routers"][dut]["links"].items(): if "vrf" not in data: continue @@ -4942,7 +4941,7 @@ def scapy_send_raw_packet(tgen, topo, senderRouter, intf, packet=None): sender_interface = intf rnode = tgen.routers()[senderRouter] - for destLink, data in topo["routers"][senderRouter]["links"].items(): + for _, data in topo["routers"][senderRouter]["links"].items(): if "type" in data and data["type"] == "loopback": continue diff --git a/tests/topotests/lib/fe_client.py b/tests/topotests/lib/fe_client.py index a47544633b..784f7d17eb 100755 --- a/tests/topotests/lib/fe_client.py +++ b/tests/topotests/lib/fe_client.py @@ -9,7 +9,6 @@ # noqa: E501 # import argparse -import json import logging import os import socket @@ -18,6 +17,8 @@ import time from pathlib import Path +from munet.base import Timeout + CWD = os.path.dirname(os.path.realpath(__file__)) # This is painful but works if you have installed protobuf would be better if we @@ -80,6 +81,13 @@ MSG_NOTIFY_FMT = "=B7x" NOTIFY_FIELD_RESULT_TYPE = 0 +MSG_NOTIFY_SELECT_FMT = "=B7x" + +MSG_SESSION_REQ_FMT = "=8x" + +MSG_SESSION_REPLY_FMT = "=B7x" +SESSION_REPLY_FIELD_CREATED = 0 + # # Native message codes # @@ -88,6 +96,9 @@ MSG_CODE_TREE_DATA = 2 MSG_CODE_GET_DATA = 3 MSG_CODE_NOTIFY = 4 +MSG_CODE_NOTIFY_SELECT = 9 +MSG_CODE_SESSION_REQ = 10 +MSG_CODE_SESSION_REPLY = 11 msg_native_formats = { MSG_CODE_ERROR: MSG_ERROR_FMT, @@ -95,6 +106,9 @@ MSG_CODE_TREE_DATA: MSG_TREE_DATA_FMT, MSG_CODE_GET_DATA: MSG_GET_DATA_FMT, MSG_CODE_NOTIFY: MSG_NOTIFY_FMT, + MSG_CODE_NOTIFY_SELECT: MSG_NOTIFY_SELECT_FMT, + MSG_CODE_SESSION_REQ: MSG_SESSION_REQ_FMT, + MSG_CODE_SESSION_REPLY: MSG_SESSION_REPLY_FMT, } @@ -177,27 +191,44 @@ class Session: client_id = 1 - def __init__(self, sock): + def __init__(self, sock, use_protobuf): self.sock = sock self.next_req_id = 1 - req = mgmt_pb2.FeMessage() - req.register_req.client_name = "test-client" - self.send_pb_msg(req) - logging.debug("Sent FeRegisterReq: %s", req) + if use_protobuf: + req = mgmt_pb2.FeMessage() + req.register_req.client_name = "test-client" + self.send_pb_msg(req) + logging.debug("Sent FeRegisterReq: %s", req) - req = mgmt_pb2.FeMessage() - req.session_req.create = 1 - req.session_req.client_conn_id = Session.client_id - Session.client_id += 1 - self.send_pb_msg(req) - logging.debug("Sent FeSessionReq: %s", req) + req = mgmt_pb2.FeMessage() + req.session_req.create = 1 + req.session_req.client_conn_id = Session.client_id + Session.client_id += 1 + self.send_pb_msg(req) + logging.debug("Sent FeSessionReq: %s", req) - reply = self.recv_pb_msg(mgmt_pb2.FeMessage()) - logging.debug("Received FeSessionReply: %s", repr(reply)) + reply = self.recv_pb_msg(mgmt_pb2.FeMessage()) + logging.debug("Received FeSessionReply: %s", repr(reply)) - assert reply.session_reply.success - self.sess_id = reply.session_reply.session_id + assert reply.session_reply.success + self.sess_id = reply.session_reply.session_id + else: + self.sess_id = 0 + mdata, _ = self.get_native_msg_header(MSG_CODE_SESSION_REQ) + mdata += struct.pack(MSG_SESSION_REQ_FMT) + mdata += "test-client".encode("utf-8") + b"\x00" + + self.send_native_msg(mdata) + logging.debug("Sent native SESSION-REQ") + + mhdr, mfixed, mdata = self.recv_native_msg() + if mhdr[HDR_FIELD_CODE] == MSG_CODE_SESSION_REPLY: + logging.debug("Recv native SESSION-REQ Message: %s: %s", mfixed, mdata) + else: + raise Exception(f"Recv NON-SESSION-REPLY Message: {mfixed}: {mdata}") + assert mfixed[0] + self.sess_id = mhdr[HDR_FIELD_SESS_ID] def close(self, clean=True): if clean: @@ -292,7 +323,7 @@ def lock(self, lock=True, ds_id=mgmt_pb2.CANDIDATE_DS): def get_data(self, query, data=True, config=False): # Create the message - mdata, req_id = self.get_native_msg_header(MSG_CODE_GET_DATA) + mdata, _ = self.get_native_msg_header(MSG_CODE_GET_DATA) flags = GET_DATA_FLAG_STATE if data else 0 flags |= GET_DATA_FLAG_CONFIG if config else 0 mdata += struct.pack(MSG_GET_DATA_FMT, MSG_FORMAT_JSON, flags) @@ -301,24 +332,29 @@ def get_data(self, query, data=True, config=False): self.send_native_msg(mdata) logging.debug("Sent GET-TREE") - mhdr, mfixed, mdata = self.recv_native_msg() + _, mfixed, mdata = self.recv_native_msg() assert mdata[-1] == 0 result = mdata[:-1].decode("utf-8") logging.debug("Received GET: %s: %s", mfixed, mdata) return result - # def subscribe(self, notif_xpath): - # # Create the message - # mdata, req_id = self.get_native_msg_header(MSG_CODE_SUBSCRIBE) - # mdata += struct.pack(MSG_SUBSCRIBE_FMT, MSG_FORMAT_JSON) - # mdata += notif_xpath.encode("utf-8") + b"\x00" + def add_notify_select(self, replace, notif_xpaths): + # Create the message + mdata, _ = self.get_native_msg_header(MSG_CODE_NOTIFY_SELECT) + mdata += struct.pack(MSG_NOTIFY_SELECT_FMT, replace) + + for xpath in notif_xpaths: + mdata += xpath.encode("utf-8") + b"\x00" - # self.send_native_msg(mdata) - # logging.debug("Sent SUBSCRIBE") + self.send_native_msg(mdata) + logging.debug("Sent NOTIFY_SELECT") def recv_notify(self, xpaths=None): - while True: + if xpaths: + self.add_notify_select(True, xpaths) + + for _ in Timeout(60): logging.debug("Waiting for Notify Message") mhdr, mfixed, mdata = self.recv_native_msg() if mhdr[HDR_FIELD_CODE] == MSG_CODE_NOTIFY: @@ -328,19 +364,11 @@ def recv_notify(self, xpaths=None): vsplit = mhdr[HDR_FIELD_VSPLIT] assert mdata[vsplit - 1] == 0 - xpath = mdata[: vsplit - 1].decode("utf-8") - assert mdata[-1] == 0 - result = mdata[vsplit:-1].decode("utf-8") - - if not xpaths: - return result - js = json.loads(result) - key = [x for x in js.keys()][0] - for xpath in xpaths: - if key.startswith(xpath): - return result - logging.debug("'%s' didn't match xpath filters", key) + # xpath = mdata[: vsplit - 1].decode("utf-8") + return mdata[vsplit:-1].decode("utf-8") + else: + raise TimeoutError("Timeout waiting for notifications") def __parse_args(): @@ -365,6 +393,9 @@ def __parse_args(): "-q", "--query", nargs="+", metavar="XPATH", help="xpath[s] to query" ) parser.add_argument("-s", "--server", default=MPATH, help="path to server socket") + parser.add_argument( + "--use-protobuf", action="store_true", help="Use protobuf when there's a choice" + ) parser.add_argument("-v", "--verbose", action="store_true", help="Be verbose") args = parser.parse_args() @@ -381,13 +412,15 @@ def __server_connect(spath): logging.warn("retry server connection in .5s (%s)", os.strerror(ec)) time.sleep(0.5) logging.info("Connected to server on %s", spath) + # Set a timeout of 5 minutes for socket operations. + sock.settimeout(60 * 5) return sock def __main(): args = __parse_args() sock = __server_connect(Path(args.server)) - sess = Session(sock) + sess = Session(sock, use_protobuf=args.use_protobuf) if args.query: # Performa an xpath query @@ -412,8 +445,12 @@ def main(): __main() except KeyboardInterrupt: logging.info("Exiting") + except TimeoutError as error: + logging.error("Timeout: %s", error) + sys.exit(2) except Exception as error: logging.error("Unexpected error exiting: %s", error, exc_info=True) + sys.exit(1) if __name__ == "__main__": diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index 5b18f8b679..2c876e1989 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -1545,7 +1545,7 @@ def verify_ospf_database( ) return errormsg if ospf_external_lsa: - for ospf_ext_lsa, ext_lsa_data in ospf_external_lsa.items(): + for ospf_ext_lsa, _ in ospf_external_lsa.items(): if ospf_ext_lsa in show_ospf_json["AS External Link States"]: logger.info( "[DUT: %s] OSPF LSDB:External LSA %s", router, ospf_ext_lsa @@ -2509,7 +2509,7 @@ def verify_ospf_gr_helper(tgen, topo, dut, input_dict=None): raise ValueError(errormsg) return errormsg - for ospf_gr, gr_data in input_dict.items(): + for ospf_gr, _ in input_dict.items(): try: if input_dict[ospf_gr] == show_ospf_json[ospf_gr]: logger.info( diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py index f7440efd6d..cc56ffdd8c 100644 --- a/tests/topotests/lib/pim.py +++ b/tests/topotests/lib/pim.py @@ -149,7 +149,7 @@ def _add_pim_rp_config(tgen, topo, input_dict, router, build, config_data_dict): # At least one interface must be enabled for PIM on the router pim_if_enabled = False pim6_if_enabled = False - for destLink, data in topo[dut]["links"].items(): + for _, data in topo[dut]["links"].items(): if "pim" in data: pim_if_enabled = True if "pim6" in data: @@ -603,7 +603,7 @@ def find_rp_details(tgen, topo): # ip address of RP rp_addr = rp_dict["rp_addr"] - for link, data in topo["routers"][router]["links"].items(): + for _, data in topo["routers"][router]["links"].items(): if data["ipv4"].split("/")[0] == rp_addr: rp_details[router] = rp_addr @@ -2089,7 +2089,7 @@ def verify_pim_interface( ) return True else: - for destLink, data in topo["routers"][dut]["links"].items(): + for _, data in topo["routers"][dut]["links"].items(): if "type" in data and data["type"] == "loopback": continue @@ -2292,7 +2292,7 @@ def clear_pim_interfaces(tgen, dut): # Waiting for maximum 60 sec fail_intf = [] - for retry in range(1, 13): + for _ in range(1, 13): sleep(5) logger.info("[DUT: %s]: Waiting for 5 sec for PIM neighbors" " to come up", dut) run_json_after = run_frr_cmd(rnode, "show ip pim neighbor json", isjson=True) @@ -2368,7 +2368,7 @@ def clear_igmp_interfaces(tgen, dut): total_groups_before_clear = igmp_json["totalGroups"] - for key, value in igmp_json.items(): + for _, value in igmp_json.items(): if type(value) is not dict: continue @@ -2381,7 +2381,7 @@ def clear_igmp_interfaces(tgen, dut): result = run_frr_cmd(rnode, "clear ip igmp interfaces") # Waiting for maximum 60 sec - for retry in range(1, 13): + for _ in range(1, 13): logger.info( "[DUT: %s]: Waiting for 5 sec for igmp interfaces" " to come up", dut ) @@ -2460,7 +2460,7 @@ def clear_mroute_verify(tgen, dut, expected=True): # RFC 3376: 8.2. Query Interval - Default: 125 seconds # So waiting for maximum 130 sec to get the igmp report - for retry in range(1, 26): + for _ in range(1, 26): logger.info("[DUT: %s]: Waiting for 2 sec for mroutes" " to come up", dut) sleep(5) keys_json1 = mroute_json_1.keys() @@ -2671,7 +2671,7 @@ def add_rp_interfaces_and_pim_config(tgen, topo, interface, rp, rp_mapping): try: config_data = [] - for group, rp_list in rp_mapping.items(): + for _, rp_list in rp_mapping.items(): for _rp in rp_list: config_data.append("interface {}".format(interface)) config_data.append("ip address {}".format(_rp)) @@ -2720,7 +2720,7 @@ def scapy_send_bsr_raw_packet(tgen, topo, senderRouter, receiverRouter, packet=N script_path = os.path.join(CWD, "send_bsr_packet.py") node = tgen.net[senderRouter] - for destLink, data in topo["routers"][senderRouter]["links"].items(): + for _, data in topo["routers"][senderRouter]["links"].items(): if "type" in data and data["type"] == "loopback": continue @@ -2795,12 +2795,12 @@ def find_rp_from_bsrp_info(tgen, dut, bsr, grp=None): # RP with lowest priority if len(priority_dict) != 1: - rp_p, lowest_priority = sorted(rp_priority.items(), key=lambda x: x[1])[0] + rp_p, _ = sorted(rp_priority.items(), key=lambda x: x[1])[0] rp_details[group] = rp_p # RP with highest hash value if len(priority_dict) == 1: - rp_h, highest_hash = sorted(rp_hash.items(), key=lambda x: x[1])[-1] + rp_h, _ = sorted(rp_hash.items(), key=lambda x: x[1])[-1] rp_details[group] = rp_h # RP with highest IP address @@ -3239,7 +3239,7 @@ def verify_pim_join( interface_json = show_pim_join_json[interface] grp_addr = grp_addr.split("/")[0] - for source, data in interface_json[grp_addr].items(): + for _, data in interface_json[grp_addr].items(): # Verify pim join if pim_join: if data["group"] == grp_addr and data["channelJoinName"] == "JOIN": diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index 087d8454fc..5a8c2e5964 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -602,6 +602,30 @@ def is_linux(): return False +def iproute2_is_json_capable(): + """ + Checks if the iproute2 version installed on the system is capable of + handling JSON outputss + + Returns True if capability can be detected, returns False otherwise. + """ + if is_linux(): + try: + subp = subprocess.Popen( + ["ip", "-json", "route", "show"], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + stdin=subprocess.PIPE, + ) + iproute2_err = subp.communicate()[1].splitlines()[0].split()[0] + + if iproute2_err != "Error:": + return True + except Exception: + pass + return False + + def iproute2_is_vrf_capable(): """ Checks if the iproute2 version installed on the system is capable of @@ -1406,7 +1430,7 @@ def __init__(self, name, *posargs, **params): self.daemondir = None self.hasmpls = False self.routertype = "frr" - self.unified_config = None + self.unified_config = False self.daemons = { "zebra": 0, "ripd": 0, @@ -1629,7 +1653,7 @@ def loadConf(self, daemon, source=None, param=None): # print "Daemons before:", self.daemons if daemon in self.daemons.keys() or daemon == "frr": if daemon == "frr": - self.unified_config = 1 + self.unified_config = True else: self.daemons[daemon] = 1 if param is not None: diff --git a/tests/topotests/mgmt_debug_flags/test_debug.py b/tests/topotests/mgmt_debug_flags/test_debug.py index e49d9b7beb..fe659e54ca 100644 --- a/tests/topotests/mgmt_debug_flags/test_debug.py +++ b/tests/topotests/mgmt_debug_flags/test_debug.py @@ -27,7 +27,7 @@ def tgen(request): tgen = Topogen(topodef, request.module.__name__) tgen.start_topology() - for rname, router in tgen.routers().items(): + for _, router in tgen.routers().items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/mgmt_notif/test_notif.py b/tests/topotests/mgmt_notif/test_notif.py index c85e7ba795..e5286faae2 100644 --- a/tests/topotests/mgmt_notif/test_notif.py +++ b/tests/topotests/mgmt_notif/test_notif.py @@ -10,7 +10,6 @@ Test YANG Notifications """ import json -import logging import os import pytest @@ -35,7 +34,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() @@ -51,7 +50,7 @@ def test_frontend_notification(tgen): check_kernel_32(r1, "11.11.11.11", 1, "") - fe_client_path = CWD + "/../lib/fe_client.py" + fe_client_path = CWD + "/../lib/fe_client.py --verbose" rc, _, _ = r1.cmd_status(fe_client_path + " --help") if rc: @@ -61,7 +60,7 @@ def test_frontend_notification(tgen): # So we filter to avoid that, all the rest are frr-ripd:authentication-failure # making our test deterministic output = r1.cmd_raises( - fe_client_path + " --listen frr-ripd:authentication-failure" + fe_client_path + " --listen /frr-ripd:authentication-failure" ) jsout = json.loads(output) @@ -69,7 +68,7 @@ def test_frontend_notification(tgen): result = json_cmp(jsout, expected) assert result is None - output = r1.cmd_raises(fe_client_path + " --listen") + output = r1.cmd_raises(fe_client_path + " --use-protobuf --listen") jsout = json.loads(output) expected = {"frr-ripd:authentication-failure": {"interface-name": "r1-eth0"}} diff --git a/tests/topotests/mgmt_oper/oper.py b/tests/topotests/mgmt_oper/oper.py index 162c1eb5cc..934093aeee 100644 --- a/tests/topotests/mgmt_oper/oper.py +++ b/tests/topotests/mgmt_oper/oper.py @@ -146,7 +146,7 @@ def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): # logger.debug("checking kernel routing table%s:\n%s", vrfstr, kernel) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if not add: assert str(net) not in kernel continue @@ -233,7 +233,7 @@ def do_config( if vrf: f.write("vrf {}\n".format(vrf)) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if add: f.write("ip route {} {}\n".format(net, via)) else: diff --git a/tests/topotests/mgmt_oper/test_oper.py b/tests/topotests/mgmt_oper/test_oper.py index 8b8a51c29e..e4ceabf352 100644 --- a/tests/topotests/mgmt_oper/test_oper.py +++ b/tests/topotests/mgmt_oper/test_oper.py @@ -12,17 +12,11 @@ import ipaddress import math -import time import pytest from lib.topogen import Topogen from oper import check_kernel_32, do_oper_test -try: - from deepdiff import DeepDiff as dd_json_cmp -except ImportError: - dd_json_cmp = None - pytestmark = [pytest.mark.staticd, pytest.mark.mgmtd] diff --git a/tests/topotests/mgmt_rpc/test_rpc.py b/tests/topotests/mgmt_rpc/test_rpc.py index 618d9022ce..4d073fd0c9 100644 --- a/tests/topotests/mgmt_rpc/test_rpc.py +++ b/tests/topotests/mgmt_rpc/test_rpc.py @@ -14,6 +14,7 @@ import threading import pytest +from lib.common_config import retry from lib.topogen import Topogen from lib.topotest import json_cmp @@ -32,7 +33,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() @@ -40,12 +41,20 @@ def tgen(request): tgen.stop_topology() +# Verify the backend test client has connected +@retry(retry_timeout=10) +def check_client_connect(r1): + out = r1.vtysh_cmd("show mgmt backend-adapter all") + assert "mgmtd-testc" in out + + def test_backend_rpc(tgen): if tgen.routers_have_failure(): pytest.skip(tgen.errors) r1 = tgen.gears["r1"] + # Run the backend test client which registers to handle the `clear ip rip` command. be_client_path = "/usr/lib/frr/mgmtd_testc" rc, _, _ = r1.net.cmd_status(be_client_path + " --help") @@ -63,6 +72,10 @@ def run_testc(): t = threading.Thread(target=run_testc) t.start() + # We need to wait for mgmtd_testc to connect before issuing the command. + res = check_client_connect(r1) + assert res is None + r1.vtysh_cmd("clear ip rip vrf testname") t.join() diff --git a/tests/topotests/mgmt_tests/test_yang_mgmt.py b/tests/topotests/mgmt_tests/test_yang_mgmt.py index 605c14285f..52f6ba4db7 100644 --- a/tests/topotests/mgmt_tests/test_yang_mgmt.py +++ b/tests/topotests/mgmt_tests/test_yang_mgmt.py @@ -66,7 +66,6 @@ start_router_daemons, ) from lib.topolog import logger -from lib.bgp import verify_bgp_convergence, create_router_bgp, verify_bgp_rib from lib.topojson import build_config_from_json pytestmark = [pytest.mark.bgpd, pytest.mark.staticd, pytest.mark.mgmtd] diff --git a/tests/topotests/msdp_topo1/r1/pimd.conf b/tests/topotests/msdp_topo1/r1/pimd.conf index 5bb268ebef..3c116a003b 100644 --- a/tests/topotests/msdp_topo1/r1/pimd.conf +++ b/tests/topotests/msdp_topo1/r1/pimd.conf @@ -20,3 +20,7 @@ ip msdp peer 192.168.0.2 source 192.168.0.1 ip msdp peer 192.168.1.2 source 192.168.1.1 ip pim rp 10.254.254.1 ip pim join-prune-interval 5 +! +router pim + msdp peer 192.168.0.2 password 1234 +! diff --git a/tests/topotests/msdp_topo1/r2/pimd.conf b/tests/topotests/msdp_topo1/r2/pimd.conf index 733bd6f2f1..4ea2c82314 100644 --- a/tests/topotests/msdp_topo1/r2/pimd.conf +++ b/tests/topotests/msdp_topo1/r2/pimd.conf @@ -16,3 +16,7 @@ ip msdp peer 192.168.0.1 source 192.168.0.2 ip msdp peer 192.168.2.2 source 192.168.2.1 ip pim rp 10.254.254.2 ip pim join-prune-interval 5 +! +router pim + msdp peer 192.168.0.1 password 1234 +! diff --git a/tests/topotests/msdp_topo1/r4/pimd.conf b/tests/topotests/msdp_topo1/r4/pimd.conf index 28085913fb..46de4fbe38 100644 --- a/tests/topotests/msdp_topo1/r4/pimd.conf +++ b/tests/topotests/msdp_topo1/r4/pimd.conf @@ -20,3 +20,16 @@ ip msdp peer 192.168.2.1 source 192.168.2.2 ip msdp peer 192.168.3.1 source 192.168.3.2 ip pim rp 10.254.254.4 ip pim join-prune-interval 5 +! +access-list forbidden-multicast seq 5 deny 229.2.1.0 0.0.0.255 +access-list forbidden-multicast seq 1000 permit any +access-list local-only-multicast seq 5 deny 229.3.1.0 0.0.0.255 +access-list local-only-multicast seq 6 deny ip 192.168.4.100 0.0.0.0 229.10.1.0 0.0.0.255 +access-list local-only-multicast seq 1000 permit any +! +router pim + msdp peer 192.168.2.1 sa-filter forbidden-multicast in + msdp peer 192.168.2.1 sa-filter local-only-multicast out + msdp peer 192.168.3.1 sa-filter forbidden-multicast in + msdp peer 192.168.3.1 sa-filter local-only-multicast out +! diff --git a/tests/topotests/msdp_topo1/test_msdp_topo1.py b/tests/topotests/msdp_topo1/test_msdp_topo1.py index 2fbff440f5..ff80052d26 100755 --- a/tests/topotests/msdp_topo1/test_msdp_topo1.py +++ b/tests/topotests/msdp_topo1/test_msdp_topo1.py @@ -66,7 +66,9 @@ def build_topo(tgen): # Create a host connected and direct at r4: tgen.add_host("h1", "192.168.4.100/24", "via 192.168.4.1") + tgen.add_host("h3", "192.168.4.120/24", "via 192.168.4.1") switch.add_link(tgen.gears["h1"]) + switch.add_link(tgen.gears["h3"]) # Create a host connected and direct at r1: switch = tgen.add_switch("s6") @@ -82,7 +84,6 @@ def setup_module(mod): router_list = tgen.routers() for rname, router in router_list.items(): - daemon_file = "{}/{}/zebra.conf".format(CWD, rname) if os.path.isfile(daemon_file): router.load_config(TopoRouter.RD_ZEBRA, daemon_file) @@ -101,7 +102,7 @@ def setup_module(mod): app_helper.init(tgen) -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() app_helper.cleanup() @@ -428,6 +429,87 @@ def test_msdp(): assert val is None, "multicast route convergence failure" +def test_msdp_sa_filter(): + "Start a number of multicast streams and check if filtering works" + + tgen = get_topogen() + + # Flow from r1 -> r4 + for multicast_address in ["229.2.1.1", "229.2.1.2", "229.2.2.1"]: + app_helper.run("h1", [multicast_address, "h1-eth0"]) + app_helper.run("h2", ["--send=0.7", multicast_address, "h2-eth0"]) + + # Flow from r4 -> r1 + for multicast_address in ["229.3.1.1", "229.3.1.2", "229.3.2.1"]: + app_helper.run("h1", ["--send=0.7", multicast_address, "h1-eth0"]) + app_helper.run("h2", [multicast_address, "h2-eth0"]) + + # Flow from r4 -> r1 but with more sources + for multicast_address in ["229.10.1.1", "229.11.1.1"]: + app_helper.run("h1", ["--send=0.7", multicast_address, "h1-eth0"]) + app_helper.run("h2", [multicast_address, "h2-eth0"]) + app_helper.run("h3", ["--send=0.7", multicast_address, "h3-eth0"]) + + # Test that we don't learn any filtered multicast streams. + r4_sa_expected = { + "229.2.1.1": None, + "229.2.1.2": None, + "229.2.2.1": { + "192.168.10.100": { + "local": "no", + "sptSetup": "yes", + } + }, + } + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r4"], + "show ip msdp sa json", + r4_sa_expected, + ) + logger.info("Waiting for r4 MDSP SA data") + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + # Test that we don't send any filtered multicast streams. + r1_sa_expected = { + "229.3.1.1": None, + "229.3.1.2": None, + "229.3.2.1": { + "192.168.4.100": { + "local": "no", + "sptSetup": "yes", + } + }, + "229.10.1.1": { + "192.168.4.100": None, + "192.168.4.120": { + "local": "no", + "sptSetup": "yes", + }, + }, + "229.11.1.1": { + "192.168.4.100": { + "local": "no", + "sptSetup": "yes", + }, + "192.168.4.120": { + "local": "no", + "sptSetup": "yes", + }, + }, + } + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + "show ip msdp sa json", + r1_sa_expected, + ) + logger.info("Waiting for r1 MDSP SA data") + _, val = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + def test_memory_leak(): "Run the memory leak test and report results." tgen = get_topogen() diff --git a/tests/topotests/msdp_topo2/r1/bgpd.conf b/tests/topotests/msdp_topo2/r1/bgpd.conf new file mode 100644 index 0000000000..67f04d8eab --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as 65002 + neighbor 192.168.3.3 remote-as 65003 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r1/pimd.conf b/tests/topotests/msdp_topo2/r1/pimd.conf new file mode 100644 index 0000000000..58a4c21e40 --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/pimd.conf @@ -0,0 +1,20 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.1 +! +interface r1-eth0 + ip pim +! +interface r1-eth1 + ip pim +! +interface r1-eth2 + ip pim + ip igmp +! +ip msdp peer 192.168.1.2 source 192.168.1.1 +ip msdp peer 192.168.3.3 source 192.168.3.1 +ip pim rp 10.254.254.1 diff --git a/tests/topotests/msdp_topo2/r1/zebra.conf b/tests/topotests/msdp_topo2/r1/zebra.conf new file mode 100644 index 0000000000..3219fad36d --- /dev/null +++ b/tests/topotests/msdp_topo2/r1/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +! +interface r1-eth0 + ip address 192.168.1.1/24 +! +interface r1-eth1 + ip address 192.168.3.1/24 +! +interface r1-eth2 + ip address 192.168.6.1/24 +! +interface lo + ip address 10.254.254.1/32 +! diff --git a/tests/topotests/msdp_topo2/r2/bgpd.conf b/tests/topotests/msdp_topo2/r2/bgpd.conf new file mode 100644 index 0000000000..b9f316898c --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as 65001 + neighbor 192.168.2.5 remote-as 65005 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r2/pimd.conf b/tests/topotests/msdp_topo2/r2/pimd.conf new file mode 100644 index 0000000000..66e630264c --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.2 +! +interface r2-eth0 + ip pim +! +interface r2-eth1 + ip pim +! +ip msdp peer 192.168.1.1 source 192.168.1.2 +ip msdp peer 192.168.2.5 source 192.168.2.2 +ip pim rp 10.254.254.2 diff --git a/tests/topotests/msdp_topo2/r2/zebra.conf b/tests/topotests/msdp_topo2/r2/zebra.conf new file mode 100644 index 0000000000..740b51a4f0 --- /dev/null +++ b/tests/topotests/msdp_topo2/r2/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r2-eth0 + ip address 192.168.1.2/24 +! +interface r2-eth1 + ip address 192.168.2.2/24 +! +interface lo + ip address 10.254.254.2/32 +! diff --git a/tests/topotests/msdp_topo2/r3/bgpd.conf b/tests/topotests/msdp_topo2/r3/bgpd.conf new file mode 100644 index 0000000000..ecd25b050e --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65003 + no bgp ebgp-requires-policy + neighbor 192.168.3.1 remote-as 65001 + neighbor 192.168.4.4 remote-as 65004 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r3/pimd.conf b/tests/topotests/msdp_topo2/r3/pimd.conf new file mode 100644 index 0000000000..e8e53268e3 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.3 +! +interface r3-eth0 + ip pim +! +interface r3-eth1 + ip pim +! +ip msdp peer 192.168.3.1 source 192.168.3.3 +ip msdp peer 192.168.4.4 source 192.168.4.3 +ip pim rp 10.254.254.3 diff --git a/tests/topotests/msdp_topo2/r3/zebra.conf b/tests/topotests/msdp_topo2/r3/zebra.conf new file mode 100644 index 0000000000..d1be65f636 --- /dev/null +++ b/tests/topotests/msdp_topo2/r3/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r3-eth0 + ip address 192.168.3.3/24 +! +interface r3-eth1 + ip address 192.168.4.3/24 +! +interface lo + ip address 10.254.254.3/32 +! diff --git a/tests/topotests/msdp_topo2/r4/bgpd.conf b/tests/topotests/msdp_topo2/r4/bgpd.conf new file mode 100644 index 0000000000..430517bc2b --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65004 + no bgp ebgp-requires-policy + neighbor 192.168.4.3 remote-as 65003 + neighbor 192.168.5.5 remote-as 65005 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r4/pimd.conf b/tests/topotests/msdp_topo2/r4/pimd.conf new file mode 100644 index 0000000000..32e3c613fa --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/pimd.conf @@ -0,0 +1,16 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.4 +! +interface r4-eth0 + ip pim +! +interface r4-eth1 + ip pim +! +ip msdp peer 192.168.4.3 source 192.168.4.4 +ip msdp peer 192.168.5.5 source 192.168.5.4 +ip pim rp 10.254.254.4 diff --git a/tests/topotests/msdp_topo2/r4/zebra.conf b/tests/topotests/msdp_topo2/r4/zebra.conf new file mode 100644 index 0000000000..045d2e8070 --- /dev/null +++ b/tests/topotests/msdp_topo2/r4/zebra.conf @@ -0,0 +1,11 @@ +ip forwarding +! +interface r4-eth0 + ip address 192.168.4.4/24 +! +interface r4-eth1 + ip address 192.168.5.4/24 +! +interface lo + ip address 10.254.254.4/32 +! diff --git a/tests/topotests/msdp_topo2/r5/bgpd.conf b/tests/topotests/msdp_topo2/r5/bgpd.conf new file mode 100644 index 0000000000..053dd3d3ef --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65005 + no bgp ebgp-requires-policy + neighbor 192.168.2.2 remote-as 65002 + neighbor 192.168.5.4 remote-as 65004 + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/msdp_topo2/r5/pimd.conf b/tests/topotests/msdp_topo2/r5/pimd.conf new file mode 100644 index 0000000000..e6cdd14c82 --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/pimd.conf @@ -0,0 +1,20 @@ +! debug pim +! debug pim zebra +! +interface lo + ip pim + ip pim use-source 10.254.254.5 +! +interface r5-eth0 + ip pim +! +interface r5-eth1 + ip pim +! +interface r5-eth2 + ip pim + ip igmp +! +ip msdp peer 192.168.2.2 source 192.168.2.5 +ip msdp peer 192.168.5.4 source 192.168.5.5 +ip pim rp 10.254.254.5 diff --git a/tests/topotests/msdp_topo2/r5/zebra.conf b/tests/topotests/msdp_topo2/r5/zebra.conf new file mode 100644 index 0000000000..195e003510 --- /dev/null +++ b/tests/topotests/msdp_topo2/r5/zebra.conf @@ -0,0 +1,14 @@ +ip forwarding +! +interface r5-eth0 + ip address 192.168.2.5/24 +! +interface r5-eth1 + ip address 192.168.5.5/24 +! +interface r5-eth2 + ip address 192.168.7.5/24 +! +interface lo + ip address 10.254.254.5/32 +! diff --git a/tests/topotests/msdp_topo2/test_msdp_topo2.py b/tests/topotests/msdp_topo2/test_msdp_topo2.py new file mode 100755 index 0000000000..def5368f41 --- /dev/null +++ b/tests/topotests/msdp_topo2/test_msdp_topo2.py @@ -0,0 +1,376 @@ +#!/usr/bin/env python +# SPDX-License-Identifier: ISC + +# +# test_msdp_topo1.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2024 by +# Adriano Marto Reis +# + +""" +test_msdp_topo2.py: Test the FRR PIM MSDP peer. + + ────────────────────► + shortest path + ┌──┐ + ┌───────┤r2├───────┐ +sender │ s1 └──┘ s2 │ receiver + ┌──┐ ┌─┴┐ ┌─┴┐ ┌──┐ + │h1├────┤r1│ │r5├────┤h2│ + └──┘ s6 └─┬┘ └─┬┘ s7 └──┘ + │ ┌──┐ ┌──┐ │ + └───┤r3├────┤r4├───┘ + s3 └──┘ s4 └──┘ s5 +""" + +import os +import sys +import json +from functools import partial +import pytest + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, "../")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest + +# Required to instantiate the topology builder class. +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +from lib.pim import McastTesterHelper + +pytestmark = [pytest.mark.bgpd, pytest.mark.pimd] + +app_helper = McastTesterHelper() + +MCAST_ADDR = "229.1.2.3" + +def build_topo(tgen): + "Build function" + + for routern in range(1, 6): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r2"]) + + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["r2"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["r1"]) + switch.add_link(tgen.gears["r3"]) + + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r3"]) + switch.add_link(tgen.gears["r4"]) + + switch = tgen.add_switch("s5") + switch.add_link(tgen.gears["r4"]) + switch.add_link(tgen.gears["r5"]) + + switch = tgen.add_switch("s6") + tgen.add_host("h1", "192.168.6.100/24", "via 192.168.6.1") + switch.add_link(tgen.gears["h1"]) + switch.add_link(tgen.gears["r1"]) + + switch = tgen.add_switch("s7") + tgen.add_host("h2", "192.168.7.100/24", "via 192.168.7.5") + switch.add_link(tgen.gears["h2"]) + switch.add_link(tgen.gears["r5"]) + + +def setup_module(mod): + "Sets up the pytest environment" + + tgen = Topogen(build_topo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + for rname, router in router_list.items(): + + daemon_file = "{}/{}/zebra.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_ZEBRA, daemon_file) + + daemon_file = "{}/{}/bgpd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_BGP, daemon_file) + + daemon_file = "{}/{}/pimd.conf".format(CWD, rname) + if os.path.isfile(daemon_file): + router.load_config(TopoRouter.RD_PIM, daemon_file) + + tgen.start_router() + + app_helper.init(tgen) + + +def teardown_module(): + "Teardown the pytest environment" + tgen = get_topogen() + app_helper.cleanup() + tgen.stop_topology() + + +def test_bgp_convergence(): + """ + Wait for BGP protocol convergence + All the loopback addresses (10.254.254.x) must be reachable from all + routers. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + routes = { + "r1": "10.254.254.1/32", + "r2": "10.254.254.2/32", + "r3": "10.254.254.3/32", + "r4": "10.254.254.4/32", + "r5": "10.254.254.5/32", + } + + for router1 in routes.keys(): + for router2, route in routes.items(): + if router1 != router2: + logger.info("waiting route {} in {}".format(route, router1)) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[router1], + "show ip route json", + {route: [{"protocol": "bgp"}]}, + ) + _, result = topotest.run_and_expect(test_func, None, count=130, wait=1) + assertmsg = '"{}" convergence failure'.format(router1) + assert result is None, assertmsg + + +def test_msdp_peers(): + """ + Waits for the MSPD peer connections to be established. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + expected_msdp_peers = { + "r1": { + "192.168.1.2": { + "peer": "192.168.1.2", + "local": "192.168.1.1", + "state": "established", + }, + "192.168.3.3": { + "peer": "192.168.3.3", + "local": "192.168.3.1", + "state": "established", + }, + }, + "r2": { + "192.168.1.1": { + "peer": "192.168.1.1", + "local": "192.168.1.2", + "state": "established", + }, + "192.168.2.5": { + "peer": "192.168.2.5", + "local": "192.168.2.2", + "state": "established", + }, + }, + "r3": { + "192.168.3.1": { + "peer": "192.168.3.1", + "local": "192.168.3.3", + "state": "established", + }, + "192.168.4.4": { + "peer": "192.168.4.4", + "local": "192.168.4.3", + "state": "established", + }, + }, + "r4": { + "192.168.4.3": { + "peer": "192.168.4.3", + "local": "192.168.4.4", + "state": "established", + }, + "192.168.5.5": { + "peer": "192.168.5.5", + "local": "192.168.5.4", + "state": "established", + }, + }, + "r5": { + "192.168.2.2": { + "peer": "192.168.2.2", + "local": "192.168.2.5", + "state": "established", + }, + "192.168.5.4": { + "peer": "192.168.5.4", + "local": "192.168.5.5", + "state": "established", + }, + }, + } + + for router, peers in expected_msdp_peers.items(): + logger.info("Waiting for {} msdp peer data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip msdp peer json", + peers, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + +def test_msdp_sa(): + """ + Waits for the MSDP SA to be propagated. + The MSDP SA must be present on all routers. The MSDP SA must indicate + the original RP. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + app_helper.run("h1", ["--send=0.7", MCAST_ADDR, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDR, "h2-eth0"]) + + expected_sa_r1 = { + MCAST_ADDR: { + "192.168.6.100": { + "source": "192.168.6.100", + "group": MCAST_ADDR, + "rp": "-", + "local": "yes", + } + } + } + + expected_sa_r2_r3_r4_r5 = { + MCAST_ADDR: { + "192.168.6.100": { + "source": "192.168.6.100", + "group": MCAST_ADDR, + "rp": "10.254.254.1", + "local": "no", + } + } + } + + expected_sa = { + "r1": expected_sa_r1, + "r2": expected_sa_r2_r3_r4_r5, + "r3": expected_sa_r2_r3_r4_r5, + "r4": expected_sa_r2_r3_r4_r5, + "r5": expected_sa_r2_r3_r4_r5, + } + + for router, sa in expected_sa.items(): + logger.info("Waiting for {} msdp peer data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip msdp sa json", + sa, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "multicast route convergence failure" + + +def test_mroute(): + """ + Wait for the multicast routes. + The multicast routes must connect the shortest path between h1 and h2: + h1 ─► r1 ─► r2 ─► r5 ─► h2 + + The routers r3 and r4 must have no multicast routes, as they are not + included in the shortest path between h1 and h2. + """ + + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + app_helper.run("h1", ["--send=0.7", MCAST_ADDR, "h1-eth0"]) + app_helper.run("h2", [MCAST_ADDR, "h2-eth0"]) + + expected_mroutes = { + "r1": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r1-eth2", + "oil": { + "r1-eth0": {"source": "192.168.6.100", "group": MCAST_ADDR}, + "r1-eth1": None, + }, + }, + }, + }, + "r2": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r2-eth0", + "oil": { + "r2-eth1": {"source": "192.168.6.100", "group": MCAST_ADDR}, + }, + }, + }, + }, + "r3": { + }, + "r4": { + }, + "r5": { + MCAST_ADDR: { + "192.168.6.100": { + "iif": "r5-eth0", + "oil": { + "r5-eth1": None, + "r5-eth2": {"source": "192.168.6.100", "group": MCAST_ADDR}, + }, + }, + }, + }, + } + + for router, mroute in expected_mroutes.items(): + logger.info("Waiting for {} mroute data".format(router)) + test_function = partial( + topotest.router_json_cmp, + tgen.gears[router], + "show ip mroute json", + mroute, + ) + _, val = topotest.run_and_expect(test_function, None, count=30, wait=1) + assert val is None, "mroute convergence failure" + + +def test_memory_leak(): + "Run the memory leak test and report results." + tgen = get_topogen() + if not tgen.is_memleak_enabled(): + pytest.skip("Memory leak test/report is disabled") + tgen.report_memory_leaks() + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py index 7eb5838037..b8eb67a32e 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm1.py @@ -221,7 +221,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py index 8b174bf9b8..bab7fddf9e 100644 --- a/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py +++ b/tests/topotests/multicast_pim6_sm_topo1/test_multicast_pim6_sm2.py @@ -175,7 +175,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py index 00d38fe647..5aa2ea65f7 100755 --- a/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py +++ b/tests/topotests/multicast_pim_dr_nondr_test/test_pim_dr_nondr_with_ospf_topo2.py @@ -20,10 +20,7 @@ import os import sys -import json import time -import datetime -from time import sleep import pytest # Save the Current Working Directory to find configuration files. @@ -43,14 +40,9 @@ write_test_footer, step, reset_config_on_routers, - shutdown_bringup_interface, apply_raw_config, add_interfaces_to_vlan, - kill_router_daemons, - start_router_daemons, - create_static_routes, check_router_status, - topo_daemons, required_linux_kernel_version, ) from lib.pim import ( @@ -59,9 +51,6 @@ verify_mroutes, clear_mroute, clear_pim_interface_traffic, - verify_pim_config, - verify_upstream_iif, - verify_multicast_traffic, verify_multicast_flag_state, verify_igmp_groups, McastTesterHelper, diff --git a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py index f87a90d198..eefa96a389 100755 --- a/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py +++ b/tests/topotests/multicast_pim_sm_topo1/test_multicast_pim_sm_topo1.py @@ -64,7 +64,6 @@ reset_config_on_routers, shutdown_bringup_interface, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -214,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py b/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py index b62f7bbfc9..0af2efcc7e 100755 --- a/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py +++ b/tests/topotests/multicast_pim_sm_topo2/test_multicast_pim_sm_topo2.py @@ -62,7 +62,6 @@ start_router_daemons, stop_router, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -211,7 +210,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py index ae27546703..9488ae02bf 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo3.py @@ -57,7 +57,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import ( start_topology, write_test_header, @@ -68,7 +68,6 @@ apply_raw_config, check_router_status, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -354,7 +353,7 @@ def verify_pim_stats_increament(stats_before, stats_after): """ for router, stats_data in stats_before.items(): - for stats, value in stats_data.items(): + for stats, _ in stats_data.items(): if stats_before[router][stats] >= stats_after[router][stats]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py index 825281afbb..11f3cc4254 100755 --- a/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py +++ b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py @@ -55,7 +55,6 @@ apply_raw_config, create_static_routes, required_linux_kernel_version, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -191,7 +190,7 @@ def reset_stats(stats): """ for router, state_data in stats.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): stats[router][state] = 0 logger.info( "[DUT: %s]: stats %s value has reset" " reset, Current value: %s", @@ -214,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] >= state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py index c492d95d40..38b9b2ecb1 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp.py @@ -87,7 +87,6 @@ import os import sys import time -from time import sleep import datetime import pytest @@ -112,10 +111,7 @@ reset_config_on_routers, step, shutdown_bringup_interface, - kill_router_daemons, - start_router_daemons, create_static_routes, - topo_daemons, ) from lib.pim import ( create_pim_config, @@ -128,10 +124,7 @@ verify_pim_rp_info, verify_pim_state, clear_pim_interface_traffic, - clear_igmp_interfaces, - clear_pim_interfaces, clear_mroute, - clear_mroute_verify, McastTesterHelper, ) diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py index 690c92f580..6f078a68d8 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp1.py @@ -112,9 +112,6 @@ reset_config_on_routers, step, shutdown_bringup_interface, - kill_router_daemons, - start_router_daemons, - create_static_routes, ) from lib.pim import ( create_pim_config, @@ -123,9 +120,7 @@ verify_join_state_and_timer, verify_mroutes, verify_pim_neighbors, - get_pim_interface_traffic, verify_pim_rp_info, - verify_pim_state, clear_pim_interface_traffic, clear_igmp_interfaces, clear_pim_interfaces, diff --git a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py index 8aa2e4efa1..48c0a78f98 100755 --- a/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py +++ b/tests/topotests/multicast_pim_static_rp_topo1/test_multicast_pim_static_rp2.py @@ -123,14 +123,9 @@ verify_join_state_and_timer, verify_mroutes, verify_pim_neighbors, - get_pim_interface_traffic, verify_pim_rp_info, - verify_pim_state, clear_pim_interface_traffic, - clear_igmp_interfaces, - clear_pim_interfaces, clear_mroute, - clear_mroute_verify, McastTesterHelper, ) diff --git a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py index 5728a4d08e..bbd5501dbb 100644 --- a/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py +++ b/tests/topotests/multicast_pim_uplink_topo1/test_multicast_pim_uplink_topo1.py @@ -25,7 +25,6 @@ import os import sys -import json import time import pytest @@ -356,7 +355,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] > state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" @@ -1682,7 +1681,7 @@ def test_mroutes_updated_correctly_after_source_interface_shut_noshut_p1(request step("Shut and No shut source interface multiple time") - for i in range(0, 2): + for _ in range(0, 2): step("Shut and no shut the source interface from DUT") intf_r1_i2 = topo["routers"]["r1"]["links"]["i2"]["interface"] shutdown_bringup_interface(tgen, "r1", intf_r1_i2, False) diff --git a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py index 1fb81c0d70..893b80083e 100644 --- a/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py +++ b/tests/topotests/multicast_pim_uplink_topo2/test_multicast_pim_uplink_topo2.py @@ -213,7 +213,7 @@ def verify_state_incremented(state_before, state_after): """ for router, state_data in state_before.items(): - for state, value in state_data.items(): + for state, _ in state_data.items(): if state_before[router][state] > state_after[router][state]: errormsg = ( "[DUT: %s]: state %s value has not" diff --git a/tests/topotests/nb_config/test_nb_config.py b/tests/topotests/nb_config/test_nb_config.py index 9099ef10b8..09d6407d5b 100644 --- a/tests/topotests/nb_config/test_nb_config.py +++ b/tests/topotests/nb_config/test_nb_config.py @@ -30,7 +30,7 @@ def tgen(request): tgen.start_topology() router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py index 81a22ebfaf..ffd9abc9d4 100644 --- a/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py +++ b/tests/topotests/nhrp_redundancy/test_nhrp_redundancy.py @@ -10,7 +10,6 @@ import os import sys import json -from time import sleep from functools import partial import pytest @@ -207,7 +206,7 @@ def test_protocols_convergence(): router_list = tgen.routers() # Check NHRP cache on servers and clients - for rname, router in router_list.items(): + for _, router in router_list.items(): json_file = "{}/{}/nhrp_cache.json".format(CWD, router.name) if not os.path.isfile(json_file): diff --git a/tests/topotests/nhrp_topo/r1/nhrpd.conf b/tests/topotests/nhrp_topo/r1/nhrpd.conf index e5224e4aab..8ade77d07d 100644 --- a/tests/topotests/nhrp_topo/r1/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r1/nhrpd.conf @@ -1,7 +1,8 @@ log stdout debugging ! debug nhrp all interface r1-gre0 - ip nhrp holdtime 500 + ip nhrp authentication secret + ip nhrp holdtime 10 ip nhrp shortcut ip nhrp network-id 42 ip nhrp nhs dynamic nbma 10.2.1.2 diff --git a/tests/topotests/nhrp_topo/r2/nhrpd.conf b/tests/topotests/nhrp_topo/r2/nhrpd.conf index f9185f9a63..d8e59936c8 100644 --- a/tests/topotests/nhrp_topo/r2/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r2/nhrpd.conf @@ -2,7 +2,8 @@ log stdout debugging nhrp nflog-group 1 interface r2-gre0 - ip nhrp holdtime 500 + ip nhrp authentication secret + ip nhrp holdtime 10 ip nhrp redirect ip nhrp network-id 42 ip nhrp registration no-unique diff --git a/tests/topotests/nhrp_topo/test_nhrp_topo.py b/tests/topotests/nhrp_topo/test_nhrp_topo.py index 284c58a8e7..8833003107 100644 --- a/tests/topotests/nhrp_topo/test_nhrp_topo.py +++ b/tests/topotests/nhrp_topo/test_nhrp_topo.py @@ -28,7 +28,7 @@ from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger -from lib.common_config import required_linux_kernel_version +from lib.common_config import required_linux_kernel_version, retry # Required to instantiate the topology builder class. @@ -214,19 +214,64 @@ def test_protocols_convergence(): def test_nhrp_connection(): "Assert that the NHRP peers can find themselves." tgen = get_topogen() + pingrouter = tgen.gears["r1"] + hubrouter = tgen.gears["r2"] if tgen.routers_have_failure(): pytest.skip(tgen.errors) - pingrouter = tgen.gears["r1"] - logger.info("Check Ping IPv4 from R1 to R2 = 10.255.255.2)") - output = pingrouter.run("ping 10.255.255.2 -f -c 1000") - logger.info(output) - if "1000 packets transmitted, 1000 received" not in output: - assertmsg = "expected ping IPv4 from R1 to R2 should be ok" - assert 0, assertmsg - else: - logger.info("Check Ping IPv4 from R1 to R2 OK") - + def ping_helper(): + output = pingrouter.run("ping 10.255.255.2 -f -c 100") + logger.info(output) + return output + + # force session to reinitialize + def relink_session(): + for r in ["r1", "r2"]: + tgen.gears[r].vtysh_cmd("clear ip nhrp cache") + tgen.net[r].cmd("ip l del {}-gre0".format(r)); + _populate_iface(); + + @retry(retry_timeout=40, initial_wait=5) + def verify_same_password(): + output = ping_helper() + if "100 packets transmitted, 100 received" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 should be ok" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 OK") + + @retry(retry_timeout=40, initial_wait=5) + def verify_mismatched_password(): + output = ping_helper() + if "Network is unreachable" not in output: + assertmsg = "expected ping IPv4 from R1 to R2 - should be down" + assert 0, assertmsg + else: + logger.info("Check Ping IPv4 from R1 to R2 missing - OK") + + ### Passwords are the same + logger.info("Check Ping IPv4 from R1 to R2 = 10.255.255.2") + verify_same_password() + + ### Passwords are different + logger.info("Modify password and send ping again, should drop") + hubrouter.vtysh_cmd(""" + configure + interface r2-gre0 + ip nhrp authentication secret12 + """) + relink_session() + verify_mismatched_password() + + ### Passwords are the same - again + logger.info("Recover password and verify conectivity is back") + hubrouter.vtysh_cmd(""" + configure + interface r2-gre0 + ip nhrp authentication secret + """) + relink_session() + verify_same_password() def test_route_install(): "Test use of NHRP routes by other protocols (sharpd here)." diff --git a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py index 45e1bc8db3..ba705e3dfc 100755 --- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py +++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py @@ -135,7 +135,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py b/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py index 8e7a7ea40a..077a9e4205 100644 --- a/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py +++ b/tests/topotests/ospf6_loopback_cost/test_ospf6_loopback_cost.py @@ -30,7 +30,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen def setup_module(mod): @@ -46,7 +46,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py index 142acf1eb4..73a9022442 100644 --- a/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py +++ b/tests/topotests/ospf6_point_to_multipoint/test_ospf6_point_to_multipoint.py @@ -153,7 +153,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -229,7 +229,7 @@ def test_ospfv3_routingTable(): # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py index 5649757010..85075a79aa 100644 --- a/tests/topotests/ospf6_topo1/test_ospf6_topo1.py +++ b/tests/topotests/ospf6_topo1/test_ospf6_topo1.py @@ -153,7 +153,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -229,7 +229,7 @@ def test_ospfv3_routingTable(): # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command @@ -351,7 +351,7 @@ def test_ospfv3_routingTable_write_multiplier(): r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py index f982990987..ccf25a0fc8 100755 --- a/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py +++ b/tests/topotests/ospf6_topo1_vrf/test_ospf6_topo1_vrf.py @@ -186,7 +186,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -260,7 +260,7 @@ def test_ospfv3_routingTable(): # For debugging, uncomment the next line # tgen.mininet_cli() # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command @@ -391,7 +391,7 @@ def test_ospfv3_routingTable_write_multiplier(): r1.vtysh_cmd("clear ipv6 ospf interface r1-sw5") # Verify OSPFv3 Routing Table - for router, rnode in tgen.routers().items(): + for router, _ in tgen.routers().items(): logger.info('Waiting for router "%s" convergence', router) # Load expected results from the command diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py index 0531e81d44..18b72772fe 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_topo1.py @@ -147,7 +147,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -2893,7 +2893,7 @@ def test_ospf_type5_summary_tc51_p2(request): step("Configure and re configure all the commands 10 times in a loop.") - for itrate in range(0, 10): + for _ in range(0, 10): ospf_summ_r1 = { "r0": { "ospf": { diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py index 603aeadb85..cdc5d126b4 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_asbr_summary_type7_lsa.py @@ -139,7 +139,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py index 8dd103013b..922c5a0e0b 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_authentication.py @@ -109,7 +109,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py index e58f081f96..dc237e9512 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_chaos.py @@ -118,7 +118,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py index aba313db9f..21e767522a 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_ecmp.py @@ -121,7 +121,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -193,7 +193,7 @@ def test_ospf_ecmp_tc16_p0(request): step("Verify that route in R2 in stalled with 8 next hops.") nh = [] - for item in range(1, 7): + for _ in range(1, 7): nh.append(topo["routers"]["r0"]["links"]["r1-link1"]["ipv4"].split("/")[0]) nh2 = topo["routers"]["r0"]["links"]["r1"]["ipv4"].split("/")[0] diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py index 62b8212203..7c37af02ac 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_flood_reduction.py @@ -51,7 +51,6 @@ create_static_routes, step, topo_daemons, - shutdown_bringup_interface, check_router_status, start_topology, write_test_header, @@ -65,8 +64,6 @@ write_test_header, write_test_footer, reset_config_on_routers, - stop_router, - start_router, step, create_static_routes, kill_router_daemons, @@ -163,7 +160,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py index 4a40b3e9ec..9c531c03ab 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_nssa.py @@ -119,7 +119,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py index a90d7dbdc0..6aec98c71b 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_p2mp.py @@ -105,7 +105,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py index c9f43cdfe4..eee51796c9 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_routemaps.py @@ -134,7 +134,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py index d169245f4e..193f5c8c5f 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_rte_calc.py @@ -130,7 +130,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -208,7 +208,7 @@ def test_ospf_redistribution_tc5_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r1" - for num in range(0, nretry): + for _ in range(0, nretry): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break @@ -332,7 +332,7 @@ def test_ospf_redistribution_tc6_p0(request): assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) dut = "r1" - for num in range(0, nretry): + for _ in range(0, nretry): result = verify_ospf_rib(tgen, dut, input_dict, next_hop=nh, expected=False) if result is not True: break diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py index 59afc7a8af..33841b9ab2 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_single_area.py @@ -115,7 +115,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py index ade55321f9..2d16379952 100644 --- a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py +++ b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.py @@ -72,7 +72,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py index 79374281cb..3bed390b18 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper1.py @@ -29,7 +29,6 @@ write_test_footer, reset_config_on_routers, step, - create_interfaces_cfg, scapy_send_raw_packet, ) @@ -38,7 +37,6 @@ from lib.ospf import ( verify_ospf_neighbor, - clear_ospf, verify_ospf_gr_helper, create_router_ospf, ) diff --git a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py index 3be28196d8..a9028673d2 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper3.py @@ -29,7 +29,6 @@ write_test_footer, reset_config_on_routers, step, - create_interfaces_cfg, scapy_send_raw_packet, ) @@ -38,7 +37,6 @@ from lib.ospf import ( verify_ospf_neighbor, - clear_ospf, verify_ospf_gr_helper, create_router_ospf, ) diff --git a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py index 73185d501d..73b660e590 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -144,7 +144,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py index 590b0d5e68..ea4507736e 100644 --- a/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py +++ b/tests/topotests/ospf_instance_redistribute/test_ospf_instance_redistribute.py @@ -15,7 +15,6 @@ """ import os -import re import sys import pytest import json diff --git a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py index ea96265176..b97b86bff9 100644 --- a/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py +++ b/tests/topotests/ospf_metric_propagation/test_ospf_metric_propagation.py @@ -11,14 +11,13 @@ import os import sys import json -from time import sleep from functools import partial import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger @@ -166,7 +165,7 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py index ee0a0f6c3b..10a0051a47 100644 --- a/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py +++ b/tests/topotests/ospf_multi_vrf_bgp_route_leak/test_ospf_multi_vrf_bgp_route_leak.py @@ -16,7 +16,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger @@ -139,7 +139,7 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py index 23eef8f5a6..eae8806a59 100644 --- a/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py +++ b/tests/topotests/ospf_netns_vrf/test_ospf_netns_vrf.py @@ -104,13 +104,13 @@ def setup_module(mod): tgen.set_error("unsupported version") -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() # Move interfaces out of vrf namespace and delete the namespace router_list = tgen.routers() - for rname, router in router_list.items(): + for rname, _ in router_list.items(): tgen.net[rname].reset_intf_netns(rname + "-eth0") tgen.net[rname].reset_intf_netns(rname + "-eth1") tgen.net[rname].delete_netns(rname + "-ospf-cust1") diff --git a/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py b/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py index d8cd1322bd..4a67fa33a6 100644 --- a/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py +++ b/tests/topotests/ospf_nssa_topo1/test_ospf_nssa_topo1.py @@ -106,7 +106,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf index cb4538c0e3..89f255bb44 100644 --- a/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r1/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all + hostname r1 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf index 0ca8aec3bf..429330987e 100644 --- a/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r2/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r2 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf index 41ea70d443..eada78450e 100644 --- a/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r3/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r3 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf index 21fa9c72f9..3146ea0957 100644 --- a/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf +++ b/tests/topotests/ospf_p2mp/r4/frr-p2mp.conf @@ -1,4 +1,10 @@ ! +!log file ospfd.log debug +! debug ospf event +! debug ospf client +! debug ospf lsa +! debug ospf packet all +! hostname r4 password zebra log file /tmp/r1-frr.log diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py index 1f0f87959a..455c737f0d 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_broadcast.py @@ -9,7 +9,6 @@ import os import sys -import json from time import sleep from functools import partial import pytest @@ -17,13 +16,10 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -112,13 +108,15 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() -def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): +def verify_p2mp_interface( + tgen, router, nbr_cnt, nbr_adj_cnt, delay_reflood, nbr_filter +): "Verify the P2MP Configuration and interface settings" topo_router = tgen.gears[router] @@ -140,22 +138,6 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): "interfaces": { "r1-eth0": { "ospfEnabled": True, - "interfaceIp": { - "10.1.0.1": { - "ipAddress": "10.1.0.1", - "ipAddressPrefixlen": 24, - "ospfIfType": "Broadcast", - "routerId": "1.1.1.1", - "networkType": "POINTOMULTIPOINT", - "cost": 10, - "state": "Point-To-Point", - "nbrCount": nbr_cnt, - "nbrAdjacentCount": nbr_adj_cnt, - "prefixSuppression": False, - "p2mpDelayReflood": False, - "nbrFilterPrefixList": nbr_filter, - } - }, "ipAddress": "10.1.0.1", "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", @@ -168,7 +150,7 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, nbr_filter): "nbrCount": nbr_cnt, "nbrAdjacentCount": nbr_adj_cnt, "prefixSuppression": False, - "p2mpDelayReflood": False, + "p2mpDelayReflood": delay_reflood, "nbrFilterPrefixList": nbr_filter, } } @@ -201,17 +183,6 @@ def verify_non_p2mp_interface(tgen): "interfaces": { "r1-eth0": { "ospfEnabled": True, - "interfaceIp": { - "10.1.0.1": { - "ipAddress": "10.1.0.1", - "ipAddressPrefixlen": 24, - "ospfIfType": "Broadcast", - "routerId": "1.1.1.1", - "networkType": "BROADCAST", - "cost": 10, - "prefixSuppression": False, - } - }, "ipAddress": "10.1.0.1", "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", @@ -312,7 +283,7 @@ def test_p2mp_broadcast_interface(): pytest.skip("Skipped because of router(s) failure") step("Verify router r1 interface r1-eth0 p2mp configuration") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") step("Verify router r1 p2mp interface r1-eth0 neighbors") verify_p2mp_neighbor( @@ -337,7 +308,7 @@ def test_p2mp_broadcast_interface(): step("Verify router r1 interface r1-eth0 p2mp configuration application") r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf network point-to-multipoint") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, False, "N/A") step("Verify restablishment of r1-eth0 p2mp neighbors") verify_p2mp_neighbor( @@ -356,14 +327,14 @@ def test_p2mp_broadcast_interface(): verify_p2mp_route(tgen, "r1", "10.1.4.0/24", 24, "10.1.0.4", "r1-eth0") -def test_p2mp_broadcast_neighbor_filter(): +def p2mp_broadcast_neighbor_filter_common(delay_reflood): tgen = get_topogen() if tgen.routers_have_failure(): pytest.skip("Skipped because of router(s) failure") step("Verify router r1 interface r1-eth0 p2mp configuration") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Verify router r1 p2mp interface r1-eth0 neighbors") verify_p2mp_neighbor( @@ -394,7 +365,7 @@ def test_p2mp_broadcast_neighbor_filter(): assert neighbor_filter_cfg == " ip ospf neighbor-filter nbr-filter", assertmsg step("Verify non-existent neighbor-filter is not applied to r1 interfaces") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Add nbr-filter prefix-list configuration to r1") r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 200 permit any") @@ -402,7 +373,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and neighbors still adjacent" ) - verify_p2mp_interface(tgen, "r1", 3, 3, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "nbr-filter") step("Add nbr-filter prefix-list configuration to block r4") r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") @@ -410,7 +381,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and r4 is no longer adjacent" ) - verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") step("Verify route to r4 subnet is now through r2") @@ -422,7 +393,7 @@ def test_p2mp_broadcast_neighbor_filter(): step( "Verify neighbor-filter is now applied to r1 interface and r2 is no longer adjacent" ) - verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") step("Verify route to r4 and r2 subnet are now through r3") @@ -438,24 +409,105 @@ def test_p2mp_broadcast_neighbor_filter(): assert rc, assertmsg step("Verify interface neighbor-filter is removed and neighbors present") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") step("Add neighbor filter configuration and verify neighbors are filtered") r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") - verify_p2mp_interface(tgen, "r1", 1, 1, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 1, 1, delay_reflood, "nbr-filter") verify_p2mp_neighbor_missing(tgen, "r1", "2.2.2.2") verify_p2mp_neighbor_missing(tgen, "r1", "4.4.4.4") step("Remove nbr-filter prefix-list configuration to block r2 and verify neighbor") r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter seq 20") - verify_p2mp_interface(tgen, "r1", 2, 2, "nbr-filter") + verify_p2mp_interface(tgen, "r1", 2, 2, delay_reflood, "nbr-filter") verify_p2mp_neighbor( tgen, "r1", "2.2.2.2", "Full/DROther", "10.1.0.2", "r1-eth0:10.1.0.1" ) step("Delete nbr-filter prefix-list and verify neighbors are present") r1.vtysh_cmd("conf t\nno ip prefix-list nbr-filter") - verify_p2mp_interface(tgen, "r1", 3, 3, "N/A") + verify_p2mp_interface(tgen, "r1", 3, 3, delay_reflood, "N/A") + + +def test_p2mp_broadcast_neighbor_filter(): + p2mp_broadcast_neighbor_filter_common(False) + + +def test_p2mp_broadcast_neighbor_filter_delay_reflood(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip("Skipped because of router(s) failure") + + step("Modify router r1 interface r1-eth0 p2mp delay-reflood configuration") + r1 = tgen.gears["r1"] + r1.vtysh_cmd( + "conf t\ninterface r1-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + verify_p2mp_interface(tgen, "r1", 3, 3, True, "N/A") + + step("Modify router r2 interface r2-eth0 p2mp delay-reflood configuration") + r2 = tgen.gears["r2"] + r2.vtysh_cmd( + "conf t\ninterface r2-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r3 interface r3-eth0 p2mp delay-reflood configuration") + r3 = tgen.gears["r3"] + r3.vtysh_cmd( + "conf t\ninterface r3-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + step("Modify router r4 interface r4-eth0 p2mp delay-reflood configuration") + r4 = tgen.gears["r4"] + r4.vtysh_cmd( + "conf t\ninterface r4-eth0\nip ospf network point-to-multipoint delay-reflood" + ) + + p2mp_broadcast_neighbor_filter_common(True) + + step("Recreate a partial P2MP mesh with neighbor filters") + step("Add nbr-filter prefix-list configuration to block r4") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.3/32") + r1.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.4/32") + r1.vtysh_cmd("conf t\ninterface r1-eth0\nip ospf neighbor-filter nbr-filter") + + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r2.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.4/32") + r2.vtysh_cmd("conf t\ninterface r2-eth0\nip ospf neighbor-filter nbr-filter") + + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r3.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r3.vtysh_cmd("conf t\ninterface r3-eth0\nip ospf neighbor-filter nbr-filter") + + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 30 permit any") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 10 deny 10.1.0.1/32") + r4.vtysh_cmd("conf t\nip prefix-list nbr-filter seq 20 deny 10.1.0.2/32") + r4.vtysh_cmd("conf t\ninterface r4-eth0\nip ospf neighbor-filter nbr-filter") + + step( + "Add redistribution and spaced static routes to r1 to test delay flood retransmission" + ) + r1.vtysh_cmd("conf t\nrouter ospf\nredistribute static") + r1.vtysh_cmd("conf t\nip route 20.1.1.1/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.2/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.3/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.4/32 null0") + sleep(1) + r1.vtysh_cmd("conf t\nip route 20.1.1.5/32 null0") + sleep(1) + + step( + "Verify the routes are installed on r1 with delay-reflood in P2MP partial mesh" + ) + verify_p2mp_route(tgen, "r4", "20.1.1.1/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.2/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.3/32", 32, "10.1.0.3", "r4-eth0") + verify_p2mp_route(tgen, "r4", "20.1.1.4/32", 32, "10.1.0.3", "r4-eth0") def test_memory_leak(): diff --git a/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py index 175dca74e7..83137a8992 100644 --- a/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py +++ b/tests/topotests/ospf_p2mp/test_ospf_p2mp_non_broadcast.py @@ -10,7 +10,6 @@ import os import sys -import json from time import sleep from functools import partial import pytest @@ -18,13 +17,10 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -116,7 +112,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -144,22 +140,6 @@ def verify_p2mp_interface(tgen, router, nbr_cnt, nbr_adj_cnt, non_broadcast): "interfaces": { "r1-eth0": { "ospfEnabled": True, - "interfaceIp": { - "10.1.0.1": { - "ipAddress": "10.1.0.1", - "ipAddressPrefixlen": 24, - "ospfIfType": "Broadcast", - "routerId": "1.1.1.1", - "networkType": "POINTOMULTIPOINT", - "cost": 10, - "state": "Point-To-Point", - "nbrCount": nbr_cnt, - "nbrAdjacentCount": nbr_adj_cnt, - "prefixSuppression": False, - "p2mpDelayReflood": False, - "p2mpNonBroadcast": non_broadcast, - } - }, "ipAddress": "10.1.0.1", "ipAddressPrefixlen": 24, "ospfIfType": "Broadcast", diff --git a/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py b/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py index d5ea7ebc40..f91cba8d3c 100644 --- a/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py +++ b/tests/topotests/ospf_prefix_suppression/test_ospf_prefix_suppression.py @@ -10,21 +10,16 @@ import os import sys -import json -from time import sleep from functools import partial import pytest # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import ( - run_frr_cmd, - shutdown_bringup_interface, - start_router_daemons, step, ) @@ -125,7 +120,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_single_switch/test_ospf_single_switch.py b/tests/topotests/ospf_single_switch/test_ospf_single_switch.py index e53b5f5b1e..0a8d8456da 100644 --- a/tests/topotests/ospf_single_switch/test_ospf_single_switch.py +++ b/tests/topotests/ospf_single_switch/test_ospf_single_switch.py @@ -14,12 +14,11 @@ import pytest from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.topolog import logger from lib.common_config import verify_rib from lib.ospf import verify_ospf_rib -from _ast import Try pytestmark = pytest.mark.ospfd @@ -86,7 +85,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Tear-down the test environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py b/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py index 21ae143231..ec076bb3cc 100755 --- a/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py +++ b/tests/topotests/ospf_sr_te_topo1/test_ospf_sr_te_topo1.py @@ -164,7 +164,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py b/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py index 936b438e9d..bac585dd8f 100644 --- a/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py +++ b/tests/topotests/ospf_sr_topo1/test_ospf_sr_topo1.py @@ -136,7 +136,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py index 8b3fc5808a..7f9ad27eab 100644 --- a/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py +++ b/tests/topotests/ospf_suppress_fa/test_ospf_suppress_fa.py @@ -24,7 +24,6 @@ import sys import json from functools import partial -import re import pytest # Save the Current Working Directory to find configuration files. diff --git a/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py b/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py index f939f3f578..2466724888 100644 --- a/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py +++ b/tests/topotests/ospf_tilfa_topo1/test_ospf_tilfa_topo1.py @@ -110,7 +110,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/ospf_topo1/test_ospf_topo1.py b/tests/topotests/ospf_topo1/test_ospf_topo1.py index a079f5698f..b9bdee3db4 100644 --- a/tests/topotests/ospf_topo1/test_ospf_topo1.py +++ b/tests/topotests/ospf_topo1/test_ospf_topo1.py @@ -93,7 +93,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_topo2/test_ospf_topo2.py b/tests/topotests/ospf_topo2/test_ospf_topo2.py index 8be06e41af..45ae338a24 100644 --- a/tests/topotests/ospf_topo2/test_ospf_topo2.py +++ b/tests/topotests/ospf_topo2/test_ospf_topo2.py @@ -66,7 +66,7 @@ def tgen(request): router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_frr_config("frr.conf") tgen.start_router() diff --git a/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py index d07f5dc5c9..712c4e1d7c 100644 --- a/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py +++ b/tests/topotests/ospf_unnumbered/test_ospf_unnumbered.py @@ -89,7 +89,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py b/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py index c0dd85cba0..a97b114547 100644 --- a/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py +++ b/tests/topotests/ospf_unnumbered_point_to_multipoint/test_ospf_unnumbered_point_to_multipoint.py @@ -92,7 +92,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ospfapi/test_ospf_clientapi.py b/tests/topotests/ospfapi/test_ospf_clientapi.py index 626a9d3185..89a34ff9b5 100644 --- a/tests/topotests/ospfapi/test_ospf_clientapi.py +++ b/tests/topotests/ospfapi/test_ospf_clientapi.py @@ -16,7 +16,6 @@ import subprocess import sys import time -from datetime import datetime, timedelta from functools import partial import pytest @@ -35,8 +34,7 @@ # pylint: disable=C0413 # Import topogen and topotest helpers from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger +from lib.topogen import Topogen, TopoRouter pytestmark = [pytest.mark.ospfd] diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py index 49c25ab8f6..c431147e55 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_asbr_summary_topo1.py @@ -29,7 +29,6 @@ from lib.common_config import ( start_topology, write_test_header, - kill_router_daemons, write_test_footer, reset_config_on_routers, stop_router, @@ -37,7 +36,6 @@ verify_rib, create_static_routes, step, - start_router_daemons, create_route_maps, shutdown_bringup_interface, create_prefix_lists, @@ -163,7 +161,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -2456,7 +2454,7 @@ def test_ospfv3_type5_summary_tc51_p2(request): step("Configure and re configure all the commands 10 times in a loop.") - for itrate in range(0, 10): + for _ in range(0, 10): ospf_summ_r1 = { "r0": { "ospf6": { diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py index 00c98ac97c..5f88f6d835 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_authentication.py @@ -14,9 +14,7 @@ import time import pytest from time import sleep -from copy import deepcopy import json -from lib.topotest import frr_unicode pytestmark = pytest.mark.ospf6d @@ -39,11 +37,8 @@ shutdown_bringup_interface, ) from lib.topolog import logger -from lib.topojson import build_topo_from_json, build_config_from_json -from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface, clear_ospf -from ipaddress import IPv4Address - -# Global variables +from lib.topojson import build_config_from_json +from lib.ospf import verify_ospf6_neighbor, config_ospf6_interface topo = None # Reading the data from JSON File for topology creation jsonFile = "{}/ospfv3_authentication.json".format(CWD) @@ -118,7 +113,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. * `mod`: module name diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py index 0c1e3fa43e..45652a3ee8 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp.py @@ -122,7 +122,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -285,7 +285,7 @@ def test_ospfv3_ecmp_tc16_p0(request): step("Verify that route in R2 in stalled with 8 next hops.") nh = [] - for item in range(1, 7): + for _ in range(1, 7): nh.append(llip) llip = get_llip("r0", "r1") diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py index 7c6773260e..95f2493c2a 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_ecmp_lan.py @@ -13,11 +13,6 @@ import sys import time import pytest -import json -from copy import deepcopy -from ipaddress import IPv4Address -from lib.topotest import frr_unicode -import ipaddress # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -37,9 +32,6 @@ verify_rib, create_static_routes, step, - create_route_maps, - shutdown_bringup_interface, - create_interfaces_cfg, get_frr_ipv6_linklocal, ) from lib.topolog import logger @@ -47,16 +39,11 @@ from lib.ospf import ( verify_ospf6_neighbor, - config_ospf_interface, clear_ospf, verify_ospf6_rib, create_router_ospf, - verify_ospf6_interface, - verify_ospf6_database, - config_ospf6_interface, ) -from ipaddress import IPv6Address pytestmark = [pytest.mark.ospfd, pytest.mark.staticd] @@ -137,7 +124,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py index dc4ce88830..cc96cd1731 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py @@ -78,7 +78,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py index 5a6c377aef..4ad725e3e6 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa2.py @@ -13,15 +13,10 @@ import sys import time import pytest -from copy import deepcopy import ipaddress from lib.ospf import ( verify_ospf6_neighbor, - config_ospf6_interface, - clear_ospf, verify_ospf6_rib, - verify_ospf6_interface, - verify_ospf6_database, create_router_ospf, ) @@ -29,12 +24,6 @@ # Import topogen and topotest helpers from lib.topogen import Topogen, get_topogen -from lib.bgp import ( - verify_bgp_convergence, - create_router_bgp, - clear_bgp_and_verify, - verify_bgp_rib, -) from lib.topolog import logger from lib.common_config import ( start_topology, @@ -44,12 +33,9 @@ verify_rib, create_static_routes, step, - create_route_maps, - shutdown_bringup_interface, create_interfaces_cfg, check_router_status, ) -from ipaddress import IPv4Address from lib.topolog import logger from lib.topojson import build_config_from_json diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py index 069806a3ef..ff88badeeb 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_routemaps.py @@ -136,7 +136,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py index 916f655550..06989db894 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_rte_calc.py @@ -45,7 +45,6 @@ verify_ospf6_neighbor, clear_ospf, verify_ospf6_rib, - verify_ospf_database, create_router_ospf, config_ospf6_interface, verify_ospf6_interface, @@ -127,7 +126,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py index 3bafd27f24..d981a84597 100644 --- a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_single_area.py @@ -36,7 +36,6 @@ step, create_interfaces_cfg, create_debug_log_config, - apply_raw_config, ) from lib.topolog import logger from lib.topojson import build_config_from_json @@ -121,7 +120,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. @@ -389,6 +388,11 @@ def test_ospfv3_hello_tc10_p0(request): step("Bring up the base config as per the topology") reset_config_on_routers(tgen) + ospf_covergence = verify_ospf6_neighbor(tgen) + assert ( + ospf_covergence is True + ), "Testcase {} [01]: Reset Failed \n Error: {}".format(tc_name, ospf_covergence) + step("modify hello timer from default value to some other value on r1") topo1 = { @@ -403,7 +407,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [02]: Failed \n Error: {}".format( + tc_name, result + ) step( "verify that new timer value is configured and applied using " @@ -423,7 +429,9 @@ def test_ospfv3_hello_tc10_p0(request): } } result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [03]: Failed \n Error: {}".format( + tc_name, result + ) step("modify hello timer from default value to r1 hello timer on r2") @@ -439,7 +447,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [04]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -456,12 +466,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [05]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [06]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("reconfigure the default hello timer value to default on r1 and r2") @@ -478,7 +490,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [07]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -492,7 +506,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [08]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -509,12 +525,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [09]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [10]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("reconfigure the default hello timer value to default on r1 and r2") @@ -531,7 +549,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [11]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -545,7 +565,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [12]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -562,12 +584,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [13]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [14]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step("configure hello timer = 1 on r1 and r2") @@ -583,7 +607,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [15]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -597,7 +623,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [16]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -614,12 +642,14 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [17]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase Failed \n Error: {}".format( - ospf_covergence + assert ospf_covergence is True, "Testcase {} [18]: Failed \n Error: {}".format( + tc_name, ospf_covergence ) step(" Configure hello timer = 65535") @@ -635,7 +665,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [19]: Failed \n Error: {}".format( + tc_name, result + ) topo1 = { "r1": { @@ -649,7 +681,9 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [20]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that new timer value is configured.") input_dict = { @@ -666,11 +700,13 @@ def test_ospfv3_hello_tc10_p0(request): } dut = "r0" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [21]: Failed \n Error: {}".format( + tc_name, result + ) step("verify that ospf neighbours are full") ospf_covergence = verify_ospf6_neighbor(tgen, topo, dut=dut) - assert ospf_covergence is True, "Testcase {} : Failed \n Error: {}".format( + assert ospf_covergence is True, "Testcase {} [22]: Failed \n Error: {}".format( tc_name, ospf_covergence ) step(" Try configuring timer values outside range for example 65536") @@ -688,7 +724,7 @@ def test_ospfv3_hello_tc10_p0(request): result = create_interfaces_cfg(tgen, topo1) assert ( result is not True - ), "Testcase {} : Failed \n Create interface failed. Error: {}".format( + ), "Testcase {} [23]: Failed \n Create interface failed. Error: {}".format( tc_name, result ) @@ -707,13 +743,17 @@ def test_ospfv3_hello_tc10_p0(request): } result = create_interfaces_cfg(tgen, topo1) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [24]: Failed \n Error: {}".format( + tc_name, result + ) step("Verify that timer value is deleted from intf & set to default value 40 sec.") input_dict = {"r1": {"links": {"r0": {"ospf6": {"timerIntervalsConfigHello": 10}}}}} dut = "r1" result = verify_ospf6_interface(tgen, topo, dut=dut, input_dict=input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + assert result is True, "Testcase {} [25]: Failed \n Error: {}".format( + tc_name, result + ) write_test_footer(tc_name) diff --git a/tests/topotests/pim_acl/test_pim_acl.py b/tests/topotests/pim_acl/test_pim_acl.py index 6e5092dabb..d8eececf81 100755 --- a/tests/topotests/pim_acl/test_pim_acl.py +++ b/tests/topotests/pim_acl/test_pim_acl.py @@ -169,7 +169,7 @@ def setup_module(module): tgen.start_router() -def teardown_module(module): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py index 85b49aacc6..ce1abe42bb 100644 --- a/tests/topotests/pim_basic/test_pim.py +++ b/tests/topotests/pim_basic/test_pim.py @@ -88,7 +88,7 @@ def setup_module(mod): # tgen.mininet_cli() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/pim_igmp_vrf/test_pim_vrf.py b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py index 01c496d703..d6d879d45f 100755 --- a/tests/topotests/pim_igmp_vrf/test_pim_vrf.py +++ b/tests/topotests/pim_igmp_vrf/test_pim_vrf.py @@ -92,7 +92,7 @@ from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger from lib.topotest import iproute2_is_vrf_capable -from lib.common_config import required_linux_kernel_version, retry +from lib.common_config import required_linux_kernel_version from lib.pim import McastTesterHelper @@ -205,7 +205,7 @@ def setup_module(module): ) -def teardown_module(module): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py index 7d958fd496..c07b1ffc15 100644 --- a/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py +++ b/tests/topotests/rip_allow_ecmp/test_rip_allow_ecmp.py @@ -20,7 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripd] @@ -39,7 +39,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py b/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py index d03d5479fd..26680f5460 100644 --- a/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py +++ b/tests/topotests/rip_bfd_topo1/test_rip_bfd_topo1.py @@ -20,7 +20,6 @@ from functools import partial from lib import topotest from lib.topogen import Topogen, TopoRouter -from lib.topolog import logger pytestmark = [ pytest.mark.bfdd, diff --git a/tests/topotests/rip_passive_interface/test_rip_passive_interface.py b/tests/topotests/rip_passive_interface/test_rip_passive_interface.py index c2b28c4a3e..ebc36d1fdc 100644 --- a/tests/topotests/rip_passive_interface/test_rip_passive_interface.py +++ b/tests/topotests/rip_passive_interface/test_rip_passive_interface.py @@ -21,7 +21,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripd] @@ -40,7 +40,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/rip_topo1/r1/show_ip_rip.ref b/tests/topotests/rip_topo1/r1/show_ip_rip.ref index a0b77c886e..b49a042dac 100644 --- a/tests/topotests/rip_topo1/r1/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r1/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r2/show_ip_rip.ref b/tests/topotests/rip_topo1/r2/show_ip_rip.ref index b61fb45eac..d0e7e81bc5 100644 --- a/tests/topotests/rip_topo1/r2/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r2/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/rip_topo1/r3/show_ip_rip.ref b/tests/topotests/rip_topo1/r3/show_ip_rip.ref index 1df299b5e6..bb4afc76b7 100644 --- a/tests/topotests/rip_topo1/r3/show_ip_rip.ref +++ b/tests/topotests/rip_topo1/r3/show_ip_rip.ref @@ -1,4 +1,7 @@ -Codes: R - RIP, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIP, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface diff --git a/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py b/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py index 08bb999928..060b558f0d 100644 --- a/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py +++ b/tests/topotests/ripng_allow_ecmp/test_ripng_allow_ecmp.py @@ -20,7 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topogen import Topogen, get_topogen from lib.common_config import step pytestmark = [pytest.mark.ripngd] @@ -39,7 +39,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ripng_route_map/test_ripng_route_map.py b/tests/topotests/ripng_route_map/test_ripng_route_map.py index e1cc88e9b6..4fadb5fbcf 100644 --- a/tests/topotests/ripng_route_map/test_ripng_route_map.py +++ b/tests/topotests/ripng_route_map/test_ripng_route_map.py @@ -20,8 +20,7 @@ # pylint: disable=C0413 from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.common_config import step +from lib.topogen import Topogen, get_topogen pytestmark = [pytest.mark.ripngd] @@ -39,7 +38,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref index 30d0f31e18..8645979cc0 100644 --- a/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r1/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref index fe5bcc8b31..2c4db1ab54 100644 --- a/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r2/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref index 909ad663ba..2ba0aa6d8f 100644 --- a/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref +++ b/tests/topotests/ripng_topo1/r3/show_ipv6_ripng.ref @@ -1,4 +1,7 @@ -Codes: R - RIPng, C - connected, S - Static, O - OSPF, B - BGP +Codes: K - kernel route, C - connected, L - local, S - static, + R - RIPng, O - OSPF, I - IS-IS, B - BGP, E - EIGRP, N - NHRP, + T - Table, v - VNC, V - VNC-Direct, A - Babel, F - PBR, + f - OpenFabric, t - Table-Direct Sub-codes: (n) - normal, (s) - static, (d) - default, (r) - redistribute, (i) - interface, (a/S) - aggregated/Suppressed diff --git a/tests/topotests/route_scale/scale_test_common.py b/tests/topotests/route_scale/scale_test_common.py index b3cba1cb4e..0b239dc04b 100644 --- a/tests/topotests/route_scale/scale_test_common.py +++ b/tests/topotests/route_scale/scale_test_common.py @@ -165,7 +165,7 @@ def route_install_helper(iter): # Table of defaults, used for timeout values and 'expected' objects scale_defaults = dict( - zip(scale_keys, [None, None, 10, 50, expected_installed, expected_removed]) + zip(scale_keys, [None, None, 10, 60, expected_installed, expected_removed]) ) # List of params for each step in the test; note extra time given @@ -182,7 +182,6 @@ def route_install_helper(iter): # Build up a list of dicts with params for each step of the test; # use defaults where the step doesn't supply a value - scale_setups = [] s = scale_steps[iter] d = dict(zip(scale_keys, s)) diff --git a/tests/topotests/route_scale/test_route_scale1.py b/tests/topotests/route_scale/test_route_scale1.py index ccbdd51595..68af979c2f 100644 --- a/tests/topotests/route_scale/test_route_scale1.py +++ b/tests/topotests/route_scale/test_route_scale1.py @@ -14,11 +14,8 @@ """ import os -import re import sys import pytest -import json -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -26,9 +23,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from scale_test_common import ( scale_build_common, diff --git a/tests/topotests/route_scale/test_route_scale2.py b/tests/topotests/route_scale/test_route_scale2.py index e244d4fbbc..4be8554a0f 100644 --- a/tests/topotests/route_scale/test_route_scale2.py +++ b/tests/topotests/route_scale/test_route_scale2.py @@ -14,11 +14,8 @@ """ import os -import re import sys import pytest -import json -from functools import partial # Save the Current Working Directory to find configuration files. CWD = os.path.dirname(os.path.realpath(__file__)) @@ -26,9 +23,6 @@ # pylint: disable=C0413 # Import topogen and topotest helpers -from lib import topotest -from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger from scale_test_common import ( scale_build_common, diff --git a/tests/topotests/simple_snmp_test/test_simple_snmp.py b/tests/topotests/simple_snmp_test/test_simple_snmp.py index ee02c7b519..0387e29274 100755 --- a/tests/topotests/simple_snmp_test/test_simple_snmp.py +++ b/tests/topotests/simple_snmp_test/test_simple_snmp.py @@ -79,7 +79,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() diff --git a/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py b/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py index b8bcab8d93..854bc1cdad 100755 --- a/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py +++ b/tests/topotests/srv6_encap_src_addr/test_srv6_encap_src_addr.py @@ -18,7 +18,6 @@ import sys import json import pytest -import functools CWD = os.path.dirname(os.path.realpath(__file__)) sys.path.append(os.path.join(CWD, "../")) @@ -56,7 +55,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() diff --git a/tests/topotests/srv6_locator/test_srv6_locator.py b/tests/topotests/srv6_locator/test_srv6_locator.py index 3a27d9c2fc..bab6746409 100755 --- a/tests/topotests/srv6_locator/test_srv6_locator.py +++ b/tests/topotests/srv6_locator/test_srv6_locator.py @@ -56,7 +56,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -81,12 +81,12 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py index 92980d3b17..d3df902aae 100755 --- a/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py +++ b/tests/topotests/srv6_locator_custom_bits_length/test_srv6_locator_custom_bits_length.py @@ -52,7 +52,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -77,12 +77,12 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=10, wait=0.5) + _, result = topotest.run_and_expect(func, None, count=10, wait=0.5) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py index 54187351b2..e0c05c5179 100755 --- a/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py +++ b/tests/topotests/srv6_locator_usid/test_srv6_locator_usid.py @@ -49,7 +49,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -70,13 +70,13 @@ def _check_sharpd_chunk(router, expected_chunk_file): def check_srv6_locator(router, expected_file): func = functools.partial(_check_srv6_locator, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=3) + _, result = topotest.run_and_expect(func, None, count=5, wait=3) assert result is None, "Failed" def check_sharpd_chunk(router, expected_file): func = functools.partial(_check_sharpd_chunk, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=5, wait=3) + _, result = topotest.run_and_expect(func, None, count=5, wait=3) assert result is None, "Failed" diff --git a/tests/topotests/srv6_static_route/test_srv6_route.py b/tests/topotests/srv6_static_route/test_srv6_route.py index 7a4cd39f2d..f23e199d4a 100755 --- a/tests/topotests/srv6_static_route/test_srv6_route.py +++ b/tests/topotests/srv6_static_route/test_srv6_route.py @@ -55,7 +55,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -74,7 +74,7 @@ def _check_srv6_static_route(router, expected_route_file): def check_srv6_static_route(router, expected_file): func = functools.partial(_check_srv6_static_route, router, expected_file) - success, result = topotest.run_and_expect(func, None, count=15, wait=1) + _, result = topotest.run_and_expect(func, None, count=15, wait=1) assert result is None, "Failed" # FOR DEVELOPER: diff --git a/tests/topotests/static_routing_mpls/test_static_routing_mpls.py b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py index c1e249cc8f..a0f11c0126 100644 --- a/tests/topotests/static_routing_mpls/test_static_routing_mpls.py +++ b/tests/topotests/static_routing_mpls/test_static_routing_mpls.py @@ -14,11 +14,8 @@ """ import os -import re import sys import pytest -import json -from functools import partial import functools # Save the Current Working Directory to find configuration files. @@ -113,7 +110,7 @@ def _check_mpls_state(router, interface, configured=True): test_func = functools.partial( _check_mpls_state_interface, router, interface, up=configured ) - success, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + success, _ = topotest.run_and_expect(test_func, None, count=10, wait=0.5) return success diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py index e01351506d..0d6b3e7b1d 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo2_ebgp.py @@ -150,7 +150,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py index 9d35b7dcd3..ff349f279e 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo3_ebgp.py @@ -134,7 +134,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py index 3e03055acd..c74d8d70a6 100644 --- a/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py +++ b/tests/topotests/static_routing_with_ebgp/test_static_routes_topo4_ebgp.py @@ -113,7 +113,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py index abae75e76e..926a9909e1 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo1_ibgp.py @@ -110,7 +110,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py index 820a736ad7..933e541095 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo2_ibgp.py @@ -152,7 +152,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py index 1ad963f314..9fabd9d571 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo3_ibgp.py @@ -133,7 +133,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment diff --git a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py index 0fc81aaf1e..f1b7606e79 100644 --- a/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py +++ b/tests/topotests/static_routing_with_ibgp/test_static_routes_topo4_ibgp.py @@ -111,7 +111,7 @@ def setup_module(mod): logger.info("Running setup_module() done") -def teardown_module(mod): +def teardown_module(): """ Teardown the pytest environment. diff --git a/tests/topotests/static_simple/test_static_simple.py b/tests/topotests/static_simple/test_static_simple.py index f862d81239..bb3580a1d8 100644 --- a/tests/topotests/static_simple/test_static_simple.py +++ b/tests/topotests/static_simple/test_static_simple.py @@ -13,11 +13,10 @@ import ipaddress import math import os -import sys import re import pytest -from lib.topogen import TopoRouter, Topogen, get_topogen +from lib.topogen import TopoRouter, Topogen from lib.topolog import logger from lib.common_config import retry, step @@ -80,7 +79,7 @@ def check_kernel(r1, super_prefix, count, add, is_blackhole, vrf, matchvia): kernel = r1.run(f"ip -4 route show{vrfstr}") logger.debug("checking kernel routing table%s:\n%s", vrfstr, kernel) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if not add: assert str(net) not in kernel continue @@ -116,7 +115,6 @@ def do_config( else: super_prefix = "2001::/48" if do_ipv6 else "10.0.0.0/8" - matchtype = "" matchvia = "" if via == "blackhole": pass @@ -146,7 +144,7 @@ def do_config( if vrf: f.write("vrf {}\n".format(vrf)) - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for _, net in enumerate(get_ip_networks(super_prefix, count)): if add: f.write("ip route {} {}\n".format(net, via)) else: diff --git a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py index 0b2937c12a..dc47527c74 100644 --- a/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py +++ b/tests/topotests/zebra_multiple_connected/test_zebra_multiple_connected.py @@ -15,7 +15,6 @@ """ import os -import re import sys import pytest import json @@ -29,7 +28,6 @@ # Import topogen and topotest helpers from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen -from lib.topolog import logger # Required to instantiate the topology builder class. @@ -157,7 +155,7 @@ def test_zebra_noprefix_connected(): test_func = partial( topotest.router_output_cmp, router, "show ip route 192.168.44.0/24", expected ) - result, diff = topotest.run_and_expect(test_func, "", count=20, wait=1) + result, _ = topotest.run_and_expect(test_func, "", count=20, wait=1) assert result, "Connected Route should not have been added" diff --git a/tests/topotests/zebra_netlink/test_zebra_netlink.py b/tests/topotests/zebra_netlink/test_zebra_netlink.py index d970c04ee2..3748f9c4e3 100644 --- a/tests/topotests/zebra_netlink/test_zebra_netlink.py +++ b/tests/topotests/zebra_netlink/test_zebra_netlink.py @@ -13,9 +13,7 @@ """ # pylint: disable=C0413 import ipaddress -import json import sys -from functools import partial import pytest from lib import topotest @@ -42,7 +40,7 @@ def tgen(request): # Initialize all routers. router_list = tgen.routers() - for rname, router in router_list.items(): + for _, router in router_list.items(): router.load_config(TopoRouter.RD_ZEBRA, "zebra.conf") router.load_config(TopoRouter.RD_SHARP) diff --git a/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py index fbef0fefc7..16e458062d 100644 --- a/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py +++ b/tests/topotests/zebra_nht_resolution/test_verify_nh_resolution.py @@ -16,7 +16,6 @@ import pytest from lib.common_config import ( - start_topology, verify_rib, verify_ip_nht, step, @@ -24,7 +23,6 @@ ) # pylint: disable=C0413 -from lib import topotest from lib.topogen import Topogen, TopoRouter, get_topogen from lib.topolog import logger diff --git a/tests/topotests/zebra_opaque/test_zebra_opaque.py b/tests/topotests/zebra_opaque/test_zebra_opaque.py index 25fbb97806..4f49a69bdc 100644 --- a/tests/topotests/zebra_opaque/test_zebra_opaque.py +++ b/tests/topotests/zebra_opaque/test_zebra_opaque.py @@ -32,7 +32,7 @@ def setup_module(mod): router_list = tgen.routers() - for i, (rname, router) in enumerate(router_list.items(), 1): + for _, (rname, router) in enumerate(router_list.items(), 1): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) ) @@ -49,7 +49,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): tgen = get_topogen() tgen.stop_topology() @@ -98,17 +98,17 @@ def _ospf6_converge(router): router = tgen.gears["r1"] test_func = functools.partial(_bgp_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see BGP community aliases "{}"'.format(router) router = tgen.gears["r3"] test_func = functools.partial(_ospf_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see OSPFv2 opaque attributes "{}"'.format(router) router = tgen.gears["r3"] test_func = functools.partial(_ospf6_converge, router) - success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) assert result is None, 'Cannot see OSPFv3 opaque attributes "{}"'.format(router) diff --git a/tests/topotests/zebra_rib/test_zebra_rib.py b/tests/topotests/zebra_rib/test_zebra_rib.py index 05036fa7ad..93296cd51a 100644 --- a/tests/topotests/zebra_rib/test_zebra_rib.py +++ b/tests/topotests/zebra_rib/test_zebra_rib.py @@ -71,7 +71,7 @@ def setup_module(mod): tgen.start_router() -def teardown_module(mod): +def teardown_module(): "Teardown the pytest environment" tgen = get_topogen() tgen.stop_topology() @@ -235,7 +235,7 @@ def check_initial_routes_installed(router): return topotest.json_cmp(output, expected) test_func = partial(check_initial_routes_installed, r1) - success, result = topotest.run_and_expect(test_func, None, count=40, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=40, wait=1) static_rmapfile = "%s/r1/static_rmap.ref" % (thisDir) expected = open(static_rmapfile).read().rstrip() diff --git a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py index 4a4cf0624f..f94b7d4a9c 100755 --- a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py +++ b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py @@ -80,7 +80,7 @@ def check_connected(router, dest, expected): expected = open_json_file(os.path.join(CWD, "{}/routes_setup.json".format("r1"))) test_func = partial(check_connected, r1, "2001::/64", expected) - success, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assert result is None, "Failed to fully setup connected routes needed" manifests = open_json_file(os.path.join(CWD, "{}/routes.json".format("r1"))) @@ -96,7 +96,7 @@ def check_connected(router, dest, expected): ) logger.info("CHECK {} {} {}".format(dest, nh, sid)) test_func = partial(check, r1, dest, manifest["out"]) - success, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) assert result is None, "Failed" diff --git a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py index 0dc87741aa..a90f5c9c98 100755 --- a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py +++ b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py @@ -101,7 +101,7 @@ def check(router, dest, expected): dest, manifest["out"], ) - success, result = topotest.run_and_expect(test_func, None, count=25, wait=1) + _, result = topotest.run_and_expect(test_func, None, count=25, wait=1) assert result is None, "Failed" diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl index f52f1a1616..2c773f7fbc 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -4668,6 +4668,7 @@ sub process { # check for new typedefs, only function parameters and sparse annotations # make sense. if ($line =~ /\btypedef\s/ && + $line !~ /\btypedef.*\s(pim_[^\s]+|[^\s]+_pim)\s*;/ && $line !~ /\btypedef\s+$Type\s*\(\s*\*?$Ident\s*\)\s*\(/ && $line !~ /\btypedef\s+$Type\s+$Ident\s*\(/ && $line !~ /\b$typeTypedefs\b/ && @@ -5149,7 +5150,7 @@ sub process { # none after. May be left adjacent to another # unary operator, or a cast } elsif ($op eq '!' || $op eq '~' || - $opv eq '*U' || $opv eq '-U' || + $opv eq '*U' || $opv eq '-U' || $opv eq '+U' || $opv eq '&U' || $opv eq '&&U') { if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) { if (ERROR("SPACING", diff --git a/tools/frr-reload.py b/tools/frr-reload.py index 461f0e8c61..a88f6b616d 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -94,7 +94,7 @@ def is_config_available(self): output = self("configure") - if "VTY configuration is locked by other VTY" in output: + if "configuration is locked" in output.lower(): log.error("vtysh 'configure' returned\n%s\n" % (output)) return False @@ -228,7 +228,7 @@ def get_normalized_interface_vrf(line): correctly and configurations are matched appropriately. """ - intf_vrf = re.search("interface (\S+) vrf (\S+)", line) + intf_vrf = re.search(r"interface (\S+) vrf (\S+)", line) if intf_vrf: old_line = "vrf %s" % intf_vrf.group(2) new_line = line.replace(old_line, "").strip() @@ -261,6 +261,8 @@ def get_normalized_interface_vrf(line): "router ospf6": {}, "router eigrp ": {}, "router babel": {}, + "router pim": {}, + "router pim6": {}, "mpls ldp": {"address-family ": {"interface ": {}}}, "l2vpn ": {"member pseudowire ": {}}, "key chain ": {"key ": {}}, @@ -306,12 +308,65 @@ def load_from_file(self, filename): file_output = self.vtysh.mark_file(filename) + vrf_context = None + pim_vrfs = [] + for line in file_output.split("\n"): line = line.strip() # Compress duplicate whitespaces line = " ".join(line.split()) + # Detect when we are within a vrf context for converting legacy PIM commands + if vrf_context: + re_vrf = re.match("^(exit-vrf|exit|end)$", line) + if re_vrf: + vrf_context = None + else: + re_vrf = re.match("^vrf ([a-z]+)$", line) + if re_vrf: + vrf_context = re_vrf.group(1) + + # Detect legacy pim commands that need to move under the router pim context + re_pim = re.match( + "^ip(v6)? pim ((ecmp|join|keep|mlag|packets|register|rp|send|spt|ssm).*)$", + line, + ) + if re_pim and re_pim.group(2): + router_pim = "router pim" + if re_pim.group(1): + router_pim += "6" + if vrf_context: + router_pim += " vrf " + vrf_context + + if vrf_context: + pim_vrfs.append(router_pim) + pim_vrfs.append(re_pim.group(2)) + pim_vrfs.append("exit") + line = "# PIM VRF LINE MOVED TO ROUTER PIM" + else: + self.lines.append(router_pim) + self.lines.append(re_pim.group(2)) + line = "exit" + + re_pim = re.match("^ip(v6)? ((ssmpingd|msdp).*)$", line) + if re_pim and re_pim.group(2): + router_pim = "router pim" + if re_pim.group(1): + router_pim += "6" + if vrf_context: + router_pim += " vrf " + vrf_context + + if vrf_context: + pim_vrfs.append(router_pim) + pim_vrfs.append(re_pim.group(2)) + pim_vrfs.append("exit") + line = "# PIM VRF LINE MOVED TO ROUTER PIM" + else: + self.lines.append(router_pim) + self.lines.append(re_pim.group(2)) + line = "exit" + # Remove 'vrf ' from 'interface vrf ' if line.startswith("interface ") and "vrf" in line: line = get_normalized_interface_vrf(line) @@ -348,6 +403,9 @@ def load_from_file(self, filename): self.lines.append(line) + if len(pim_vrfs) > 0: + self.lines.append(pim_vrfs) + self.load_contexts() def load_from_show_running(self, daemon): @@ -836,13 +894,13 @@ def bgp_delete_nbr_remote_as_line(lines_to_add): if ctx_keys[0] in pg_dict: for pg_key in pg_dict[ctx_keys[0]]: # Find 'neighbor remote-as' - pg_rmtas = "neighbor %s remote-as (\S+)" % pg_key + pg_rmtas = r"neighbor %s remote-as (\S+)" % pg_key re_pg_rmtas = re.search(pg_rmtas, line) if re_pg_rmtas: pg_dict[ctx_keys[0]][pg_key]["remoteas"] = True # Find 'neighbor [interface] peer-group ' - nb_pg = "neighbor (\S+) peer-group %s$" % pg_key + nb_pg = r"neighbor (\S+) peer-group %s$" % pg_key re_nbr_pg = re.search(nb_pg, line) if ( re_nbr_pg @@ -860,7 +918,7 @@ def bgp_delete_nbr_remote_as_line(lines_to_add): and line and line.startswith("neighbor ") ): - nbr_rmtas = "neighbor (\S+) remote-as.*" + nbr_rmtas = r"neighbor (\S+) remote-as.*" re_nbr_rmtas = re.search(nbr_rmtas, line) if re_nbr_rmtas and ctx_keys[0] in pg_dict: for pg in pg_dict[ctx_keys[0]]: @@ -889,8 +947,8 @@ def bgp_remove_neighbor_cfg(lines_to_del, del_nbr_dict): ): if ctx_keys[0] in del_nbr_dict: for nbr in del_nbr_dict[ctx_keys[0]]: - re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line) - nb_exp = "neighbor %s .*" % nbr + re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line) + nb_exp = r"neighbor %s .*" % nbr if not re_nbr_pg: re_nb = re.search(nb_exp, line) if re_nb: @@ -988,7 +1046,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): # neighbor uplink1 interface remote-as internal # # 'no neighbor peer [interface] remote-as <>' - nb_remoteas = "neighbor (\S+) .*remote-as (\S+)" + nb_remoteas = r"neighbor (\S+) .*remote-as (\S+)" re_nb_remoteas = re.search(nb_remoteas, line) if re_nb_remoteas: lines_to_del_to_app.append((ctx_keys, line)) @@ -996,7 +1054,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): # 'no neighbor peer [interface] peer-group <>' is in lines_to_del # copy the neighbor and look for all config removal lines associated # to neighbor and delete them from the lines_to_del - re_nbr_pg = re.search("neighbor (\S+) .*peer-group (\S+)", line) + re_nbr_pg = re.search(r"neighbor (\S+) .*peer-group (\S+)", line) if re_nbr_pg: if ctx_keys[0] not in del_nbr_dict: del_nbr_dict[ctx_keys[0]] = list() @@ -1035,7 +1093,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): if ctx_keys[0] in del_dict: for pg_key in del_dict[ctx_keys[0]]: # 'neighbor [interface] peer-group ' - nb_pg = "neighbor (\S+) .*peer-group %s$" % pg_key + nb_pg = r"neighbor (\S+) .*peer-group %s$" % pg_key re_nbr_pg = re.search(nb_pg, line) if ( re_nbr_pg @@ -1053,7 +1111,7 @@ def bgp_delete_move_lines(lines_to_add, lines_to_del): if ctx_keys[0] in del_dict: for pg in del_dict[ctx_keys[0]]: for nbr in del_dict[ctx_keys[0]][pg]: - nb_exp = "neighbor %s .*" % nbr + nb_exp = r"neighbor %s .*" % nbr re_nb = re.search(nb_exp, line) # add peer configs to delete list. if re_nb and line not in lines_to_del_to_del: @@ -1093,7 +1151,7 @@ def pim_delete_move_lines(lines_to_add, lines_to_del): # no ip msdp peer <> does not accept source so strip it off. if line and line.startswith("ip msdp peer "): - pim_msdp_peer = re.search("ip msdp peer (\S+) source (\S+)", line) + pim_msdp_peer = re.search(r"ip msdp peer (\S+) source (\S+)", line) if pim_msdp_peer: source_sub_str = "source %s" % pim_msdp_peer.group(2) new_line = line.replace(source_sub_str, "").strip() @@ -1186,10 +1244,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # # If so then chop the del line and the corresponding add lines re_swpx_int_peergroup = re.search( - "neighbor (\S+) interface peer-group (\S+)", line + r"neighbor (\S+) interface peer-group (\S+)", line ) re_swpx_int_v6only_peergroup = re.search( - "neighbor (\S+) interface v6only peer-group (\S+)", line + r"neighbor (\S+) interface v6only peer-group (\S+)", line ) if re_swpx_int_peergroup or re_swpx_int_v6only_peergroup: @@ -1246,7 +1304,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): if re_nbr_bfd_timers: nbr = re_nbr_bfd_timers.group(1) - bfd_nbr = "neighbor %s" % nbr + bfd_nbr = r"neighbor %s" % nbr bfd_search_string = bfd_nbr + r" bfd (\S+) (\S+) (\S+)" for ctx_keys, add_line in lines_to_add: @@ -1271,13 +1329,13 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # they actually match and if we are going from a very old style # command such that the neighbor command is under the `router # bgp ..` node that we need to handle that appropriately - re_nbr_rm = re.search("neighbor(.*)route-map(.*)(in|out)$", line) + re_nbr_rm = re.search(r"neighbor(.*)route-map(.*)(in|out)$", line) if re_nbr_rm: adjust_for_bgp_node = 0 neighbor_name = re_nbr_rm.group(1) rm_name_del = re_nbr_rm.group(2) dir = re_nbr_rm.group(3) - search = "neighbor%sroute-map(.*)%s" % (neighbor_name, dir) + search = r"neighbor%sroute-map(.*)%s" % (neighbor_name, dir) save_line = "EMPTY" for ctx_keys_al, add_line in lines_to_add: if ctx_keys_al[0].startswith("router bgp"): @@ -1330,10 +1388,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # # If so then chop the del line and the corresponding add lines re_swpx_int_remoteas = re.search( - "neighbor (\S+) interface remote-as (\S+)", line + r"neighbor (\S+) interface remote-as (\S+)", line ) re_swpx_int_v6only_remoteas = re.search( - "neighbor (\S+) interface v6only remote-as (\S+)", line + r"neighbor (\S+) interface v6only remote-as (\S+)", line ) if re_swpx_int_remoteas or re_swpx_int_v6only_remoteas: @@ -1373,7 +1431,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # unnecessary session resets. if "multipath-relax" in line: re_asrelax_new = re.search( - "^bgp\s+bestpath\s+as-path\s+multipath-relax$", line + r"^bgp\s+bestpath\s+as-path\s+multipath-relax$", line ) old_asrelax_cmd = "bgp bestpath as-path multipath-relax no-as-set" found_asrelax_old = line_exist(lines_to_add, ctx_keys, old_asrelax_cmd) @@ -1398,7 +1456,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # the new syntax. This causes an unnecessary 'no import-table' followed # by the same old 'ip import-table' which causes perturbations in # announced routes leading to traffic blackholes. Fix this issue. - re_importtbl = re.search("^ip\s+import-table\s+(\d+)$", ctx_keys[0]) + re_importtbl = re.search(r"^ip\s+import-table\s+(\d+)$", ctx_keys[0]) if re_importtbl: table_num = re_importtbl.group(1) for ctx in lines_to_add: @@ -1419,7 +1477,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # access-list FOO seq 5 permit 2.2.2.2/32 # ipv6 access-list BAR seq 5 permit 2:2:2::2/128 re_acl_pfxlst = re.search( - "^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(ip |ipv6 |)(prefix-list|access-list)(\s+\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_acl_pfxlst: @@ -1452,7 +1510,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # bgp large-community-list standard llist seq 5 permit 65001:65001:1 # bgp extcommunity-list standard elist seq 5 permit soo 123:123 re_bgp_lists = re.search( - "^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(bgp )(community-list|large-community-list|extcommunity-list)(\s+\S+\s+)(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_bgp_lists: @@ -1481,7 +1539,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): # Examples: # bgp as-path access-list important_internet_bgp_as_numbers seq 30 permit _40841_" re_bgp_as_path = re.search( - "^(bgp )(as-path )(access-list )(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", + r"^(bgp )(as-path )(access-list )(\S+\s+)(seq \d+\s+)(permit|deny)(.*)$", ctx_keys[0], ) if re_bgp_as_path: @@ -1511,7 +1569,7 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): and ctx_keys[2].startswith("vni") ): re_route_target = ( - re.search("^route-target import (.*)$", line) + re.search(r"^route-target import (.*)$", line) if line is not None else False ) @@ -1648,7 +1706,7 @@ def compare_context_objects(newconf, running): pcclist_to_del = [] candidates_to_add = [] delete_bgpd = False - area_stub_no_sum = "area (\S+) stub no-summary" + area_stub_no_sum = r"area (\S+) stub no-summary" deleted_keychains = [] # Find contexts that are in newconf but not in running @@ -1683,9 +1741,11 @@ def compare_context_objects(newconf, running): lines_to_del.append((running_ctx_keys, None)) # We cannot do 'no interface' or 'no vrf' in FRR, and so deal with it - elif running_ctx_keys[0].startswith("interface") or running_ctx_keys[ - 0 - ].startswith("vrf"): + elif ( + running_ctx_keys[0].startswith("interface") + or running_ctx_keys[0].startswith("vrf") + or running_ctx_keys[0].startswith("router pim") + ): for line in running_ctx.lines: lines_to_del.append((running_ctx_keys, line)) diff --git a/vtysh/.gitignore b/vtysh/.gitignore index a6c3d4abc6..9cbd248f2f 100644 --- a/vtysh/.gitignore +++ b/vtysh/.gitignore @@ -1,5 +1,6 @@ vtysh vtysh_cmd.c +vtysh_cmd.*.c # does not exist anymore - remove 2023-10-04 or so extract.pl diff --git a/vtysh/subdir.am b/vtysh/subdir.am index 2eae16d629..d39987eb83 100644 --- a/vtysh/subdir.am +++ b/vtysh/subdir.am @@ -17,9 +17,6 @@ vtysh_vtysh_SOURCES = \ vtysh/vtysh_user.c \ vtysh/vtysh_config.c \ # end -nodist_vtysh_vtysh_SOURCES = \ - vtysh/vtysh_cmd.c \ - # end noinst_HEADERS += \ vtysh/vtysh.h \ diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index b1c957d043..c43e1909e3 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -1161,14 +1161,12 @@ static char **new_completion(const char *text, int start, int end) } /* Vty node structures. */ -#ifdef HAVE_BGPD static struct cmd_node bgp_node = { .name = "bgp", .node = BGP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_BGPD */ static struct cmd_node rip_node = { .name = "rip", @@ -1177,7 +1175,6 @@ static struct cmd_node rip_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_ISISD static struct cmd_node isis_node = { .name = "isis", .node = ISIS_NODE, @@ -1205,16 +1202,13 @@ static struct cmd_node isis_srv6_node_msd_node = { .parent_node = ISIS_SRV6_NODE, .prompt = "%s(config-router-srv6-node-msd)# ", }; -#endif /* HAVE_ISISD */ -#ifdef HAVE_FABRICD static struct cmd_node openfabric_node = { .name = "openfabric", .node = OPENFABRIC_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_FABRICD */ static struct cmd_node interface_node = { .name = "interface", @@ -1237,7 +1231,6 @@ static struct cmd_node segment_routing_node = { .prompt = "%s(config-sr)# ", }; -#if defined(HAVE_PATHD) static struct cmd_node sr_traffic_eng_node = { .name = "sr traffic-eng", .node = SR_TRAFFIC_ENG_NODE, @@ -1293,7 +1286,6 @@ static struct cmd_node pcep_pce_config_node = { .parent_node = PCEP_NODE, .prompt = "%s(pcep-sr-te-pcep-pce-config)# ", }; -#endif /* HAVE_PATHD */ static struct cmd_node vrf_node = { .name = "vrf", @@ -1344,14 +1336,33 @@ static struct cmd_node srv6_encap_node = { .prompt = "%s(config-srv6-encap)# " }; -#ifdef HAVE_PBRD +static struct cmd_node srv6_sid_formats_node = { + .name = "srv6-formats", + .node = SRV6_SID_FORMATS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-formats)# ", +}; + +static struct cmd_node srv6_sid_format_usid_f3216_node = { + .name = "srv6-format-usid-f3216", + .node = SRV6_SID_FORMAT_USID_F3216_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .name = "srv6-format-uncompressed-f4024", + .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + static struct cmd_node pbr_map_node = { .name = "pbr-map", .node = PBRMAP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-pbr-map)# ", }; -#endif /* HAVE_PBRD */ static struct cmd_node zebra_node = { .name = "zebra", @@ -1360,7 +1371,6 @@ static struct cmd_node zebra_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_BGPD static struct cmd_node bgp_vpnv4_node = { .name = "bgp vpnv4", .node = BGP_VPNV4_NODE, @@ -1456,7 +1466,6 @@ static struct cmd_node bgp_ipv6l_node = { .no_xpath = true, }; -#ifdef ENABLE_BGP_VNC static struct cmd_node bgp_vnc_defaults_node = { .name = "bgp vnc defaults", .node = BGP_VNC_DEFAULTS_NODE, @@ -1484,7 +1493,6 @@ static struct cmd_node bgp_vnc_l2_group_node = { .parent_node = BGP_NODE, .prompt = "%s(config-router-vnc-l2-group)# ", }; -#endif /* ENABLE_BGP_VNC */ static struct cmd_node bmp_node = { .name = "bmp", @@ -1499,34 +1507,27 @@ static struct cmd_node bgp_srv6_node = { .parent_node = BGP_NODE, .prompt = "%s(config-router-srv6)# ", }; -#endif /* HAVE_BGPD */ -#ifdef HAVE_OSPFD static struct cmd_node ospf_node = { .name = "ospf", .node = OSPF_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_OSPFD */ -#ifdef HAVE_EIGRPD static struct cmd_node eigrp_node = { .name = "eigrp", .node = EIGRP_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_EIGRPD */ -#ifdef HAVE_BABELD static struct cmd_node babel_node = { .name = "babel", .node = BABEL_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-router)# ", }; -#endif /* HAVE_BABELD */ static struct cmd_node ripng_node = { .name = "ripng", @@ -1535,16 +1536,13 @@ static struct cmd_node ripng_node = { .prompt = "%s(config-router)# ", }; -#ifdef HAVE_OSPF6D static struct cmd_node ospf6_node = { .name = "ospf6", .node = OSPF6_NODE, .parent_node = CONFIG_NODE, .prompt = "%s(config-ospf6)# ", }; -#endif /* HAVE_OSPF6D */ -#ifdef HAVE_LDPD static struct cmd_node ldp_node = { .name = "ldp", .node = LDP_NODE, @@ -1593,7 +1591,6 @@ static struct cmd_node ldp_pseudowire_node = { .parent_node = LDP_L2VPN_NODE, .prompt = "%s(config-l2vpn-pw)# ", }; -#endif /* HAVE_LDPD */ static struct cmd_node keychain_node = { .name = "keychain", @@ -1616,7 +1613,6 @@ struct cmd_node link_params_node = { .prompt = "%s(config-link-params)# ", }; -#ifdef HAVE_BGPD static struct cmd_node rpki_node = { .name = "rpki", .node = RPKI_NODE, @@ -1631,9 +1627,6 @@ static struct cmd_node rpki_vrf_node = { .prompt = "%s(config-vrf-rpki)# ", }; -#endif /* HAVE_BGPD */ - -#if HAVE_BFDD > 0 static struct cmd_node bfd_node = { .name = "bfd", .node = BFD_NODE, @@ -1654,7 +1647,20 @@ static struct cmd_node bfd_profile_node = { .parent_node = BFD_NODE, .prompt = "%s(config-bfd-profile)# ", }; -#endif /* HAVE_BFDD */ + +static struct cmd_node pim_node = { + .name = "pim", + .node = PIM_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim)# ", +}; + +static struct cmd_node pim6_node = { + .name = "pim6", + .node = PIM6_NODE, + .parent_node = CONFIG_NODE, + .prompt = "%s(config-pim6)# ", +}; /* Defined in lib/vty.c */ extern struct cmd_node vty_node; @@ -1715,6 +1721,31 @@ DEFUNSH(VTYSH_ZEBRA, srv6_encap, srv6_encap_cmd, return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, srv6_sid_formats, srv6_sid_formats_cmd, "formats", + "Segment Routing SRv6 SID formats\n") +{ + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f3216_usid, srv6_sid_format_f3216_usid_cmd, + "format usid-f3216", + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + vty->node = SRV6_SID_FORMAT_USID_F3216_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, srv6_sid_format_f4024_uncompressed, srv6_sid_format_f4024_uncompressed_cmd, + "format uncompressed-f4024", + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + vty->node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_BGPD DEFUNSH(VTYSH_BGPD, router_bgp, router_bgp_cmd, "router bgp [ASNUM [ VIEWVRFNAME] [as-notation ]]", @@ -2367,6 +2398,30 @@ DEFUNSH(VTYSH_BFDD, bfd_profile_enter, bfd_profile_enter_cmd, } #endif /* HAVE_BFDD */ +#ifdef HAVE_PIMD +DEFUNSH(VTYSH_PIMD, router_pim, router_pim_cmd, + "router pim [vrf NAME]", + ROUTER_STR + "Start PIM configuration\n" + VRF_CMD_HELP_STR) +{ + vty->node = PIM_NODE; + return CMD_SUCCESS; +} +#endif /* HAVE_PIMD */ + +#ifdef HAVE_PIM6D +DEFUNSH(VTYSH_PIM6D, router_pim6, router_pim6_cmd, + "router pim6 [vrf NAME]", + ROUTER_STR + "Start PIMv6 configuration\n" + VRF_CMD_HELP_STR) +{ + vty->node = PIM6_NODE; + return CMD_SUCCESS; +} +#endif /* HAVE_PIM6D*/ + DEFUNSH(VTYSH_ALL, vtysh_line_vty, vtysh_line_vty_cmd, "line vty", "Configure a terminal line\n" "Virtual terminal\n") @@ -2515,6 +2570,23 @@ DEFUNSH(VTYSH_ZEBRA, exit_srv6_encap, exit_srv6_encap_cmd, "exit", return CMD_SUCCESS; } +DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_formats, exit_srv6_sid_formats_cmd, "exit", + "Exit from SRv6 SID formats configuration mode\n") +{ + if (vty->node == SRV6_SID_FORMATS_NODE) + vty->node = SRV6_NODE; + return CMD_SUCCESS; +} + +DEFUNSH(VTYSH_ZEBRA, exit_srv6_sid_format, exit_srv6_sid_format_cmd, + "exit", "Exit from SRv6 SID format configuration mode\n") +{ + if (vty->node == SRV6_SID_FORMAT_USID_F3216_NODE || + vty->node == SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE) + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + #ifdef HAVE_RIPD DEFUNSH(VTYSH_MGMTD, vtysh_exit_ripd, vtysh_exit_ripd_cmd, "exit", "Exit current mode and down to previous mode\n") @@ -2763,6 +2835,34 @@ DEFUNSH(VTYSH_PATHD, vtysh_quit_pathd, vtysh_quit_pathd_cmd, "quit", } #endif /* HAVE_PATHD */ +#ifdef HAVE_PIMD +DEFUNSH(VTYSH_PIMD, vtysh_exit_pimd, vtysh_exit_pimd_cmd, "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit(vty); +} + +DEFUNSH(VTYSH_PIMD, vtysh_quit_pimd, vtysh_quit_pimd_cmd, "quit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_pimd(self, vty, argc, argv); +} +#endif /* HAVE_PIMD */ + +#ifdef HAVE_PIM6D +DEFUNSH(VTYSH_PIM6D, vtysh_exit_pim6d, vtysh_exit_pim6d_cmd, "exit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit(vty); +} + +DEFUNSH(VTYSH_PIM6D, vtysh_quit_pim6d, vtysh_quit_pim6d_cmd, "quit", + "Exit current mode and down to previous mode\n") +{ + return vtysh_exit_pim6d(self, vty, argc, argv); +} +#endif /* HAVE_PIM6D */ + DEFUNSH(VTYSH_ALL, vtysh_exit_line_vty, vtysh_exit_line_vty_cmd, "exit", "Exit current mode and down to previous mode\n") { @@ -2925,9 +3025,6 @@ static int show_one_daemon(struct vty *vty, struct cmd_token **argv, int argc, return ret; } -#if CONFDATE > 20240707 - CPP_NOTICE("Remove `show thread ...` commands") -#endif DEFUN (vtysh_show_event_timer, vtysh_show_event_timer_cmd, "show event timers", @@ -4824,15 +4921,87 @@ void vtysh_init_vty(void) cmd_init(0); cmd_variable_handler_register(vtysh_var_handler); + install_node(&bgp_node); + install_node(&babel_node); + install_node(&bgp_vpnv4_node); + install_node(&bgp_vpnv6_node); + install_node(&bgp_flowspecv4_node); + install_node(&bgp_flowspecv6_node); + install_node(&bgp_ipv4_node); + install_node(&bgp_ipv4m_node); + install_node(&bgp_ipv4l_node); + install_node(&bgp_ipv6_node); + install_node(&bgp_ipv6m_node); + install_node(&bgp_ipv6l_node); + install_node(&bgp_vrf_policy_node); + install_node(&bgp_vnc_defaults_node); + install_node(&bgp_vnc_nve_group_node); + install_node(&bgp_vnc_l2_group_node); + install_node(&bgp_evpn_node); + install_node(&bgp_evpn_vni_node); + install_node(&rpki_node); + install_node(&bmp_node); + install_node(&bgp_srv6_node); + install_node(&rip_node); + install_node(&ripng_node); + install_node(&ospf_node); + install_node(&ospf6_node); + install_node(&ldp_node); + install_node(&ldp_ipv4_node); + install_node(&ldp_ipv6_node); + install_node(&ldp_ipv4_iface_node); + install_node(&ldp_ipv6_iface_node); + install_node(&ldp_l2vpn_node); + install_node(&ldp_pseudowire_node); + install_node(&eigrp_node); + install_node(&isis_node); + install_node(&isis_flex_algo_node); + install_node(&isis_srv6_node); + install_node(&isis_srv6_node_msd_node); + install_node(&openfabric_node); + install_node(&pbr_map_node); + install_node(&bfd_node); + install_node(&bfd_peer_node); + install_node(&bfd_profile_node); + install_node(&segment_routing_node); + install_node(&sr_traffic_eng_node); + install_node(&srte_segment_list_node); + install_node(&srte_policy_node); + install_node(&srte_candidate_dyn_node); + install_node(&pcep_node); + install_node(&pcep_pcc_node); + install_node(&pcep_pce_node); + install_node(&pcep_pce_config_node); + install_node(&keychain_node); + install_node(&keychain_key_node); + install_node(&nh_group_node); + install_node(&zebra_node); + install_node(&interface_node); + install_node(&pim_node); + install_node(&pim6_node); + install_node(&link_params_node); + install_node(&pw_node); + install_node(&vrf_node); + install_node(&rpki_vrf_node); + install_node(&rmap_node); + install_node(&vty_node); + install_node(&srv6_node); + install_node(&srv6_locs_node); + install_node(&srv6_loc_node); + install_node(&srv6_encap_node); + install_node(&srv6_sid_formats_node); + install_node(&srv6_sid_format_usid_f3216_node); + install_node(&srv6_sid_format_uncompressed_f4024_node); + + vtysh_init_cmd(); + /* bgpd */ #ifdef HAVE_BGPD - install_node(&bgp_node); install_element(CONFIG_NODE, &router_bgp_cmd); install_element(BGP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_NODE, &vtysh_end_all_cmd); - install_node(&bgp_vpnv4_node); install_element(BGP_NODE, &address_family_ipv4_vpn_cmd); #ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv4_cmd); @@ -4842,7 +5011,6 @@ void vtysh_init_vty(void) install_element(BGP_VPNV4_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV4_NODE, &exit_address_family_cmd); - install_node(&bgp_vpnv6_node); install_element(BGP_NODE, &address_family_ipv6_vpn_cmd); #ifdef KEEP_OLD_VPN_COMMANDS install_element(BGP_NODE, &address_family_vpnv6_cmd); @@ -4852,56 +5020,48 @@ void vtysh_init_vty(void) install_element(BGP_VPNV6_NODE, &vtysh_end_all_cmd); install_element(BGP_VPNV6_NODE, &exit_address_family_cmd); - install_node(&bgp_flowspecv4_node); install_element(BGP_NODE, &address_family_flowspecv4_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_FLOWSPECV4_NODE, &vtysh_end_all_cmd); install_element(BGP_FLOWSPECV4_NODE, &exit_address_family_cmd); - install_node(&bgp_flowspecv6_node); install_element(BGP_NODE, &address_family_flowspecv6_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_FLOWSPECV6_NODE, &vtysh_end_all_cmd); install_element(BGP_FLOWSPECV6_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4_node); install_element(BGP_NODE, &address_family_ipv4_cmd); install_element(BGP_IPV4_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4m_node); install_element(BGP_NODE, &address_family_ipv4_multicast_cmd); install_element(BGP_IPV4M_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4M_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4M_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4M_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv4l_node); install_element(BGP_NODE, &address_family_ipv4_labeled_unicast_cmd); install_element(BGP_IPV4L_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV4L_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV4L_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV4L_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6_node); install_element(BGP_NODE, &address_family_ipv6_cmd); install_element(BGP_IPV6_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV6_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6m_node); install_element(BGP_NODE, &address_family_ipv6_multicast_cmd); install_element(BGP_IPV6M_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6M_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_IPV6M_NODE, &vtysh_end_all_cmd); install_element(BGP_IPV6M_NODE, &exit_address_family_cmd); - install_node(&bgp_ipv6l_node); install_element(BGP_NODE, &address_family_ipv6_labeled_unicast_cmd); install_element(BGP_IPV6L_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_IPV6L_NODE, &vtysh_quit_bgpd_cmd); @@ -4909,28 +5069,24 @@ void vtysh_init_vty(void) install_element(BGP_IPV6L_NODE, &exit_address_family_cmd); #if defined(ENABLE_BGP_VNC) - install_node(&bgp_vrf_policy_node); install_element(BGP_NODE, &vnc_vrf_policy_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VRF_POLICY_NODE, &vtysh_end_all_cmd); install_element(BGP_VRF_POLICY_NODE, &exit_vrf_policy_cmd); - install_node(&bgp_vnc_defaults_node); install_element(BGP_NODE, &vnc_defaults_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &vtysh_end_all_cmd); install_element(BGP_VNC_DEFAULTS_NODE, &exit_vnc_config_cmd); - install_node(&bgp_vnc_nve_group_node); install_element(BGP_NODE, &vnc_nve_group_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &vtysh_end_all_cmd); install_element(BGP_VNC_NVE_GROUP_NODE, &exit_vnc_config_cmd); - install_node(&bgp_vnc_l2_group_node); install_element(BGP_NODE, &vnc_l2_group_cmd); install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_VNC_L2_GROUP_NODE, &vtysh_quit_bgpd_cmd); @@ -4938,33 +5094,28 @@ void vtysh_init_vty(void) install_element(BGP_VNC_L2_GROUP_NODE, &exit_vnc_config_cmd); #endif - install_node(&bgp_evpn_node); install_element(BGP_NODE, &address_family_evpn_cmd); install_element(BGP_EVPN_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_EVPN_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_EVPN_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_NODE, &exit_address_family_cmd); - install_node(&bgp_evpn_vni_node); install_element(BGP_EVPN_NODE, &bgp_evpn_vni_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_exit_bgpd_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_quit_bgpd_cmd); install_element(BGP_EVPN_VNI_NODE, &vtysh_end_all_cmd); install_element(BGP_EVPN_VNI_NODE, &exit_vni_cmd); - install_node(&rpki_node); install_element(CONFIG_NODE, &rpki_cmd); install_element(RPKI_NODE, &rpki_exit_cmd); install_element(RPKI_NODE, &rpki_quit_cmd); install_element(RPKI_NODE, &vtysh_end_all_cmd); - install_node(&bmp_node); install_element(BGP_NODE, &bmp_targets_cmd); install_element(BMP_NODE, &bmp_exit_cmd); install_element(BMP_NODE, &bmp_quit_cmd); install_element(BMP_NODE, &vtysh_end_all_cmd); - install_node(&bgp_srv6_node); install_element(BGP_NODE, &bgp_srv6_cmd); install_element(BGP_SRV6_NODE, &exit_bgp_srv6_cmd); install_element(BGP_SRV6_NODE, &quit_bgp_srv6_cmd); @@ -4972,7 +5123,6 @@ void vtysh_init_vty(void) #endif /* HAVE_BGPD */ /* ripd */ - install_node(&rip_node); #ifdef HAVE_RIPD install_element(CONFIG_NODE, &router_rip_cmd); install_element(RIP_NODE, &vtysh_exit_ripd_cmd); @@ -4981,7 +5131,6 @@ void vtysh_init_vty(void) #endif /* HAVE_RIPD */ /* ripngd */ - install_node(&ripng_node); #ifdef HAVE_RIPNGD install_element(CONFIG_NODE, &router_ripng_cmd); install_element(RIPNG_NODE, &vtysh_exit_ripngd_cmd); @@ -4991,7 +5140,6 @@ void vtysh_init_vty(void) /* ospfd */ #ifdef HAVE_OSPFD - install_node(&ospf_node); install_element(CONFIG_NODE, &router_ospf_cmd); install_element(OSPF_NODE, &vtysh_exit_ospfd_cmd); install_element(OSPF_NODE, &vtysh_quit_ospfd_cmd); @@ -5000,7 +5148,6 @@ void vtysh_init_vty(void) /* ospf6d */ #ifdef HAVE_OSPF6D - install_node(&ospf6_node); install_element(CONFIG_NODE, &router_ospf6_cmd); install_element(OSPF6_NODE, &vtysh_exit_ospf6d_cmd); install_element(OSPF6_NODE, &vtysh_quit_ospf6d_cmd); @@ -5009,45 +5156,38 @@ void vtysh_init_vty(void) /* ldpd */ #if defined(HAVE_LDPD) - install_node(&ldp_node); install_element(CONFIG_NODE, &ldp_mpls_ldp_cmd); install_element(LDP_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv4_node); install_element(LDP_NODE, &ldp_address_family_ipv4_cmd); install_element(LDP_IPV4_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV4_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV4_NODE, &ldp_exit_address_family_cmd); install_element(LDP_IPV4_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv6_node); install_element(LDP_NODE, &ldp_address_family_ipv6_cmd); install_element(LDP_IPV6_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV6_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV6_NODE, &ldp_exit_address_family_cmd); install_element(LDP_IPV6_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv4_iface_node); install_element(LDP_IPV4_NODE, &ldp_interface_ifname_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV4_IFACE_NODE, &vtysh_end_all_cmd); - install_node(&ldp_ipv6_iface_node); install_element(LDP_IPV6_NODE, &ldp_interface_ifname_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_IPV6_IFACE_NODE, &vtysh_end_all_cmd); - install_node(&ldp_l2vpn_node); install_element(CONFIG_NODE, &ldp_l2vpn_word_type_vpls_cmd); install_element(LDP_L2VPN_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_L2VPN_NODE, &vtysh_quit_ldpd_cmd); install_element(LDP_L2VPN_NODE, &vtysh_end_all_cmd); - install_node(&ldp_pseudowire_node); install_element(LDP_L2VPN_NODE, &ldp_member_pseudowire_ifname_cmd); install_element(LDP_PSEUDOWIRE_NODE, &vtysh_exit_ldpd_cmd); install_element(LDP_PSEUDOWIRE_NODE, &vtysh_quit_ldpd_cmd); @@ -5056,7 +5196,6 @@ void vtysh_init_vty(void) /* eigrpd */ #ifdef HAVE_EIGRPD - install_node(&eigrp_node); install_element(CONFIG_NODE, &router_eigrp_cmd); install_element(EIGRP_NODE, &vtysh_exit_eigrpd_cmd); install_element(EIGRP_NODE, &vtysh_quit_eigrpd_cmd); @@ -5065,7 +5204,6 @@ void vtysh_init_vty(void) /* babeld */ #ifdef HAVE_BABELD - install_node(&babel_node); install_element(CONFIG_NODE, &router_babel_cmd); install_element(BABEL_NODE, &vtysh_exit_babeld_cmd); install_element(BABEL_NODE, &vtysh_quit_babeld_cmd); @@ -5074,25 +5212,21 @@ void vtysh_init_vty(void) /* isisd */ #ifdef HAVE_ISISD - install_node(&isis_node); install_element(CONFIG_NODE, &router_isis_cmd); install_element(ISIS_NODE, &vtysh_exit_isisd_cmd); install_element(ISIS_NODE, &vtysh_quit_isisd_cmd); install_element(ISIS_NODE, &vtysh_end_all_cmd); - install_node(&isis_flex_algo_node); install_element(ISIS_NODE, &isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_exit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_quit_isis_flex_algo_cmd); install_element(ISIS_FLEX_ALGO_NODE, &vtysh_end_all_cmd); - install_node(&isis_srv6_node); install_element(ISIS_NODE, &isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &isis_srv6_node_msd_cmd); install_element(ISIS_SRV6_NODE, &vtysh_exit_isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &vtysh_quit_isis_srv6_enable_cmd); install_element(ISIS_SRV6_NODE, &vtysh_end_all_cmd); - install_node(&isis_srv6_node_msd_node); install_element(ISIS_SRV6_NODE_MSD_NODE, &vtysh_exit_isis_srv6_node_msd_cmd); install_element(ISIS_SRV6_NODE_MSD_NODE, @@ -5102,7 +5236,6 @@ void vtysh_init_vty(void) /* fabricd */ #ifdef HAVE_FABRICD - install_node(&openfabric_node); install_element(CONFIG_NODE, &router_openfabric_cmd); install_element(OPENFABRIC_NODE, &vtysh_exit_fabricd_cmd); install_element(OPENFABRIC_NODE, &vtysh_quit_fabricd_cmd); @@ -5111,7 +5244,6 @@ void vtysh_init_vty(void) /* pbrd */ #ifdef HAVE_PBRD - install_node(&pbr_map_node); install_element(CONFIG_NODE, &vtysh_pbr_map_cmd); install_element(CONFIG_NODE, &vtysh_no_pbr_map_cmd); install_element(PBRMAP_NODE, &vtysh_exit_pbr_map_cmd); @@ -5121,37 +5253,28 @@ void vtysh_init_vty(void) /* bfdd */ #if HAVE_BFDD > 0 - install_node(&bfd_node); install_element(CONFIG_NODE, &bfd_enter_cmd); install_element(BFD_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_NODE, &vtysh_end_all_cmd); - install_node(&bfd_peer_node); install_element(BFD_NODE, &bfd_peer_enter_cmd); install_element(BFD_PEER_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_PEER_NODE, &vtysh_end_all_cmd); - install_node(&bfd_profile_node); install_element(BFD_NODE, &bfd_profile_enter_cmd); install_element(BFD_PROFILE_NODE, &vtysh_exit_bfdd_cmd); install_element(BFD_PROFILE_NODE, &vtysh_quit_bfdd_cmd); install_element(BFD_PROFILE_NODE, &vtysh_end_all_cmd); #endif /* HAVE_BFDD */ - install_node(&segment_routing_node); install_element(CONFIG_NODE, &segment_routing_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd); #if defined(HAVE_PATHD) - install_node(&sr_traffic_eng_node); - install_node(&srte_segment_list_node); - install_node(&srte_policy_node); - install_node(&srte_candidate_dyn_node); - install_element(SR_TRAFFIC_ENG_NODE, &vtysh_exit_pathd_cmd); install_element(SR_TRAFFIC_ENG_NODE, &vtysh_quit_pathd_cmd); install_element(SR_SEGMENT_LIST_NODE, &vtysh_exit_pathd_cmd); @@ -5172,11 +5295,6 @@ void vtysh_init_vty(void) install_element(SR_TRAFFIC_ENG_NODE, &srte_policy_cmd); install_element(SR_POLICY_NODE, &srte_policy_candidate_dyn_path_cmd); - install_node(&pcep_node); - install_node(&pcep_pcc_node); - install_node(&pcep_pce_node); - install_node(&pcep_pce_config_node); - install_element(PCEP_NODE, &vtysh_exit_pathd_cmd); install_element(PCEP_NODE, &vtysh_quit_pathd_cmd); install_element(PCEP_PCC_NODE, &vtysh_exit_pathd_cmd); @@ -5199,14 +5317,12 @@ void vtysh_init_vty(void) #endif /* HAVE_PATHD */ /* keychain */ - install_node(&keychain_node); install_element(CONFIG_NODE, &key_chain_cmd); install_element(KEYCHAIN_NODE, &key_chain_cmd); install_element(KEYCHAIN_NODE, &vtysh_exit_keys_cmd); install_element(KEYCHAIN_NODE, &vtysh_quit_keys_cmd); install_element(KEYCHAIN_NODE, &vtysh_end_all_cmd); - install_node(&keychain_key_node); install_element(KEYCHAIN_NODE, &key_cmd); install_element(KEYCHAIN_KEY_NODE, &key_chain_cmd); install_element(KEYCHAIN_KEY_NODE, &vtysh_exit_keys_cmd); @@ -5214,7 +5330,6 @@ void vtysh_init_vty(void) install_element(KEYCHAIN_KEY_NODE, &vtysh_end_all_cmd); /* nexthop-group */ - install_node(&nh_group_node); install_element(CONFIG_NODE, &vtysh_nexthop_group_cmd); install_element(CONFIG_NODE, &vtysh_no_nexthop_group_cmd); install_element(NH_GROUP_NODE, &vtysh_end_all_cmd); @@ -5222,15 +5337,27 @@ void vtysh_init_vty(void) install_element(NH_GROUP_NODE, &vtysh_quit_nexthop_group_cmd); /* zebra and all */ - install_node(&zebra_node); - - install_node(&interface_node); install_element(CONFIG_NODE, &vtysh_interface_cmd); install_element(INTERFACE_NODE, &vtysh_end_all_cmd); install_element(INTERFACE_NODE, &vtysh_exit_interface_cmd); install_element(INTERFACE_NODE, &vtysh_quit_interface_cmd); - install_node(&link_params_node); + /* pimd */ +#ifdef HAVE_PIMD + install_element(CONFIG_NODE, &router_pim_cmd); + install_element(PIM_NODE, &vtysh_exit_pimd_cmd); + install_element(PIM_NODE, &vtysh_quit_pimd_cmd); + install_element(PIM_NODE, &vtysh_end_all_cmd); +#endif /* HAVE_PIMD */ + + /* pim6d */ +#ifdef HAVE_PIM6D + install_element(CONFIG_NODE, &router_pim6_cmd); + install_element(PIM6_NODE, &vtysh_exit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_quit_pim6d_cmd); + install_element(PIM6_NODE, &vtysh_end_all_cmd); +#endif /* HAVE_PIM6D */ + install_element(INTERFACE_NODE, &vtysh_link_params_cmd); install_element(LINK_PARAMS_NODE, &no_link_params_enable_cmd); install_element(LINK_PARAMS_NODE, &exit_link_params_cmd); @@ -5238,13 +5365,11 @@ void vtysh_init_vty(void) install_element(LINK_PARAMS_NODE, &vtysh_exit_link_params_cmd); install_element(LINK_PARAMS_NODE, &vtysh_quit_link_params_cmd); - install_node(&pw_node); install_element(CONFIG_NODE, &vtysh_pseudowire_cmd); install_element(PW_NODE, &vtysh_end_all_cmd); install_element(PW_NODE, &vtysh_exit_pseudowire_cmd); install_element(PW_NODE, &vtysh_quit_pseudowire_cmd); - install_node(&vrf_node); install_element(CONFIG_NODE, &vtysh_vrf_cmd); install_element(VRF_NODE, &exit_vrf_config_cmd); install_element(VRF_NODE, &vtysh_end_all_cmd); @@ -5252,7 +5377,6 @@ void vtysh_init_vty(void) install_element(VRF_NODE, &vtysh_quit_vrf_cmd); #ifdef HAVE_BGPD - install_node(&rpki_vrf_node); install_element(VRF_NODE, &rpki_cmd); install_element(RPKI_VRF_NODE, &rpki_exit_cmd); install_element(RPKI_VRF_NODE, &rpki_quit_cmd); @@ -5262,13 +5386,11 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &vtysh_affinity_map_cmd); install_element(CONFIG_NODE, &vtysh_no_affinity_map_cmd); - install_node(&rmap_node); install_element(CONFIG_NODE, &vtysh_route_map_cmd); install_element(RMAP_NODE, &vtysh_exit_rmap_cmd); install_element(RMAP_NODE, &vtysh_quit_rmap_cmd); install_element(RMAP_NODE, &vtysh_end_all_cmd); - install_node(&vty_node); install_element(CONFIG_NODE, &vtysh_line_vty_cmd); install_element(VTY_NODE, &vtysh_exit_line_vty_cmd); install_element(VTY_NODE, &vtysh_quit_line_vty_cmd); @@ -5301,26 +5423,38 @@ void vtysh_init_vty(void) install_element(ENABLE_NODE, &vtysh_end_all_cmd); /* SRv6 Data-plane */ - install_node(&srv6_node); install_element(SEGMENT_ROUTING_NODE, &srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); + install_element(SRV6_NODE, &srv6_sid_formats_cmd); install_element(SRV6_NODE, &exit_srv6_config_cmd); install_element(SRV6_NODE, &vtysh_end_all_cmd); install_element(SRV6_NODE, &srv6_encap_cmd); - install_node(&srv6_locs_node); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &exit_srv6_locs_config_cmd); install_element(SRV6_LOCS_NODE, &vtysh_end_all_cmd); - install_node(&srv6_loc_node); install_element(SRV6_LOC_NODE, &exit_srv6_loc_config_cmd); install_element(SRV6_LOC_NODE, &vtysh_end_all_cmd); - install_node(&srv6_encap_node); install_element(SRV6_ENCAP_NODE, &exit_srv6_encap_cmd); install_element(SRV6_ENCAP_NODE, &vtysh_end_all_cmd); + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_f4024_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, &exit_srv6_sid_formats_cmd); + install_element(SRV6_SID_FORMATS_NODE, &vtysh_end_all_cmd); + + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, &vtysh_end_all_cmd); + + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &exit_srv6_sid_format_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &vtysh_end_all_cmd); + install_element(ENABLE_NODE, &vtysh_show_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_running_config_cmd); install_element(ENABLE_NODE, &vtysh_copy_to_running_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index c207e4d427..8f7cd84818 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -497,6 +497,11 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(BFD_NODE, line); else if (strncmp(line, "rpki", strlen("rpki")) == 0) config = config_get(RPKI_NODE, line); + else if (strncmp(line, "router pim", strlen("router pim")) == 0) + config = config_get(PIM_NODE, line); + else if (strncmp(line, "router pim6", strlen("router pim6")) == + 0) + config = config_get(PIM6_NODE, line); else { if (strncmp(line, "log", strlen("log")) == 0 || strncmp(line, "hostname", strlen("hostname")) == 0 || diff --git a/vtysh/vtysh_main.c b/vtysh/vtysh_main.c index 464d82cf7f..64198132cc 100644 --- a/vtysh/vtysh_main.c +++ b/vtysh/vtysh_main.c @@ -489,7 +489,6 @@ int main(int argc, char **argv, char **env) /* Make vty structure and register commands. */ vtysh_init_vty(); - vtysh_init_cmd(); vtysh_user_init(); vtysh_config_init(); diff --git a/yang/frr-bfdd.yang b/yang/frr-bfdd.yang index ffba42b53b..02ed921459 100644 --- a/yang/frr-bfdd.yang +++ b/yang/frr-bfdd.yang @@ -16,9 +16,6 @@ module frr-bfdd { import frr-vrf { prefix frr-vrf; } - import frr-route-types { - prefix frr-route-types; - } organization "FRRouting"; contact diff --git a/yang/frr-eigrpd.yang b/yang/frr-eigrpd.yang index f672dd5571..d3d9db2f62 100644 --- a/yang/frr-eigrpd.yang +++ b/yang/frr-eigrpd.yang @@ -75,7 +75,7 @@ module frr-eigrpd { typedef autonomous-system { description "Administrative domain identification for a network"; type uint16 { - range 1..65535; + range "1..65535"; } } diff --git a/yang/frr-isisd.yang b/yang/frr-isisd.yang index d1a08fa976..60914b0be9 100644 --- a/yang/frr-isisd.yang +++ b/yang/frr-isisd.yang @@ -685,7 +685,7 @@ module frr-isisd { type uint32 { range "0..16777215"; } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide' or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style)"; + must ". < 64 or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style) or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style != 'narrow'"; default "10"; description "Default level-1 metric for this IS-IS circuit."; @@ -695,7 +695,7 @@ module frr-isisd { type uint32 { range "0..16777215"; } - must ". < 64 or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style = 'wide' or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style)"; + must ". < 64 or not(/frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style) or /frr-isisd:isis/instance[area-tag = current()/../../area-tag]/metric-style != 'narrow'"; default "10"; description "Default level-2 metric for this IS-IS circuit."; diff --git a/yang/frr-pim.yang b/yang/frr-pim.yang index 732a38a9e3..6a6c52185d 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -5,6 +5,10 @@ module frr-pim { prefix frr-pim; + import frr-filter { + prefix frr-filter; + } + import frr-interface { prefix frr-interface; } @@ -118,6 +122,37 @@ module frr-pim { } } + grouping msdp-authentication { + description + "MSDP authentication options."; + + leaf authentication-type { + type enumeration { + enum None { + value 0; + description + "No authentication."; + } + enum MD5 { + value 1; + description + "Use MD5 digest."; + } + } + default None; + description + "Authentication method."; + } + + leaf authentication-key { + when "../authentication-type = 'MD5'"; + mandatory true; + type string; + description + "Authentication key."; + } + } + grouping global-pim-config-attributes { description "A grouping defining per address family pim global attributes"; @@ -267,6 +302,20 @@ module frr-pim { description "MSDP source IP address."; } + + leaf sa-filter-in { + type frr-filter:access-list-name; + description + "Access list name used to filter the incoming SAs exchanged."; + } + + leaf sa-filter-out { + type frr-filter:access-list-name; + description + "Access list name used to filter the outgoing SAs exchanged."; + } + + uses msdp-authentication; } container mlag { diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index 26d56acc03..c875a6ec7f 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -360,16 +360,16 @@ module frr-route-map { case set-min-metric { when "derived-from-or-self(../action, 'set-min-metric')"; - choice minimun-metric-value { + choice minimum-metric-value { description - "Mimimum metric to set or use"; + "Minimum metric to set or use"; case min-metric { leaf min-metric { type uint32 { range "0..4294967295"; } description - "Use the following mimumn metric value"; + "Use the following minimum metric value"; } } } diff --git a/yang/frr-zebra.yang b/yang/frr-zebra.yang index 79c524a40a..1c7d1c8ef4 100644 --- a/yang/frr-zebra.yang +++ b/yang/frr-zebra.yang @@ -626,6 +626,7 @@ module frr-zebra { leaf table-id { type uint32; + default "254"; description "Routing Table id (default id - 254)."; } diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 9ad92d6269..09080aa616 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -36,13 +36,11 @@ #include "zebra/zebra_dplane.h" #include "zebra/zebra_mpls.h" #include "zebra/zebra_router.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan_private.h" #include "zebra/zebra_evpn.h" #include "zebra/zebra_evpn_mac.h" #include "zebra/kernel_netlink.h" #include "zebra/rt_netlink.h" -#include "zebra/debug.h" #include "fpm/fpm.h" #include "zebra/dplane_fpm_nl_clippy.c" @@ -136,8 +134,6 @@ struct fpm_nl_ctx { /* Amount of data plane context processed. */ _Atomic uint32_t dplane_contexts; - /* Amount of data plane contexts enqueued. */ - _Atomic uint32_t ctxqueue_len; /* Peak amount of data plane contexts enqueued. */ _Atomic uint32_t ctxqueue_len_peak; @@ -399,6 +395,12 @@ DEFUN(fpm_show_counters, fpm_show_counters_cmd, FPM_STR "FPM statistic counters\n") { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + vty_out(vty, "%30s\n%30s\n", "FPM counters", "============"); #define SHOW_COUNTER(label, counter) \ @@ -412,8 +414,7 @@ DEFUN(fpm_show_counters, fpm_show_counters_cmd, SHOW_COUNTER("Connection errors", gfnc->counters.connection_errors); SHOW_COUNTER("Data plane items processed", gfnc->counters.dplane_contexts); - SHOW_COUNTER("Data plane items enqueued", - gfnc->counters.ctxqueue_len); + SHOW_COUNTER("Data plane items enqueued", curr_queue_len); SHOW_COUNTER("Data plane items queue peak", gfnc->counters.ctxqueue_len_peak); SHOW_COUNTER("Buffer full hits", gfnc->counters.buffer_full); @@ -432,6 +433,12 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, "FPM statistic counters\n" JSON_STR) { + uint32_t curr_queue_len; + + frr_with_mutex (&gfnc->ctxqueue_mutex) { + curr_queue_len = dplane_ctx_queue_count(&gfnc->ctxqueue); + } + struct json_object *jo; jo = json_object_new_object(); @@ -445,8 +452,7 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, gfnc->counters.connection_errors); json_object_int_add(jo, "data-plane-contexts", gfnc->counters.dplane_contexts); - json_object_int_add(jo, "data-plane-contexts-queue", - gfnc->counters.ctxqueue_len); + json_object_int_add(jo, "data-plane-contexts-queue", curr_queue_len); json_object_int_add(jo, "data-plane-contexts-queue-peak", gfnc->counters.ctxqueue_len_peak); json_object_int_add(jo, "buffer-full-hits", gfnc->counters.buffer_full); @@ -1495,8 +1501,6 @@ static void fpm_process_queue(struct event *t) /* Account the processed entries. */ processed_contexts++; - atomic_fetch_sub_explicit(&fnc->counters.ctxqueue_len, 1, - memory_order_relaxed); dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); dplane_provider_enqueue_out_ctx(fnc->prov, ctx); @@ -1670,7 +1674,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) struct zebra_dplane_ctx *ctx; struct fpm_nl_ctx *fnc; int counter, limit; - uint64_t cur_queue, peak_queue = 0, stored_peak_queue; + uint64_t cur_queue = 0, peak_queue = 0, stored_peak_queue; fnc = dplane_provider_get_data(prov); limit = dplane_provider_get_work_limit(prov); @@ -1684,20 +1688,12 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) * anyway. */ if (fnc->socket != -1 && fnc->connecting == false) { - /* - * Update the number of queued contexts *before* - * enqueueing, to ensure counter consistency. - */ - atomic_fetch_add_explicit(&fnc->counters.ctxqueue_len, - 1, memory_order_relaxed); - frr_with_mutex (&fnc->ctxqueue_mutex) { dplane_ctx_enqueue_tail(&fnc->ctxqueue, ctx); + cur_queue = + dplane_ctx_queue_count(&fnc->ctxqueue); } - cur_queue = atomic_load_explicit( - &fnc->counters.ctxqueue_len, - memory_order_relaxed); if (peak_queue < cur_queue) peak_queue = cur_queue; continue; @@ -1714,9 +1710,7 @@ static int fpm_nl_process(struct zebra_dplane_provider *prov) atomic_store_explicit(&fnc->counters.ctxqueue_len_peak, peak_queue, memory_order_relaxed); - if (atomic_load_explicit(&fnc->counters.ctxqueue_len, - memory_order_relaxed) - > 0) + if (cur_queue > 0) event_add_event(fnc->fthread->master, fpm_process_queue, fnc, 0, &fnc->t_dequeue); diff --git a/zebra/interface.c b/zebra/interface.c index b3adc4483e..03b710e1a0 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -32,7 +32,6 @@ #include "zebra/zebra_ptm.h" #include "zebra/rt_netlink.h" #include "zebra/if_netlink.h" -#include "zebra/interface.h" #include "zebra/zebra_vxlan.h" #include "zebra/zebra_errors.h" #include "zebra/zebra_evpn_mh.h" diff --git a/zebra/main.c b/zebra/main.c index ea1e1cbdbb..687da70cab 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -65,8 +65,6 @@ struct mgmt_be_client *mgmt_be_client; /* Route retain mode flag. */ int retain_mode = 0; -int graceful_restart; - /* Receive buffer size for kernel control sockets */ #define RCVBUFSIZE_MIN 4194304 #ifdef HAVE_NETLINK @@ -88,7 +86,6 @@ const struct option longopts[] = { { "socket", required_argument, NULL, 'z' }, { "ecmp", required_argument, NULL, 'e' }, { "retain", no_argument, NULL, 'r' }, - { "graceful_restart", required_argument, NULL, 'K' }, { "asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD }, { "v6-with-v4-nexthops", no_argument, NULL, OPTION_V6_WITH_V4_NEXTHOP }, #ifdef HAVE_NETLINK @@ -96,7 +93,7 @@ const struct option longopts[] = { { "nl-bufsize", required_argument, NULL, 's' }, { "v6-rr-semantics", no_argument, NULL, OPTION_V6_RR_SEMANTICS }, #endif /* HAVE_NETLINK */ - {"routing-table", optional_argument, NULL, 'R'}, + { "routing-table", optional_argument, NULL, 'R' }, { 0 } }; @@ -326,7 +323,6 @@ int main(int argc, char **argv) bool v6_with_v4_nexthop = false; bool notify_on_ack = true; - graceful_restart = 0; vrf_configure_backend(VRF_BACKEND_VRF_LITE); frr_preinit(&zebra_di, argc, argv); @@ -342,7 +338,6 @@ int main(int argc, char **argv) " -z, --socket Set path of zebra socket\n" " -e, --ecmp Specify ECMP to use.\n" " -r, --retain When program terminates, retain added route by zebra.\n" - " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" " --v6-with-v4-nexthops Underlying dataplane supports v6 routes with v4 nexthops" #ifdef HAVE_NETLINK @@ -352,8 +347,7 @@ int main(int argc, char **argv) #else " -s, Set kernel socket receive buffer size\n" #endif /* HAVE_NETLINK */ - " -R, --routing-table Set kernel routing table\n" - ); + " -R, --routing-table Set kernel routing table\n"); while (1) { int opt = frr_getopt(argc, argv, NULL); @@ -397,9 +391,6 @@ int main(int argc, char **argv) case 'r': retain_mode = 1; break; - case 'K': - graceful_restart = atoi(optarg); - break; case 's': rcvbufsize = atoi(optarg); if (rcvbufsize < RCVBUFSIZE_MIN) @@ -488,11 +479,25 @@ int main(int argc, char **argv) * Clean up zebra-originated routes. The requests will be sent to OS * immediately, so originating PID in notifications from kernel * will be equal to the current getpid(). To know about such routes, - * we have to have route_read() called before. + * we have to have route_read() called before. + * If FRR is gracefully restarting, we either wait for clients + * (e.g., BGP) to signal GR is complete else we wait for specified + * duration. */ zrouter.startup_time = monotime(NULL); - event_add_timer(zrouter.master, rib_sweep_route, NULL, graceful_restart, - &zrouter.sweeper); + zrouter.rib_sweep_time = 0; + zrouter.graceful_restart = zebra_di.graceful_restart; + if (!zrouter.graceful_restart) + event_add_timer(zrouter.master, rib_sweep_route, NULL, 0, NULL); + else { + int gr_cleanup_time; + + gr_cleanup_time = zebra_di.gr_cleanup_time + ? zebra_di.gr_cleanup_time + : ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME; + event_add_timer(zrouter.master, rib_sweep_route, NULL, + gr_cleanup_time, &zrouter.t_rib_sweep); + } /* Needed for BSD routing socket. */ pid = getpid(); diff --git a/zebra/rib.h b/zebra/rib.h index a721f4bac4..84ea766c47 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -622,10 +622,10 @@ static inline struct nexthop_group *rib_get_fib_backup_nhg( } extern void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance); + uint8_t instance, time_t restart_time); extern void zebra_vty_init(void); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 01b527ea80..768090badb 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1040,7 +1040,7 @@ int netlink_route_change_read_unicast_internal(struct nlmsghdr *h, zlog_err( "%s: %pFX multipath RTM_NEWROUTE has a invalid nexthop group from the kernel", __func__, &p); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } } else { if (ctx) { diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index d585ef996b..aecbba2ebc 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -999,6 +999,48 @@ void zsend_neighbor_notify(int cmd, struct interface *ifp, } } +void zsend_srv6_sid_notify(struct zserv *client, const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, const char *locator_name, + enum zapi_srv6_sid_notify note) + +{ + struct stream *s; + uint16_t cmd = ZEBRA_SRV6_SID_NOTIFY; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: notifying %s ctx %s sid %pI6 note %s (proto=%u, instance=%u, sessionId=%u)", + __func__, zserv_command_string(cmd), + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value, + zapi_srv6_sid_notify2str(note), client->proto, + client->instance, client->session_id); + + s = stream_new(ZEBRA_MAX_PACKET_SIZ); + + zclient_create_header(s, cmd, VRF_DEFAULT); + /* Notification type (e.g. ZAPI_SRV6_SID_ALLOCATED, ZAPI_SRV6_SID_FAIL_ALLOC, ...) */ + stream_put(s, ¬e, sizeof(note)); + /* Context associated with the SRv6 SID */ + stream_put(s, ctx, sizeof(struct srv6_sid_ctx)); + /* SRv6 SID value (i.e. IPv6 address) */ + stream_put(s, sid_value, sizeof(struct in6_addr)); + /* SRv6 SID function */ + stream_putl(s, func); + /* SRv6 wide SID function */ + stream_putl(s, wide_func); + /* SRv6 locator name optional */ + if (locator_name) { + stream_putw(s, strlen(locator_name)); + stream_put(s, locator_name, strlen(locator_name)); + } else + stream_putw(s, 0); + + stream_putw_at(s, 0, stream_get_endp(s)); + + zserv_send_message(client, s); +} + /* Router-id is updated. Send ZEBRA_ROUTER_ID_UPDATE to client. */ int zsend_router_id_update(struct zserv *client, afi_t afi, struct prefix *p, @@ -1136,9 +1178,25 @@ static int zsend_table_manager_connect_response(struct zserv *client, int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); + struct srv6_locator locator = {}; + struct srv6_sid_format *format = loc->sid_format; + + /* + * Copy the locator and fill locator block/node/func/arg length from the format + * before sending the locator to the zclient + */ + srv6_locator_copy(&locator, loc); + if (format) { + locator.block_bits_length = format->block_len; + locator.node_bits_length = format->node_len; + locator.function_bits_length = format->function_len; + locator.argument_bits_length = format->argument_len; + if (format->type == SRV6_SID_FORMAT_TYPE_USID) + SET_FLAG(locator.flags, SRV6_LOCATOR_USID); + } zclient_create_header(s, ZEBRA_SRV6_LOCATOR_ADD, VRF_DEFAULT); - zapi_srv6_locator_encode(s, loc); + zapi_srv6_locator_encode(s, &locator); stream_putw_at(s, 0, stream_get_endp(s)); return zserv_send_message(client, s); @@ -2090,7 +2148,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, &api.prefix, zebra_route_string(client->proto)); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2115,7 +2173,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2134,8 +2192,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) @@ -2147,8 +2204,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) __func__, api.safi); nexthop_group_delete(&ng); zebra_nhg_backup_free(&bnhg); - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return; } @@ -2177,8 +2233,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) */ if (ret == -1) { client->error_cnt++; - XFREE(MTYPE_RE_OPAQUE, re->opaque); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } /* At this point, these allocations are not needed: 're' has been @@ -2206,9 +2261,10 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) } } -void zapi_re_opaque_free(struct re_opaque *opaque) +void zapi_re_opaque_free(struct route_entry *re) { - XFREE(MTYPE_RE_OPAQUE, opaque); + XFREE(MTYPE_RE_OPAQUE, re->opaque); + re->opaque = NULL; } static void zread_route_del(ZAPI_HANDLER_ARGS) @@ -2356,6 +2412,7 @@ static void zsend_capabilities(struct zserv *client, struct zebra_vrf *zvrf) stream_putl(s, zrouter.multipath_num); stream_putc(s, zebra_mlag_get_role()); stream_putc(s, zrouter.v6_with_v4_nexthop); + stream_putc(s, zrouter.graceful_restart); stream_putw_at(s, 0, stream_get_endp(s)); zserv_send_message(client, s); } @@ -2990,6 +3047,96 @@ static void zread_srv6_manager_release_locator_chunk(struct zserv *client, return; } +/** + * Handle SRv6 SID request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + struct in6_addr sid_value = {}; + struct in6_addr *sid_value_ptr = NULL; + char locator[SRV6_LOCNAME_SIZE] = { 0 }; + uint16_t len; + struct zebra_srv6_sid *sid = NULL; + uint8_t flags; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + STREAM_GETC(s, flags); + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_SID_VALUE)) { + STREAM_GET(&sid_value, s, sizeof(struct in6_addr)); + sid_value_ptr = &sid_value; + } + if (CHECK_FLAG(flags, ZAPI_SRV6_MANAGER_SID_FLAG_HAS_LOCATOR)) { + STREAM_GETW(s, len); + STREAM_GET(locator, s, len); + } + + /* Call hook to get a SID using wrapper */ + srv6_manager_get_sid_call(&sid, client, &ctx, sid_value_ptr, locator); + +stream_failure: + return; +} + +/** + * Handle SRv6 SID release request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_release_srv6_sid(struct zserv *client, + struct stream *msg) +{ + struct stream *s; + struct srv6_sid_ctx ctx = {}; + + /* Get input stream */ + s = msg; + + /* Get data */ + STREAM_GET(&ctx, s, sizeof(struct srv6_sid_ctx)); + + /* Call hook to release a SID using wrapper */ + srv6_manager_release_sid_call(client, &ctx); + +stream_failure: + return; +} + +/** + * Handle SRv6 locator get request received from a client daemon protocol. + * + * @param client The client zapi session + * @param msg The request message + */ +static void zread_srv6_manager_get_locator(struct zserv *client, + struct stream *msg) +{ + struct stream *s = msg; + uint16_t len; + char locator_name[SRV6_LOCNAME_SIZE] = { 0 }; + struct srv6_locator *locator = NULL; + + /* Get data */ + STREAM_GETW(s, len); + STREAM_GET(locator_name, s, len); + + /* Call hook to get the locator info using wrapper */ + srv6_manager_get_locator_call(&locator, client, locator_name); + +stream_failure: + return; +} + static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) { switch (hdr->command) { @@ -3001,6 +3148,15 @@ static void zread_srv6_manager_request(ZAPI_HANDLER_ARGS) zread_srv6_manager_release_locator_chunk(client, msg, zvrf_id(zvrf)); break; + case ZEBRA_SRV6_MANAGER_GET_SRV6_SID: + zread_srv6_manager_get_srv6_sid(client, msg); + break; + case ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID: + zread_srv6_manager_release_srv6_sid(client, msg); + break; + case ZEBRA_SRV6_MANAGER_GET_LOCATOR: + zread_srv6_manager_get_locator(client, msg); + break; default: zlog_err("%s: unknown SRv6 Manager command", __func__); break; @@ -3949,6 +4105,9 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_MLAG_FORWARD_MSG] = zebra_mlag_forward_client_msg, [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = zread_srv6_manager_request, [ZEBRA_SRV6_MANAGER_RELEASE_LOCATOR_CHUNK] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_SRV6_SID] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_RELEASE_SRV6_SID] = zread_srv6_manager_request, + [ZEBRA_SRV6_MANAGER_GET_LOCATOR] = zread_srv6_manager_request, [ZEBRA_CLIENT_CAPABILITIES] = zread_client_capabilities, [ZEBRA_NEIGH_DISCOVER] = zread_neigh_discover, [ZEBRA_NHG_ADD] = zread_nhg_add, diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h index 43f734d26e..a59ccc838b 100644 --- a/zebra/zapi_msg.h +++ b/zebra/zapi_msg.h @@ -94,6 +94,11 @@ extern int zsend_sr_policy_notify_status(uint32_t color, extern void zsend_neighbor_notify(int cmd, struct interface *ifp, struct ipaddr *ipaddr, int ndm_state, union sockunion *link_layer_ipv4, int ip_len); +extern void zsend_srv6_sid_notify(struct zserv *client, + const struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, uint32_t func, + uint32_t wide_func, const char *locator_name, + enum zapi_srv6_sid_notify note); extern int zsend_client_close_notify(struct zserv *client, struct zserv *closed_client); @@ -101,7 +106,7 @@ extern int zsend_client_close_notify(struct zserv *client, int zsend_nhg_notify(uint16_t type, uint16_t instance, uint32_t session_id, uint32_t id, enum zapi_nhg_notify_owner note); -extern void zapi_re_opaque_free(struct re_opaque *opaque); +extern void zapi_re_opaque_free(struct route_entry *re); extern int zsend_zebra_srv6_locator_add(struct zserv *client, struct srv6_locator *loc); @@ -110,6 +115,9 @@ extern int zsend_zebra_srv6_locator_delete(struct zserv *client, extern int zsend_srv6_manager_get_locator_chunk_response(struct zserv *client, vrf_id_t vrf_id, struct srv6_locator *loc); +extern int zsend_srv6_manager_get_locator_response(struct zserv *client, + struct srv6_locator *locator); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 3944876439..1cee1ebb93 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -969,6 +969,11 @@ struct zebra_dplane_ctx *dplane_ctx_dequeue(struct dplane_ctx_list_head *q) return ctx; } +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q) +{ + return dplane_ctx_list_count(q); +} + /* * Accessors for information from the context object */ @@ -4309,6 +4314,10 @@ dplane_route_update_internal(struct route_node *rn, NEXTHOP_FLAG_RECURSIVE)) continue; + if (CHECK_FLAG(nexthop->flags, + NEXTHOP_FLAG_DUPLICATE)) + continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) SET_FLAG(nexthop->flags, @@ -5994,6 +6003,14 @@ int dplane_show_helper(struct vty *vty, bool detailed) vty_out(vty, "Zebra dataplane:\nRoute updates: %"PRIu64"\n", incoming); vty_out(vty, "Route update errors: %"PRIu64"\n", errs); + + incoming = atomic_load_explicit(&zdplane_info.dg_nexthops_in, + memory_order_relaxed); + errs = atomic_load_explicit(&zdplane_info.dg_nexthop_errors, + memory_order_relaxed); + vty_out(vty, "Nexthop updates: %" PRIu64 "\n", incoming); + vty_out(vty, "Nexthop update errors: %" PRIu64 "\n", errs); + vty_out(vty, "Other errors : %"PRIu64"\n", other_errs); vty_out(vty, "Route update queue limit: %"PRIu64"\n", limit); vty_out(vty, "Route update queue depth: %"PRIu64"\n", queued); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 060b1c8b9e..0e9a8bfb99 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -323,6 +323,8 @@ struct zebra_dplane_ctx *dplane_ctx_get_head(struct dplane_ctx_list_head *q); /* Init a list of contexts */ void dplane_ctx_q_init(struct dplane_ctx_list_head *q); +uint32_t dplane_ctx_queue_count(struct dplane_ctx_list_head *q); + /* * Accessors for information from the context object */ diff --git a/zebra/zebra_errors.c b/zebra/zebra_errors.c index 09b369e23e..dcfa37d268 100644 --- a/zebra/zebra_errors.c +++ b/zebra/zebra_errors.c @@ -787,6 +787,18 @@ static struct log_ref ferr_zebra_err[] = { .suggestion = "Wait for Zebra to reattempt update.", }, + { + .code = EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + .title = "SRv6 manager unable to assign SID", + .description = "Zebra's SRv6 manager was unable to assign a SID to client.", + .suggestion = "Ensure that Zebra has a sufficient SID range available.", + }, + { + .code = EC_ZEBRA_SM_DAEMON_MISMATCH, + .title = "Daemon mismatch when releasing SRV6 SIDs", + .description = "Zebra noticed a mismatch between a SRv6 SID and a protocol daemon number or instance when releasing unused SRv6 SIDs.", + .suggestion = "Ignore this error.", + }, { .code = END_FERR, } diff --git a/zebra/zebra_errors.h b/zebra/zebra_errors.h index 3ac654bda5..84632e1ad5 100644 --- a/zebra/zebra_errors.h +++ b/zebra/zebra_errors.h @@ -124,6 +124,8 @@ enum zebra_log_refs { EC_ZEBRA_GRE_SET_UPDATE, EC_ZEBRA_SRV6M_UNRELEASED_LOCATOR_CHUNK, EC_ZEBRA_INTF_UPDATE_FAILURE, + EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + EC_ZEBRA_SM_DAEMON_MISMATCH, }; void zebra_error_init(void); diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index cee66cc055..d84f680e22 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -103,6 +103,7 @@ static struct client_gr_info *zebra_gr_client_info_create(struct zserv *client) info->stale_client_ptr = client; TAILQ_INSERT_TAIL(&(client->gr_info_queue), info, gr_info); + info->client_ptr = client; return info; } @@ -290,6 +291,7 @@ struct zebra_gr_afi_clean { afi_t afi; uint8_t proto; uint8_t instance; + time_t restart_time; struct event *t_gac; }; @@ -420,7 +422,7 @@ void zread_client_capabilities(ZAPI_HANDLER_ARGS) * Schedule for after anything already in the meta Q */ rib_add_gr_run(api.afi, api.vrf_id, client->proto, - client->instance); + client->instance, client->restart_time); zebra_gr_process_client_stale_routes(client, info); break; case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: @@ -455,7 +457,11 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) struct zserv *client; struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - client = (struct zserv *)info->stale_client_ptr; + info->t_stale_removal = NULL; + if (zrouter.graceful_restart) + client = (struct zserv *)info->client_ptr; + else + client = (struct zserv *)info->stale_client_ptr; cnt = zebra_gr_delete_stale_routes(info); @@ -486,16 +492,24 @@ static void zebra_gr_route_stale_delete_timer_expiry(struct event *thread) * * Returns true when a node is deleted else false */ -static bool zebra_gr_process_route_entry(struct zserv *client, - struct route_node *rn, - struct route_entry *re) +static bool zebra_gr_process_route_entry(struct route_node *rn, + struct route_entry *re, + time_t compare_time, uint8_t proto) { + struct nexthop *nexthop; + char buf[PREFIX2STR_BUFFER]; + /* If the route is not refreshed after restart, delete the entry */ - if (re->uptime < client->restart_time) { - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("%s: Client %s stale route %pFX is deleted", - __func__, zebra_route_string(client->proto), - &rn->p); + if (re->uptime < compare_time) { + if (IS_ZEBRA_DEBUG_RIB) { + prefix2str(&rn->p, buf, sizeof(buf)); + zlog_debug("%s: Client %s stale route %s is deleted", + __func__, zebra_route_string(proto), buf); + } + SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + rib_delnode(rn, re); return true; @@ -532,8 +546,9 @@ static void zebra_gr_delete_stale_route_table_afi(struct event *event) if (re->type == gac->proto && re->instance == gac->instance && - zebra_gr_process_route_entry( - gac->info->stale_client_ptr, rn, re)) + zebra_gr_process_route_entry(rn, re, + gac->restart_time, + gac->proto)) n++; /* If the max route count is reached @@ -567,28 +582,42 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, uint8_t proto; uint16_t instance; struct zserv *s_client; + struct zserv *client; + time_t restart_time = time(NULL); - s_client = info->stale_client_ptr; - if (s_client == NULL) { - LOG_GR("%s: Stale client %s(%u) not present", __func__, - zvrf->vrf->name, zvrf->vrf->vrf_id); + if ((info == NULL) || (zvrf == NULL)) return -1; - } - proto = s_client->proto; - instance = s_client->instance; + if (zrouter.graceful_restart) { + client = info->client_ptr; + if (client == NULL) { + LOG_GR("%s: client not present", __func__); + return -1; + } + proto = client->proto; + instance = client->instance; + restart_time = zrouter.startup_time; + } else { + s_client = info->stale_client_ptr; + if (s_client == NULL) { + LOG_GR("%s: Stale client not present", __func__); + return -1; + } + proto = s_client->proto; + instance = s_client->instance; + restart_time = s_client->restart_time; + } LOG_GR("%s: Client %s %s(%u) stale routes are being deleted", __func__, zebra_route_string(proto), zvrf->vrf->name, zvrf->vrf->vrf_id); /* Process routes for all AFI */ for (afi = AFI_IP; afi < AFI_MAX; afi++) { - /* * Schedule for immediately after anything in the * meta-Q */ - rib_add_gr_run(afi, info->vrf_id, proto, instance); + rib_add_gr_run(afi, info->vrf_id, proto, instance, restart_time); } return 0; } @@ -641,12 +670,13 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, /* * Route update completed for all AFI, SAFI - * Cancel the stale timer, routes are already being processed + * Also perform the cleanup if FRR itself is gracefully restarting. */ - if (info->t_stale_removal) { + info->route_sync_done_time = monotime(NULL); + if (info->t_stale_removal || zrouter.graceful_restart) { struct vrf *vrf = vrf_lookup_by_id(info->vrf_id); - LOG_GR("%s: Client %s canceled stale delete timer vrf %s(%d)", + LOG_GR("%s: Client %s route update complete for all AFI/SAFI in vrf %s(%d)", __func__, zebra_route_string(client->proto), VRF_LOGNAME(vrf), info->vrf_id); EVENT_OFF(info->t_stale_removal); @@ -654,7 +684,7 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, } void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, - uint8_t instance) + uint8_t instance, time_t restart_time) { struct zserv *client = zserv_find_client(proto, instance); struct client_gr_info *info = NULL; @@ -676,6 +706,7 @@ void zebra_gr_process_client(afi_t afi, vrf_id_t vrf_id, uint8_t proto, gac->afi = afi; gac->proto = proto; gac->instance = instance; + gac->restart_time = restart_time; event_add_event(zrouter.master, zebra_gr_delete_stale_route_table_afi, gac, 0, &gac->t_gac); diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index 6235ecada4..8164e2a56f 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -1782,6 +1782,12 @@ static struct nexthop *nexthop_set_resolved(afi_t afi, SET_FLAG(resolved_hop->flags, NEXTHOP_FLAG_ACTIVE); resolved_hop->vrf_id = nexthop->vrf_id; + + /* Using weighted ECMP, we should respect the weight and use + * the same value for non-recursive next-hop. + */ + resolved_hop->weight = nexthop->weight; + switch (newhop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 5b95d8668a..59190e9dd3 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -1659,6 +1659,9 @@ static bool rib_update_nhg_from_ctx(struct nexthop_group *re_nhg, if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_DUPLICATE)) + continue; + /* Check for a FIB nexthop corresponding to the RIB nexthop */ if (!nexthop_same(ctx_nexthop, nexthop)) { /* If the FIB doesn't know about the nexthop, @@ -2693,8 +2696,7 @@ static void early_route_memory_free(struct zebra_early_route *ere) if (ere->re_nhe) zebra_nhg_free(ere->re_nhe); - zapi_re_opaque_free(ere->re->opaque); - XFREE(MTYPE_RE, ere->re); + zebra_rib_route_entry_free(ere->re); XFREE(MTYPE_WQ_WRAPPER, ere); } @@ -3159,6 +3161,7 @@ struct meta_q_gr_run { vrf_id_t vrf_id; uint8_t proto; uint8_t instance; + time_t restart_time; }; static void process_subq_gr_run(struct listnode *lnode) @@ -3166,7 +3169,7 @@ static void process_subq_gr_run(struct listnode *lnode) struct meta_q_gr_run *gr_run = listgetdata(lnode); zebra_gr_process_client(gr_run->afi, gr_run->vrf_id, gr_run->proto, - gr_run->instance); + gr_run->instance, gr_run->restart_time); XFREE(MTYPE_WQ_WRAPPER, gr_run); } @@ -3833,7 +3836,8 @@ static void rib_meta_queue_free(struct meta_queue *mq, struct list *l, } static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, - struct zebra_vrf *zvrf) + const struct zebra_vrf *zvrf, + uint8_t proto, uint8_t instance) { struct zebra_early_route *ere; struct listnode *node, *nnode; @@ -3842,6 +3846,10 @@ static void early_route_meta_queue_free(struct meta_queue *mq, struct list *l, if (zvrf && ere->re->vrf_id != zvrf->vrf->vrf_id) continue; + if (proto != ZEBRA_ROUTE_ALL && + (proto != ere->re->type && instance != ere->re->instance)) + continue; + early_route_memory_free(ere); node->data = NULL; list_delete_node(l, node); @@ -3880,7 +3888,8 @@ void meta_queue_free(struct meta_queue *mq, struct zebra_vrf *zvrf) evpn_meta_queue_free(mq, mq->subq[i], zvrf); break; case META_QUEUE_EARLY_ROUTE: - early_route_meta_queue_free(mq, mq->subq[i], zvrf); + early_route_meta_queue_free(mq, mq->subq[i], zvrf, + ZEBRA_ROUTE_ALL, 0); break; case META_QUEUE_EARLY_LABEL: early_label_meta_queue_free(mq, mq->subq[i], zvrf); @@ -4060,9 +4069,7 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) rib_re_nhg_free(re); - zapi_re_opaque_free(re->opaque); - - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } void rib_delnode(struct route_node *rn, struct route_entry *re) @@ -4266,7 +4273,8 @@ static int rib_meta_queue_early_route_add(struct meta_queue *mq, void *data) return 0; } -int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) +int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance, + time_t restart_time) { struct meta_q_gr_run *gr_run; @@ -4276,6 +4284,7 @@ int rib_add_gr_run(afi_t afi, vrf_id_t vrf_id, uint8_t proto, uint8_t instance) gr_run->proto = proto; gr_run->vrf_id = vrf_id; gr_run->instance = instance; + gr_run->restart_time = restart_time; return mq_add_handler(gr_run, rib_meta_queue_gr_run_add); } @@ -4307,6 +4316,7 @@ struct route_entry *zebra_rib_route_entry_new(vrf_id_t vrf_id, int type, void zebra_rib_route_entry_free(struct route_entry *re) { + zapi_re_opaque_free(re); XFREE(MTYPE_RE, re); } @@ -4377,7 +4387,7 @@ int rib_add_multipath(afi_t afi, safi_t safi, struct prefix *p, /* In error cases, free the route also */ if (ret < 0) - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); return ret; } @@ -4694,6 +4704,10 @@ void rib_sweep_route(struct event *t) struct vrf *vrf; struct zebra_vrf *zvrf; + zrouter.rib_sweep_time = monotime(NULL); + /* TODO: Change to debug */ + zlog_info("Sweeping the RIB for stale routes..."); + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { if ((zvrf = vrf->info) == NULL) continue; @@ -4742,6 +4756,10 @@ unsigned long rib_score_proto(uint8_t proto, unsigned short instance) if (!zvrf) continue; + early_route_meta_queue_free(zrouter.mq, + zrouter.mq->subq[META_QUEUE_EARLY_ROUTE], + zvrf, proto, instance); + cnt += rib_score_proto_table(proto, instance, zvrf->table[AFI_IP][SAFI_UNICAST]) + rib_score_proto_table( diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index bff8258879..303a81bb3e 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -826,7 +826,7 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, /* free RE and nexthops */ zebra_nhg_free(re->nhe); - XFREE(MTYPE_RE, re); + zebra_rib_route_entry_free(re); } static void copy_state(struct rnh *rnh, const struct route_entry *re, diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index c1ec5067d9..46afbcecfa 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -650,9 +650,8 @@ route_match_address_prefix_list(void *rule, const struct prefix *prefix, plist = prefix_list_lookup(afi, (char *)rule); if (plist == NULL) { if (unlikely(CHECK_FLAG(rmap_debug, DEBUG_ROUTEMAP_DETAIL))) - zlog_debug( - "%s: Prefix List %s specified does not exist defaulting to NO_MATCH", - __func__, (char *)rule); + zlog_debug("%s: Prefix List %s (%s) specified does not exist defaulting to NO_MATCH", + __func__, (char *)rule, afi2str(afi)); return RMAP_NOMATCH; } diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index 3fd4e6eb1f..8d6b2f3476 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -238,7 +238,7 @@ void zebra_router_terminate(void) { struct zebra_router_table *zrt, *tmp; - EVENT_OFF(zrouter.sweeper); + EVENT_OFF(zrouter.t_rib_sweep); RB_FOREACH_SAFE (zrt, zebra_router_table_head, &zrouter.tables, tmp) zebra_router_free_table(zrt); diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 3041707439..c86c6be1ef 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -191,10 +191,16 @@ struct zebra_router { enum multicast_mode ipv4_multicast_mode; /* - * Time for when we sweep the rib from old routes + * zebra start time and time of sweeping RIB of old routes */ time_t startup_time; - struct event *sweeper; + time_t rib_sweep_time; + + /* FRR fast/graceful restart info */ + bool graceful_restart; + int gr_cleanup_time; +#define ZEBRA_GR_DEFAULT_RIB_SWEEP_TIME 500 + struct event *t_rib_sweep; /* * The hash of nexthop groups associated with this router diff --git a/zebra/zebra_srv6.c b/zebra/zebra_srv6.c index bb872ef91c..082d4609aa 100644 --- a/zebra/zebra_srv6.c +++ b/zebra/zebra_srv6.c @@ -18,11 +18,6 @@ #include "zebra/zebra_srv6.h" #include "zebra/zebra_errors.h" #include "zebra/ge_netlink.h" -#include -#include -#include -#include -#include #include #include @@ -33,6 +28,16 @@ DEFINE_MGROUP(SRV6_MGR, "SRv6 Manager"); DEFINE_MTYPE_STATIC(SRV6_MGR, SRV6M_CHUNK, "SRv6 Manager Chunk"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_BLOCK, "SRv6 SID block"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_FUNC, "SRv6 SID function"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_USID_WLIB, + "SRv6 uSID Wide LIB information"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID, "SRv6 SID"); +DEFINE_MTYPE_STATIC(SRV6_MGR, ZEBRA_SRV6_SID_CTX, "SRv6 SID context"); + +/* Prototypes */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func); /* define hooks for the basic API, so that it can be specialized or served * externally @@ -55,6 +60,18 @@ DEFINE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DEFINE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DEFINE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); +DEFINE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); + /* define wrappers to be called in zapi_msg.c (as hooks must be called in * source file where they were defined) */ @@ -85,11 +102,502 @@ int srv6_manager_client_disconnect_cb(struct zserv *client) return 0; } + +void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + hook_call(srv6_manager_get_sid, sid, client, ctx, sid_value, + locator_name); +} + +void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + hook_call(srv6_manager_release_sid, client, ctx); +} + +void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + hook_call(srv6_manager_get_locator, locator, client, locator_name); +} + static int zebra_srv6_cleanup(struct zserv *client) { + /* Client has disconnected, let's release all the SIDs allocated by it. */ + release_daemon_srv6_sids(client); return 0; } +/* --- Zebra SRv6 SID context management functions -------------------------- */ + +struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void) +{ + struct zebra_srv6_sid_ctx *ctx = NULL; + + ctx = XCALLOC(MTYPE_ZEBRA_SRV6_SID_CTX, + sizeof(struct zebra_srv6_sid_ctx)); + + return ctx; +} + +void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_CTX, ctx); +} + +/** + * Free an SRv6 SID context. + * + * @param val SRv6 SID context to be freed + */ +void delete_zebra_srv6_sid_ctx(void *val) +{ + zebra_srv6_sid_ctx_free((struct zebra_srv6_sid_ctx *)val); +} + +/* --- Zebra SRv6 SID format management functions --------------------------- */ + +void srv6_sid_format_register(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + /* Ensure that the format is registered only once */ + assert(!srv6_sid_format_lookup(format->name)); + + listnode_add(srv6->sid_formats, format); +} + +void srv6_sid_format_unregister(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + + listnode_delete(srv6->sid_formats, format); +} + +struct srv6_sid_format *srv6_sid_format_lookup(const char *name) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_sid_format *format; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) + if (!strncmp(name, format->name, sizeof(format->name))) + return format; + + return NULL; +} + +/* + * Called to change the SID format of a locator. + * + * After switching the locator to a different format, the SIDs allocated + * from the locator may no longer be valid; we need to notify the + * interested zclient that the locator has changed, so that the + * zclients can withdraw/uninstall the old SIDs, allocate/advertise/program + * the new SIDs. + */ +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block_old, *block_new; + struct prefix_ipv6 block_pfx_new; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (!locator) + return; + + locator->sid_format = format; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, old=%s new=%s", + __func__, locator->name, + locator->sid_format ? ((struct srv6_sid_format *) + locator->sid_format) + ->name + : NULL, + format ? format->name : NULL); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_DEL notification to zclients", + __func__, locator->name); + + /* Release the current parent block */ + block_old = locator->sid_block; + if (block_old) { + block_old->refcnt--; + if (block_old->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block_old); + zebra_srv6_sid_block_free(block_old); + } + } + locator->sid_block = NULL; + + block_pfx_new = locator->prefix; + if (format) + block_pfx_new.prefixlen = format->block_len; + else + block_pfx_new.prefixlen = locator->block_bits_length; + apply_mask(&block_pfx_new); + + /* Allocate the new parent block */ + block_new = zebra_srv6_sid_block_lookup(&block_pfx_new); + if (!block_new) { + block_new = zebra_srv6_sid_block_alloc(format, &block_pfx_new); + listnode_add(srv6->sid_blocks, block_new); + } + + block_new->refcnt++; + locator->sid_block = block_new; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s format has changed, send SRV6_LOCATOR_ADD notification to zclients", + __func__, locator->name); + + /* Notify zclients about the updated locator */ + zebra_srv6_locator_add(locator); +} + +/* + * Called when a SID format is modified by the user. + * + * After modifying a SID format, the SIDs that are using that format may no + * longer be valid. + * This function walks through the list of locators that are using the SID format + * and notifies the zclients that the locator has changed, so that the zclients + * can withdraw/uninstall the old SIDs, allocate/program/advertise the new SIDs. + */ +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *locator; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SID format %s has changed. Notifying zclients.", + __func__, format->name); + + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { + if (locator->sid_format == format) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: Locator %s has changed because its format (%s) has been modified. Notifying zclients.", + __func__, locator->name, + format->name); + + /* Notify zclients that the locator is no longer valid */ + zebra_notify_srv6_locator_delete(locator); + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + /* Notify zclients about the updated locator */ + zebra_notify_srv6_locator_add(locator); + } + } +} + +/* + * Helper function to create the SRv6 compressed format `usid-f3216`. + */ +static struct srv6_sid_format *create_srv6_sid_format_usid_f3216(void) +{ + struct srv6_sid_format *format = NULL; + + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_USID_F3216_NAME); + + format->type = SRV6_SID_FORMAT_TYPE_USID; + + /* Define block/node/function length */ + format->block_len = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + return format; +} + +/* + * Helper function to create the SRv6 uncompressed format. + */ +static struct srv6_sid_format *create_srv6_sid_format_uncompressed(void) +{ + struct srv6_sid_format *format = NULL; + + format = srv6_sid_format_alloc(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + + format->type = SRV6_SID_FORMAT_TYPE_UNCOMPRESSED; + + /* Define block/node/function length */ + format->block_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN; + format->node_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + format->function_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN; + format->argument_len = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN; + + /* Define the ranges from which the SID function can be allocated */ + format->config.uncompressed.explicit_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + return format; +} + +/* --- Zebra SRv6 SID function management functions ---------------------------- */ + +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func) +{ + uint32_t *sid_func_ptr; + + sid_func_ptr = XCALLOC(MTYPE_ZEBRA_SRV6_SID_FUNC, sizeof(uint32_t)); + *sid_func_ptr = func; + + return sid_func_ptr; +} + +void zebra_srv6_sid_func_free(uint32_t *func) +{ + XFREE(MTYPE_ZEBRA_SRV6_SID_FUNC, func); +} + +/** + * Free an SRv6 SID function. + * + * @param val SRv6 SID function to be freed + */ +void delete_zebra_srv6_sid_func(void *val) +{ + zebra_srv6_sid_func_free((uint32_t *)val); +} + +/* --- Zebra SRv6 SID block management functions ---------------------------- */ + +static struct zebra_srv6_sid_block *zebra_srv6_sid_block_alloc_internal(void) +{ + struct zebra_srv6_sid_block *block = NULL; + + block = XCALLOC(MTYPE_ZEBRA_SRV6_SID_BLOCK, + sizeof(struct zebra_srv6_sid_block)); + + return block; +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, + struct prefix_ipv6 *prefix) +{ + struct zebra_srv6_sid_block *block; + + block = zebra_srv6_sid_block_alloc_internal(); + block->sid_format = format; + block->prefix = *prefix; + + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Init uSID LIB */ + block->u.usid.lib.func_allocated = list_new(); + block->u.usid.lib.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.func_released = list_new(); + block->u.usid.lib.func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.lib.first_available_func = + format->config.usid.lib_start; + + /* Init uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + block->u.usid.wide_lib = + XCALLOC(MTYPE_ZEBRA_SRV6_USID_WLIB, + (wlib_end - wlib_start + 1) * + sizeof(struct wide_lib)); + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + block->u.usid.wide_lib[func].func_allocated = + list_new(); + block->u.usid.wide_lib[func].func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func_released = + list_new(); + block->u.usid.wide_lib[func].func_released->del = + delete_zebra_srv6_sid_func; + block->u.usid.wide_lib[func].func = func; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + } else { + /* We should never arrive here */ + assert(0); + } + } else { + block->u.uncompressed.func_allocated = list_new(); + block->u.uncompressed.func_allocated->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.func_released = list_new(); + block->u.uncompressed.func_released->del = + delete_zebra_srv6_sid_func; + block->u.uncompressed.first_available_func = 1; + } + + return block; +} + +void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block) +{ + if (block->sid_format) { + if (block->sid_format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t wlib_start, wlib_end, func; + + /* Free uSID LIB */ + list_delete(&block->u.usid.lib.func_allocated); + list_delete(&block->u.usid.lib.func_released); + + /* Free uSID Wide LIB */ + wlib_start = block->sid_format->config.usid.wlib_start; + wlib_end = block->sid_format->config.usid.wlib_end; + for (func = 0; func < wlib_end - wlib_start + 1; + func++) { + list_delete(&block->u.usid.wide_lib[func] + .func_allocated); + list_delete(&block->u.usid.wide_lib[func] + .func_released); + } + XFREE(MTYPE_ZEBRA_SRV6_USID_WLIB, + block->u.usid.wide_lib); + } else if (block->sid_format->type == + SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + list_delete(&block->u.uncompressed.func_allocated); + list_delete(&block->u.uncompressed.func_released); + } + + XFREE(MTYPE_ZEBRA_SRV6_SID_BLOCK, block); +} + +/** + * Free an SRv6 SID block. + * + * @param val SRv6 SID block to be freed + */ +void delete_zebra_srv6_sid_block(void *val) +{ + zebra_srv6_sid_block_free((struct zebra_srv6_sid_block *)val); +} + +struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, block)) + if (prefix_match(prefix, &block->prefix)) + return block; + + return NULL; +} + +/* --- Zebra SRv6 SID management functions ---------------------------------- */ + +/** + * Alloc and fill an SRv6 SID. + * + * @param ctx Context associated with the SID to be created + * @param sid_value IPv6 address associated with the SID to be created + * @param locator Parent locator of the SID to be created + * @param sid_block Block from which the SID value has been allocated + * @param sid_func Function part of the SID to be created + * @param alloc_mode Allocation mode of the Function (dynamic vs explicit) + * @return The requested SID + */ +struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode) +{ + struct zebra_srv6_sid *sid; + + if (!ctx || !sid_value) + return NULL; + + sid = XCALLOC(MTYPE_ZEBRA_SRV6_SID, sizeof(struct zebra_srv6_sid)); + sid->ctx = ctx; + sid->value = *sid_value; + sid->locator = locator; + sid->block = sid_block; + sid->func = sid_func; + sid->alloc_mode = alloc_mode; + sid->client_list = list_new(); + + return sid; +} + +void zebra_srv6_sid_free(struct zebra_srv6_sid *sid) +{ + list_delete(&sid->client_list); + XFREE(MTYPE_ZEBRA_SRV6_SID, sid); +} + +/** + * Free an SRv6 SID. + * + * @param val SRv6 SID to be freed + */ +void delete_zebra_srv6_sid(void *val) +{ + zebra_srv6_sid_free((struct zebra_srv6_sid *)val); +} + void zebra_srv6_locator_add(struct srv6_locator *locator) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); @@ -121,7 +629,6 @@ void zebra_srv6_locator_add(struct srv6_locator *locator) void zebra_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct zserv *client; @@ -136,18 +643,8 @@ void zebra_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn( - "%s: Not found zclient(proto=%u, instance=%u).", - __func__, c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } listnode_delete(srv6->locators, locator); srv6_locator_free(locator); @@ -190,7 +687,6 @@ void zebra_notify_srv6_locator_add(struct srv6_locator *locator) void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) { struct listnode *n; - struct srv6_locator_chunk *c; struct zserv *client; /* @@ -204,17 +700,8 @@ void zebra_notify_srv6_locator_delete(struct srv6_locator *locator) * by ZEBRA_SRV6_LOCATOR_DELETE, and this notification is sent to the * owner of each chunk. */ - for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, n, c)) { - if (c->proto == ZEBRA_ROUTE_SYSTEM) - continue; - client = zserv_find_client(c->proto, c->instance); - if (!client) { - zlog_warn("Not found zclient(proto=%u, instance=%u).", - c->proto, c->instance); - continue; - } + for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, n, client)) zsend_zebra_srv6_locator_delete(client, locator); - } } struct zebra_srv6 srv6; @@ -222,10 +709,32 @@ struct zebra_srv6 srv6; struct zebra_srv6 *zebra_srv6_get_default(void) { static bool first_execution = true; + struct srv6_sid_format *format_usidf3216; + struct srv6_sid_format *format_uncompressed; if (first_execution) { first_execution = false; srv6.locators = list_new(); + + /* Initialize list of SID formats */ + srv6.sid_formats = list_new(); + srv6.sid_formats->del = delete_srv6_sid_format; + + /* Create SID format `usid-f3216` */ + format_usidf3216 = create_srv6_sid_format_usid_f3216(); + srv6_sid_format_register(format_usidf3216); + + /* Create SID format `uncompressed` */ + format_uncompressed = create_srv6_sid_format_uncompressed(); + srv6_sid_format_register(format_uncompressed); + + /* Init list to store SRv6 SIDs */ + srv6.sids = list_new(); + srv6.sids->del = delete_zebra_srv6_sid_ctx; + + /* Init list to store SRv6 SID blocks */ + srv6.sid_blocks = list_new(); + srv6.sid_blocks->del = delete_zebra_srv6_sid_block; } return &srv6; } @@ -427,30 +936,1522 @@ void zebra_srv6_encap_src_addr_unset(void) memset(&srv6->encap_src_addr, 0, sizeof(struct in6_addr)); } -void zebra_srv6_terminate(void) +/* --- SRv6 SID Allocation/Release functions -------------------------------- */ + +/** + * Return the SRv6 SID obtained composing the locator and function. + * + * @param sid_value SRv6 SID address returned + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_compose(struct in6_addr *sid_value, + struct srv6_locator *locator, + uint32_t sid_func) { - struct srv6_locator *locator; + uint8_t offset, func_len; + struct srv6_sid_format *format; - if (!srv6.locators) - return; + if (!sid_value || !locator) + return false; - while (listcount(srv6.locators)) { - locator = listnode_head(srv6.locators); + format = locator->sid_format; + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = locator->block_bits_length + locator->node_bits_length; + func_len = locator->function_bits_length; + } + + *sid_value = locator->prefix.prefix; + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; - listnode_delete(srv6.locators, locator); - srv6_locator_free(locator); + sid_value->s6_addr[tidx / 8] &= ~(0x1 << (7 - tidx % 8)); + if (sid_func >> (func_len - 1 - idx) & 0x1) + sid_value->s6_addr[tidx / 8] |= 0x1 << (7 - tidx % 8); } - list_delete(&srv6.locators); + return true; } -void zebra_srv6_init(void) +/** + * Return the parent locator and function of an SRv6 SID. + * + * @param sid_value SRv6 SID address to be decomposed + * @param sid_block Parent block of the SRv6 SID + * @param locator Parent locator of the SRv6 SID + * @param sid_func Function part of the SID + * @param sid_wide_func Wide function of the SID + * @return True if success, False otherwise + */ +static bool zebra_srv6_sid_decompose(struct in6_addr *sid_value, + struct zebra_srv6_sid_block **sid_block, + struct srv6_locator **locator, + uint32_t *sid_func, uint32_t *sid_wide_func) { - hook_register(zserv_client_close, zebra_srv6_cleanup); - hook_register(srv6_manager_get_chunk, - zebra_srv6_manager_get_locator_chunk); - hook_register(srv6_manager_release_chunk, - zebra_srv6_manager_release_locator_chunk); + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct srv6_locator *l; + struct zebra_srv6_sid_block *b; + struct srv6_sid_format *format; + struct listnode *node; + struct prefix_ipv6 tmp_prefix; + uint8_t offset, func_len; + + if (!sid_value || !sid_func) + return false; + + *sid_func = 0; + *sid_wide_func = 0; + + /* + * Build a temporary prefix_ipv6 object representing the SRv6 SID. + * This temporary prefix object is used below by the prefix_match + * function to check if the SID belongs to a specific locator. + */ + tmp_prefix.family = AF_INET6; + tmp_prefix.prefixlen = IPV6_MAX_BITLEN; + tmp_prefix.prefix = *sid_value; + + /* + * Lookup the parent locator of the SID and return the locator and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, l)) { + /* + * Check if the locator prefix includes the temporary prefix + * representing the SID. + */ + if (prefix_match((struct prefix *)&l->prefix, + (struct prefix *)&tmp_prefix)) { + format = l->sid_format; + + if (format) { + offset = format->block_len + format->node_len; + func_len = format->function_len; + } else { + offset = l->block_bits_length + + l->node_bits_length; + func_len = l->function_bits_length; + } + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((func_len - 1 - idx) / 8) * 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = l->sid_format; + + offset = format->block_len + + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / + 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * + 8); + } + } + } + + *locator = l; + *sid_block = l->sid_block; + + return true; + } + } + + /* + * If we arrive here, the SID does not belong to any locator. + * Then, let's try to find the parent block from which the SID + * has been allocated. + */ + + /* + * Lookup the parent block of the SID and return the block and + * the function of the SID. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sid_blocks, node, b)) { + /* + * Check if the block prefix includes the temporary prefix + * representing the SID + */ + if (prefix_match((struct prefix *)&b->prefix, + (struct prefix *)&tmp_prefix)) { + format = b->sid_format; + + if (!format) + continue; + + offset = format->block_len + format->node_len; + func_len = format->function_len; + + for (uint8_t idx = 0; idx < func_len; idx++) { + uint8_t tidx = offset + idx; + *sid_func |= (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << ((func_len - 1 - idx) / 8); + } + + /* + * If function comes from the Wide LIB range, we also + * need to get the Wide function. + */ + if (*sid_func >= format->config.usid.wlib_start && + *sid_func <= format->config.usid.wlib_end) { + format = b->sid_format; + + offset = format->block_len + format->node_len + + format->function_len; + + for (uint8_t idx = 0; idx < 16; idx++) { + uint8_t tidx = offset + idx; + *sid_wide_func |= + (sid_value->s6_addr[tidx / 8] & + (0x1 << (7 - tidx % 8))) + << (((16 - 1 - idx) / 8) * 8); + } + } + + *sid_block = b; + + return true; + } + } + + return false; +} + +/** + * Allocate an explicit SID function (i.e. specific SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function to be allocated + * @param sid_wide_func SID wide function to be allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t wlib_end = format->config.usid.wlib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function has to be allocated from the ELIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = + zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.usid.lib.func_allocated, + sid_func_ptr); + block->u.usid.lib.num_func_allocated++; + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function has to be allocated from the EWLIB range */ + + /* Ensure that the requested SID function has not already been taken */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, + sid_wide_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + if (sid_wide_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_wide_func_ptr = zebra_srv6_sid_func_alloc( + sid_wide_func); + listnode_add(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + block->u.usid.wide_lib[sid_func] + .num_func_allocated++; + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_err("%s: invalid SM request arguments: SID function %u out of explicit range (%u - %u)", + __func__, sid_func, explicit_start, + explicit_end); + return false; + } + + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, + sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* Ensure that the SID function has not already been taken */ + + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* SID function already taken */ + if (sid_func_ptr) { + zlog_err("%s: invalid SM request arguments: SID function %u already taken", + __func__, sid_func); + return false; + } + + /* + * Mark the SID function as "taken" by adding it to the "func_allocated" list and + * increase the counter of function allocated + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add(block->u.uncompressed.func_allocated, sid_func_ptr); + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return true; +} + +/** + * Allocate a dynamic SID function (i.e. any available SID function value) from a given SID block. + * + * @param block SRv6 SID block from which the SID function has to be allocated + * @param sid_func SID function allocated + * + * @return true on success, false otherwise + */ +static bool alloc_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t *sid_func) +{ + struct srv6_sid_format *format; + uint32_t *sid_func_ptr = NULL; + + if (!block || !sid_func) + return false; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to allocate dynamic SID function from block %pFX", + __func__, &block->prefix); + + /* + * Allocate SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + /* Format is uSID and behavior => allocate SID function from LIB range */ + + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.usid.lib.first_available_func > dlib_end) { + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted", + __func__); + return false; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.usid.lib.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.usid.lib.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.usid.lib.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = + block->u.usid.lib.first_available_func; + block->u.usid.lib.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.usid.lib.num_func_allocated++; + + if (block->u.usid.lib.first_available_func > dlib_end) + zlog_warn("%s: SRv6: Warning, SRv6 Dynamic LIB is depleted and next SID request will fail", + __func__); + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + /* Format is uncompressed => allocate SID function from Dynamic range */ + + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Check if we ran out of available SID functions */ + if (block->u.uncompressed.first_available_func > + dynamic_end) { + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted", + __func__); + return NULL; + } + + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed + .first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + + if (block->u.uncompressed.first_available_func > + dynamic_end) + zlog_warn("%s: SRv6: Warning, SRv6 SID Dynamic alloc space is depleted and next SID request will fail", + __func__); + } else { + /* We should never arrive here */ + zlog_err("%s: unknown SID format type: %u", __func__, + format->type); + assert(0); + } + } else { + /* + * First, let's check if there are any SID functions that were previously + * allocated and then released. + */ + if (listcount(block->u.uncompressed.func_released) != 0) { + /* + * There are SID functions previously allocated and then released, + * let's pick the first one and reuse it now. + */ + sid_func_ptr = listnode_head( + block->u.uncompressed.func_released); + *sid_func = *sid_func_ptr; + listnode_delete(block->u.uncompressed.func_released, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* + * There are no SID functions previously allocated and then released, + * let's allocate a new function from the pool of available functions. + */ + *sid_func = block->u.uncompressed.first_available_func; + block->u.uncompressed.first_available_func++; + } + + /* Increase the counter of SID functions allocated */ + block->u.uncompressed.num_func_allocated++; + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated dynamic SID function %u from block %pFX", + __func__, *sid_func, &block->prefix); + + return true; +} + +/** + * Get an explicit SID (i.e., a specific SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value specific SRv6 SID value (i.e. IPv6 address) to be + * allocated explicitly + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_explicit(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx = NULL; + struct listnode *node; + uint32_t sid_func = 0, sid_func_wide = 0; + struct srv6_locator *locator = NULL; + struct zebra_srv6_sid_block *block = NULL; + char buf[256]; + + if (!ctx || !sid_value) + return -1; + + /* Check if we already have a SID associated with the provided context */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + /* + * If the context is already associated with a SID that has the same SID value, then + * return the existing SID + */ + if (sid_same(&s->sid->value, sid_value)) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SRv6 SID %pI6 ctx %s", + __func__, &s->sid->value, + srv6_sid_ctx2str(buf, + sizeof(buf), + ctx)); + *sid = s->sid; + return 0; + } + + /* + * It is not allowed to allocate an explicit SID for a given context if the context + * is already associated with an explicit SID + */ + if (s->sid->alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { + zlog_err("%s: cannot alloc SID %pI6 for ctx %s: ctx already associated with SID %pI6", + __func__, sid_value, + srv6_sid_ctx2str(buf, sizeof(buf), + &s->ctx), + &s->sid->value); + return -1; + } + + zctx = s; + break; + } + } + + /* Get parent locator and function of the provided SID */ + if (!zebra_srv6_sid_decompose(sid_value, &block, &locator, &sid_func, + &sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: parent block/locator not found for SID %pI6", + __func__, sid_value); + return -1; + } + + if (ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + zlog_err("%s: invalid SM request arguments: explicit SID allocation not allowed for End/uN behavior", + __func__); + return -1; + } + + /* Allocate an explicit SID function for the SID */ + if (!alloc_srv6_sid_func_explicit(block, sid_func, sid_func_wide)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + if (!zctx) { + /* If we don't have a zebra SID context for this context, allocate a new one */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + } else { + /* + * If we already have a SID associated with this context, we need to + * deallocate the current SID function before allocating the new one + */ + if (zctx->sid) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: ctx %s already associated with a dynamic SID %pI6, releasing dynamic SID", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &zctx->sid->value); + + release_srv6_sid_func_dynamic(block, zctx->sid->func); + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + } + } + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_EXPLICIT); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated explicit SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get a dynamic SID (i.e., any available SID value) for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param locator SRv6 locator from which the SID has to be allocated + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +static int get_srv6_sid_dynamic(struct zebra_srv6_sid **sid, + struct srv6_sid_ctx *ctx, + struct srv6_locator *locator) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct srv6_sid_format *format; + struct zebra_srv6_sid_ctx *s = NULL; + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node; + struct in6_addr sid_value; + uint32_t sid_func = 0; + char buf[256]; + + if (!ctx || !locator) + return -1; + + block = locator->sid_block; + format = locator->sid_format; + + /* + * If we already have a SID for the provided context, we return the existing + * SID instead of allocating a new one. + */ + for (ALL_LIST_ELEMENTS_RO(srv6->sids, node, s)) { + if (locator && s->sid && s->sid->locator) { + if (strncmp(s->sid->locator->name, locator->name, + SRV6_LOCNAME_SIZE)) { + continue; + } + } + if (memcmp(&s->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: returning existing SID %s %pI6", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), + ctx), + &s->sid->value); + *sid = s->sid; + return 0; + } + } + + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID && + ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else if (!format && ctx->behavior == ZEBRA_SEG6_LOCAL_ACTION_END) { + /* uN SID is allocated from the GIB range */ + sid_value = locator->prefix.prefix; + } else { + /* Allocate a dynamic SID function for the SID */ + if (!alloc_srv6_sid_func_dynamic(block, &sid_func)) { + zlog_err("%s: invalid SM request arguments: failed to allocate SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + return -1; + } + + /* Compose the SID as the locator followed by the SID function */ + zebra_srv6_sid_compose(&sid_value, locator, sid_func); + } + + /* Allocate a zebra SID context to store SID context information */ + zctx = zebra_srv6_sid_ctx_alloc(); + zctx->ctx = *ctx; + + /* Allocate the SID to store SID information */ + *sid = zebra_srv6_sid_alloc(zctx, &sid_value, locator, block, sid_func, + SRV6_SID_ALLOC_MODE_DYNAMIC); + if (!(*sid)) { + flog_err(EC_ZEBRA_SM_CANNOT_ASSIGN_SID, + "%s: failed to create SRv6 SID ctx %s (%pI6)", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), &sid_value); + return -1; + } + (*sid)->ctx = zctx; + zctx->sid = *sid; + listnode_add(srv6->sids, zctx); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: allocated new dynamic SRv6 SID %pI6 for context %s", + __func__, &(*sid)->value, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + return 1; +} + +/** + * Get an SRv6 SID for a given context. + * + * If a SID already exists associated with the context, it returns the existing SID. + * Otherwise, it allocates a new SID. + * + * If the sid_value parameter is non-NULL, it allocates the requested SID value + * if it is available (explicit SID allocation). + * If the sid_value parameter is NULL, it allocates any available SID value + * (dynamic SID allocation). + * + * @param sid SID returned + * @param ctx Context for which the SID has been requested + * @param sid_value SRv6 SID value to be allocated (for explicit SID allocation) + * @param locator_name Parent SRv6 locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 if the function returned an existing SID and SID value has not changed, + * 1 if a new SID has been allocated or the existing SID value has changed, -1 if an error occurred + */ +int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name) +{ + int ret = -1; + struct srv6_locator *locator; + char buf[256]; + + enum srv6_sid_alloc_mode alloc_mode = + (sid_value) ? SRV6_SID_ALLOC_MODE_EXPLICIT + : SRV6_SID_ALLOC_MODE_DYNAMIC; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: received SRv6 SID alloc request: SID ctx %s (%pI6), mode=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value, srv6_sid_alloc_mode2str(alloc_mode)); + + if (alloc_mode == SRV6_SID_ALLOC_MODE_EXPLICIT) { + /* + * Explicit SID allocation: allocate a specific SID value + */ + + if (!sid_value) { + zlog_err("%s: invalid SM request arguments: missing SRv6 SID value, necessary for explicit allocation", + __func__); + return -1; + } + + ret = get_srv6_sid_explicit(sid, ctx, sid_value); + } else { + /* + * Dynamic SID allocation: allocate any available SID value + */ + + if (!locator_name) { + zlog_err("%s: invalid SM request arguments: missing SRv6 locator, necessary for dynamic allocation", + __func__); + return -1; + } + + locator = zebra_srv6_locator_lookup(locator_name); + if (!locator) { + zlog_err("%s: invalid SM request arguments: SRv6 locator '%s' does not exist", + __func__, locator_name); + return -1; + } + + ret = get_srv6_sid_dynamic(sid, ctx, locator); + } + + return ret; +} + +/** + * Release an explicit SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static bool release_srv6_sid_func_explicit(struct zebra_srv6_sid_block *block, + uint32_t sid_func, + uint32_t sid_wide_func) +{ + struct srv6_sid_format *format; + struct listnode *node; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format) { + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t elib_start = format->config.usid.elib_start; + uint32_t elib_end = format->config.usid.elib_end; + uint32_t ewlib_start = format->config.usid.ewlib_start; + uint32_t ewlib_end = format->config.usid.wlib_end; + uint32_t *sid_wide_func_ptr = NULL; + + /* Figure out the range from which the SID function has been allocated and release it */ + if ((sid_func >= elib_start) && (sid_func <= elib_end)) { + /* The SID function comes from the ELIB range */ + + /* Lookup SID function in the functions allocated list of ELIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid.lib + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the ELIB range */ + listnode_delete(block->u.usid.lib.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else if ((sid_func >= ewlib_start) && + (sid_func <= ewlib_end)) { + /* The SID function comes from the EWLIB range */ + + /* Lookup SID function in the functions allocated list of EWLIB range */ + for (ALL_LIST_ELEMENTS_RO(block->u.usid + .wide_lib[sid_func] + .func_allocated, + node, sid_wide_func_ptr)) + if (*sid_wide_func_ptr == sid_wide_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_wide_func_ptr) { + zlog_warn("%s: failed to release wide SID function %u, function is not allocated", + __func__, sid_wide_func); + return -1; + } + + /* Release the SID function from the EWLIB range */ + listnode_delete(block->u.usid.wide_lib[sid_func] + .func_allocated, + sid_wide_func_ptr); + zebra_srv6_sid_func_free(sid_wide_func_ptr); + } else { + zlog_warn("%s: function %u is outside ELIB [%u/%u] and EWLIB alloc ranges [%u/%u]", + __func__, sid_func, elib_start, + elib_end, ewlib_start, ewlib_end); + return -1; + } + } else if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t explicit_start = + format->config.uncompressed.explicit_start; + uint32_t explicit_end = + (uint32_t)((1 << format->function_len) - 1); + + /* Ensure that the SID function comes from the Explicit range */ + if (!(sid_func >= explicit_start && + sid_func <= explicit_end)) { + zlog_warn("%s: function %u is outside explicit alloc range [%u/%u]", + __func__, sid_func, explicit_start, + explicit_end); + return -1; + } + + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed + .func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } else { + /* We should never arrive here */ + assert(0); + } + } else { + /* Lookup SID function in the functions allocated list of Explicit range */ + for (ALL_LIST_ELEMENTS_RO(block->u.uncompressed.func_allocated, + node, sid_func_ptr)) + if (*sid_func_ptr == sid_func) + break; + + /* Ensure that the SID function is allocated */ + if (!sid_func_ptr) { + zlog_warn("%s: failed to release SID function %u, function is not allocated", + __func__, sid_func); + return -1; + } + + /* Release the SID function from the Explicit range */ + listnode_delete(block->u.uncompressed.func_allocated, + sid_func_ptr); + zebra_srv6_sid_func_free(sid_func_ptr); + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released explicit SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Release a dynamic SRv6 SID function. + * + * @param block Parent SRv6 SID block of the SID function that has to be released + * @param sid_func SID function to be released + * @return 0 on success, -1 otherwise + */ +static int release_srv6_sid_func_dynamic(struct zebra_srv6_sid_block *block, + uint32_t sid_func) +{ + struct srv6_sid_format *format; + struct listnode *node, *nnode; + uint32_t *sid_func_ptr = NULL; + + if (!block) + return -1; + + format = block->sid_format; + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: trying to release dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + /* + * Release SID function from the corresponding range depending on the SID format type + */ + if (format && format->type == SRV6_SID_FORMAT_TYPE_USID) { + uint32_t dlib_start = format->config.usid.lib_start; + /* The Dynamic LIB range ends where the Explicit LIB range begins */ + uint32_t dlib_end = format->config.usid.elib_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic LIB (DLIB) range */ + if (!(sid_func >= dlib_start && sid_func <= dlib_end)) { + zlog_warn("%s: function %u is outside Dynamic LIB range [%u/%u]", + __func__, sid_func, dlib_start, dlib_end); + return -1; + } + + if (sid_func == block->u.usid.lib.first_available_func - 1) { + /* + * The SID function to be released precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.usid.lib.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.usid.lib + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.usid.lib.first_available_func - + 1) { + listnode_delete(block->u.usid + .lib + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.usid.lib + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The SID function to be released does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.usid.lib.func_released, + sid_func_ptr); + } + } else if (format && format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + uint32_t dynamic_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN; + /* The Dynamic range ends where the Explicit range begins */ + uint32_t dynamic_end = + format->config.uncompressed.explicit_start - 1; + + /* Ensure that the SID function to be released comes from the Dynamic range */ + if (!(sid_func >= dynamic_start && sid_func <= dynamic_end)) { + zlog_warn("%s: function %u is outside dynamic range [%u/%u]", + __func__, sid_func, dynamic_start, + dynamic_end); + return -1; + } + + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } else if (!format) { + if (sid_func == block->u.uncompressed.first_available_func - 1) { + /* + * The released SID function precedes the `first_available_func`. + * Reset first_available_func to the first available position. + */ + + block->u.uncompressed.first_available_func -= 1; + + bool found; + + do { + found = false; + for (ALL_LIST_ELEMENTS(block->u.uncompressed + .func_released, + node, nnode, + sid_func_ptr)) + if (*sid_func_ptr == + block->u.uncompressed + .first_available_func - + 1) { + listnode_delete(block->u.uncompressed + .func_released, + sid_func_ptr); + zebra_srv6_sid_func_free( + sid_func_ptr); + block->u.uncompressed + .first_available_func -= + 1; + found = true; + break; + } + } while (found); + } else { + /* + * The released SID function does not precede the `first_available_func`. + * Add the released function to the func_released array to indicate + * that it is available again for allocation. + */ + sid_func_ptr = zebra_srv6_sid_func_alloc(sid_func); + listnode_add_head(block->u.uncompressed.func_released, + sid_func_ptr); + } + } + + if (ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released dynamic SRv6 SID function %u from block %pFX", + __func__, sid_func, &block->prefix); + + return 0; +} + +/** + * Core function, release the SRv6 SID associated with a given context. + * + * @param client The client for which the SID has to be released + * @param ctx Context associated with the SRv6 SID to be released + * @return 0 on success, -1 otherwise + */ +int release_srv6_sid(struct zserv *client, struct zebra_srv6_sid_ctx *zctx) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + char buf[256]; + + if (!zctx || !zctx->sid) + return -1; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* Ensures the SID is in use by the client */ + if (!listnode_lookup(zctx->sid->client_list, client)) { + flog_err(EC_ZEBRA_SM_DAEMON_MISMATCH, "%s: Daemon mismatch!!", + __func__); + return -1; + } + + /* Remove the client from the list of clients using the SID */ + listnode_delete(zctx->sid->client_list, client); + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released SRv6 SID %pI6 associated with ctx %s (proto=%u, instance=%u)", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), &zctx->ctx), + client->proto, client->instance); + + /* + * If the SID is not used by any other client, then deallocate it + * and remove it from the SRv6 database. + */ + if (listcount(zctx->sid->client_list) == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: SRv6 SID %pI6 associated with ctx %s is no longer in use, removing it from SRv6 database", + __func__, &zctx->sid->value, + srv6_sid_ctx2str(buf, sizeof(buf), + &zctx->ctx)); + + if (!(zctx->sid->block->sid_format && + zctx->sid->block->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END) && + !(!zctx->sid->block->sid_format && + zctx->ctx.behavior == ZEBRA_SEG6_LOCAL_ACTION_END)) { + if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_EXPLICIT) + /* Release SRv6 SID function */ + release_srv6_sid_func_explicit(zctx->sid->block, + zctx->sid->func, + zctx->sid->wide_func); + else if (zctx->sid->alloc_mode == + SRV6_SID_ALLOC_MODE_DYNAMIC) + /* Release SRv6 SID function */ + release_srv6_sid_func_dynamic(zctx->sid->block, + zctx->sid->func); + else + /* We should never arrive here */ + assert(0); + } + + /* Free the SID */ + zebra_srv6_sid_free(zctx->sid); + zctx->sid = NULL; + + /* Remove the SID context from the list and free memory */ + listnode_delete(srv6->sids, zctx); + zebra_srv6_sid_ctx_free(zctx); + } + + return 0; +} + +/** + * Handle a get SRv6 Locator request received from a client. + * + * It looks up the requested locator and send it to the client. + * + * @param locator SRv6 locator returned by this function + * @param client The client that sent the Get SRv6 Locator request + * @param locator_name Name of the locator to look up + * + * @return 0 on success + */ +static int srv6_manager_get_srv6_locator_internal(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name) +{ + *locator = zebra_srv6_locator_lookup(locator_name); + if (!*locator) + return -1; + + return zsend_zebra_srv6_locator_add(client, *locator); +} + +/** + * Handle a get SID request received from a client. + * + * It gets a SID for a given context. If there is no SID associated with the context yet, + * we allocate one and return it to the client. Otherwise, we return the existing SID. + * + * - When the `sid_value` parameter is non-NULL, SRv6 Manager assigns the requested SID value + * if it is available (explicit SID allocation). + * - When the `sid_value` parameter is NULL, SRv6 Manager assigns any available SID value + * (dynamic SID allocation). + * + * Finally, notify the client whether the SID allocation was successful or failed. + * + * @param sid SID returned by this function + * @param client The client that requested the SID + * @param ctx Context for which the SID was requested + * @param sid_value SID value (i.e., IPv6 address) that has to be assigned to the SID + * (for explicit SID allocation) + * @param locator_name Locator from which the SID has to be allocated (for dynamic SID allocation) + * + * @return 0 on success, -1 otherwise + */ +static int srv6_manager_get_sid_internal(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name) +{ + int ret = -1; + struct listnode *node; + struct zserv *c; + char buf[256]; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: getting SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value ? sid_value : &in6addr_any, locator_name); + + ret = get_srv6_sid(sid, ctx, sid_value, locator_name); + if (ret < 0) { + zlog_warn("%s: not got SRv6 SID for ctx %s, sid_value=%pI6, locator_name=%s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx), + sid_value ? sid_value : &in6addr_any, locator_name); + + /* Notify client about SID alloc failure */ + zsend_srv6_sid_notify(client, ctx, sid_value, 0, 0, NULL, + ZAPI_SRV6_SID_FAIL_ALLOC); + } else if (ret == 0) { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got existing SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notify client", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + + zsend_srv6_sid_notify(client, ctx, &(*sid)->value, (*sid)->func, + (*sid)->wide_func, + (*sid)->locator ? (*sid)->locator->name + : NULL, + ZAPI_SRV6_SID_ALLOCATED); + } else { + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: got new SRv6 SID for ctx %s: sid_value=%pI6 (func=%u) (proto=%u, instance=%u, sessionId=%u), notifying all clients", + __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx), + &(*sid)->value, (*sid)->func, client->proto, + client->instance, client->session_id); + if (!listnode_lookup((*sid)->client_list, client)) + listnode_add((*sid)->client_list, client); + + for (ALL_LIST_ELEMENTS_RO((*sid)->client_list, node, c)) + zsend_srv6_sid_notify(c, ctx, &(*sid)->value, + (*sid)->func, (*sid)->wide_func, + (*sid)->locator + ? (*sid)->locator->name + : NULL, + ZAPI_SRV6_SID_ALLOCATED); + } + + return ret; +} + +/** + * Release SRv6 SIDs from a client. + * + * Called on client disconnection or reconnection. + * + * @param client The client to release SIDs from + * @return Number of SIDs released + */ +int release_daemon_srv6_sids(struct zserv *client) +{ + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; + int count = 0; + int ret; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SIDs for client proto %s, instance %d, session %u", + __func__, zebra_route_string(client->proto), + client->instance, client->session_id); + + /* Iterate over the SIDs and release SIDs used by the client daemon */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!listnode_lookup(ctx->sid->client_list, client)) + continue; + + ret = release_srv6_sid(client, ctx); + if (ret == 0) + count++; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: released %d SRv6 SIDs", __func__, count); + + return count; +} + +/** + * Release SRv6 SIDs from a client. + * + * @param client The client zapi session + * @param ctx Context associated with the SRv6 SID + * @return 0 on success, -1 on failure + */ +static int srv6_manager_release_sid_internal(struct zserv *client, + struct srv6_sid_ctx *ctx) +{ + int ret = -1; + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_ctx *zctx; + struct listnode *node, *nnode; + char buf[256]; + const char *locator_name = NULL; + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: releasing SRv6 SID associated with ctx %s", + __func__, srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + /* Lookup Zebra SID context and release it */ + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, zctx)) + if (memcmp(&zctx->ctx, ctx, sizeof(struct srv6_sid_ctx)) == 0) { + if (zctx->sid && zctx->sid->locator) + locator_name = + (const char *)zctx->sid->locator->name; + ret = release_srv6_sid(client, zctx); + break; + } + + if (IS_ZEBRA_DEBUG_PACKET) + zlog_debug("%s: no SID associated with ctx %s", __func__, + srv6_sid_ctx2str(buf, sizeof(buf), ctx)); + + if (ret == 0) + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, + ZAPI_SRV6_SID_RELEASED); + else + zsend_srv6_sid_notify(client, ctx, NULL, 0, 0, locator_name, + ZAPI_SRV6_SID_FAIL_RELEASE); + + return ret; +} + +void zebra_srv6_terminate(void) +{ + struct srv6_locator *locator; + struct srv6_sid_format *format; + struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *sid_ctx; + + if (srv6.locators) { + while (listcount(srv6.locators)) { + locator = listnode_head(srv6.locators); + + listnode_delete(srv6.locators, locator); + srv6_locator_free(locator); + } + + list_delete(&srv6.locators); + } + + /* Free SRv6 SIDs */ + if (srv6.sids) { + while (listcount(srv6.sids)) { + sid_ctx = listnode_head(srv6.sids); + + listnode_delete(srv6.sids, sid_ctx); + zebra_srv6_sid_ctx_free(sid_ctx); + } + + list_delete(&srv6.sids); + } + + /* Free SRv6 SID blocks */ + if (srv6.sid_blocks) { + while (listcount(srv6.sid_blocks)) { + block = listnode_head(srv6.sid_blocks); + + listnode_delete(srv6.sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + + list_delete(&srv6.sid_blocks); + } + + /* Free SRv6 SID formats */ + if (srv6.sid_formats) { + while (listcount(srv6.sid_formats)) { + format = listnode_head(srv6.sid_formats); + + srv6_sid_format_unregister(format); + srv6_sid_format_free(format); + } + + list_delete(&srv6.sid_formats); + } +} + +void zebra_srv6_init(void) +{ + hook_register(zserv_client_close, zebra_srv6_cleanup); + hook_register(srv6_manager_get_chunk, + zebra_srv6_manager_get_locator_chunk); + hook_register(srv6_manager_release_chunk, + zebra_srv6_manager_release_locator_chunk); + + hook_register(srv6_manager_get_sid, srv6_manager_get_sid_internal); + hook_register(srv6_manager_release_sid, + srv6_manager_release_sid_internal); + hook_register(srv6_manager_get_locator, + srv6_manager_get_srv6_locator_internal); } bool zebra_srv6_is_enable(void) diff --git a/zebra/zebra_srv6.h b/zebra/zebra_srv6.h index 21936c3323..1599fd7adf 100644 --- a/zebra/zebra_srv6.h +++ b/zebra/zebra_srv6.h @@ -16,12 +16,197 @@ #include #include +/* Default config for SRv6 SID `usid-f3216` format */ +#define SRV6_SID_FORMAT_USID_F3216_NAME "usid-f3216" +#define SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN 32 +#define SRV6_SID_FORMAT_USID_F3216_NODE_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_USID_F3216_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_USID_F3216_LIB_START 0xE000 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_START 0xFE00 +#define SRV6_SID_FORMAT_USID_F3216_ELIB_END 0xFEFF +#define SRV6_SID_FORMAT_USID_F3216_WLIB_START 0xFFF0 +#define SRV6_SID_FORMAT_USID_F3216_WLIB_END 0xFFF7 +#define SRV6_SID_FORMAT_USID_F3216_EWLIB_START 0xFFF7 + +/* Default config for SRv6 SID `uncompressed` format */ +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME "uncompressed-f4024" +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN 40 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN 24 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNCTION_LEN 16 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_ARGUMENT_LEN 0 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START 0xFF00 +#define SRV6_SID_FORMAT_UNCOMPRESSED_F4024_FUNC_UNRESERVED_MIN 0x40 + +/* uSID Wide LIB */ +struct wide_lib { + uint32_t func; + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; +}; + +/* + * SRv6 SID block. + * + * A SID block is an IPv6 prefix from which SRv6 SIDs are allocated. + * Example: + * SID block = fc00:0::/32 + * SID 1 = fc00:0:1:e000:: + * SID 2 = fc00:0:1:fe00:: + * ... + */ +struct zebra_srv6_sid_block { + /* Prefix of this block, e.g. fc00:0::/32 */ + struct prefix_ipv6 prefix; + + /* Reference counter */ + unsigned long refcnt; + + /* + * Pointer to the SID format that defines the structure of the SIDs + * allocated from this block + */ + struct srv6_sid_format *sid_format; + + /* + * Run-time information/state of this SID block. + * + * This includes stuff like how many SID functions have been allocated + * from this block, which functions are still available to be allocated + * and so on... + */ + union { + /* Information/state for compressed uSID format */ + struct { + /* uSID Local ID Block (LIB) */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } lib; + + /* uSID Wide LIB */ + struct wide_lib *wide_lib; + } usid; + + /* Information/state for uncompressed SID format */ + struct { + uint32_t num_func_allocated; + uint32_t first_available_func; + struct list *func_allocated; + struct list *func_released; + } uncompressed; + } u; +}; + +/** + * The function part of an SRv6 SID can be allocated in one + * of the following ways: + * - dynamic: allocate any available function + * - explicit: allocate a specific function + */ +enum srv6_sid_alloc_mode { + SRV6_SID_ALLOC_MODE_UNSPEC = 0, + /* Dynamic SID allocation */ + SRV6_SID_ALLOC_MODE_DYNAMIC = 1, + /* Explicit SID allocation */ + SRV6_SID_ALLOC_MODE_EXPLICIT = 2, + SRV6_SID_ALLOC_MODE_MAX = 3, +}; + +/** + * Convert SID allocation mode to string. + * + * @param alloc_mode SID allocation mode + * @return String representing the allocation mode + */ +static inline const char * +srv6_sid_alloc_mode2str(enum srv6_sid_alloc_mode alloc_mode) +{ + switch (alloc_mode) { + case SRV6_SID_ALLOC_MODE_EXPLICIT: + return "explicit"; + case SRV6_SID_ALLOC_MODE_DYNAMIC: + return "dynamic"; + case SRV6_SID_ALLOC_MODE_UNSPEC: + return "unspec"; + case SRV6_SID_ALLOC_MODE_MAX: + default: + return "unknown"; + } +} + +/* SRv6 SID instance. */ +struct zebra_srv6_sid { + /* + * SID context associated with the SID. + * Defines behavior and attributes of the SID. + */ + struct zebra_srv6_sid_ctx *ctx; + + /* SID value (e.g. fc00:0:1:e000::) */ + struct in6_addr value; + + /* Pointer to the SRv6 locator from which the SID has been allocated */ + struct srv6_locator *locator; + + /* Pointer to the SRv6 block from which the SID has been allocated */ + struct zebra_srv6_sid_block *block; + + /* + * Function part of the SID + * Example: + * SID = fc00:0:1:e000:: => func = e000 + */ + uint32_t func; + + /* SID wide function. */ + uint32_t wide_func; + + /* SID allocation mode: dynamic or explicit */ + enum srv6_sid_alloc_mode alloc_mode; + + /* List of clients that are using the SID */ + struct list *client_list; +}; + +/* + * Zebra SRv6 SID context. + * A context defines a behavior and (optionally) some behavior-specific + * attributes. Client daemons (bgp, isis, ...) ask SRv6 Manager to allocate + * a SID for a particular context. SRv6 Manager is responsible for allocating + * a SID from a given SID block and associating with the context. + * + * Example: + * bgp asks to associate a SID to the context {behavior=End.DT46 vrf=Vrf10}. + * SRv6 Manager allocate SID fc00:0:1:e000:: for that context. + */ +struct zebra_srv6_sid_ctx { + /* SRv6 SID context information. */ + struct srv6_sid_ctx ctx; + + /* SID associated with the context. */ + struct zebra_srv6_sid *sid; +}; + /* SRv6 instance structure. */ struct zebra_srv6 { struct list *locators; /* Source address for SRv6 encapsulation */ struct in6_addr encap_src_addr; + + /* SRv6 SID formats */ + struct list *sid_formats; + + /* SRv6 SIDs */ + struct list *sids; + + /* SRv6 SID blocks */ + struct list *sid_blocks; }; /* declare hooks for the basic API, so that it can be specialized or served @@ -46,6 +231,17 @@ DECLARE_HOOK(srv6_manager_release_chunk, vrf_id_t vrf_id), (client, locator_name, vrf_id)); +DECLARE_HOOK(srv6_manager_get_sid, + (struct zebra_srv6_sid **sid, struct zserv *client, + struct srv6_sid_ctx *ctx, struct in6_addr *sid_value, + const char *locator_name), + (sid, client, ctx, sid_value, locator_name)); +DECLARE_HOOK(srv6_manager_release_sid, + (struct zserv *client, struct srv6_sid_ctx *ctx), (client, ctx)); +DECLARE_HOOK(srv6_manager_get_locator, + (struct srv6_locator **locator, struct zserv *client, + const char *locator_name), + (locator, client, locator_name)); extern void zebra_srv6_locator_add(struct srv6_locator *locator); extern void zebra_srv6_locator_delete(struct srv6_locator *locator); @@ -74,4 +270,55 @@ extern int release_daemon_srv6_locator_chunks(struct zserv *client); extern void zebra_srv6_encap_src_addr_set(struct in6_addr *src_addr); extern void zebra_srv6_encap_src_addr_unset(void); +void srv6_sid_format_register(struct srv6_sid_format *format); +void srv6_sid_format_unregister(struct srv6_sid_format *format); +struct srv6_sid_format *srv6_sid_format_lookup(const char *name); +void zebra_srv6_locator_format_set(struct srv6_locator *locator, + struct srv6_sid_format *format); +void zebra_srv6_sid_format_changed_cb(struct srv6_sid_format *format); + +uint32_t *zebra_srv6_sid_func_alloc(uint32_t func); +void zebra_srv6_sid_func_free(uint32_t *func); +void delete_zebra_srv6_sid_func(void *val); + +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_alloc(struct srv6_sid_format *format, + struct prefix_ipv6 *prefix); +extern void zebra_srv6_sid_block_free(struct zebra_srv6_sid_block *block); +extern void delete_zebra_srv6_sid_block(void *val); +extern struct zebra_srv6_sid_block * +zebra_srv6_sid_block_lookup(struct prefix_ipv6 *prefix); + +extern struct zebra_srv6_sid * +zebra_srv6_sid_alloc(struct zebra_srv6_sid_ctx *ctx, struct in6_addr *sid_value, + struct srv6_locator *locator, + struct zebra_srv6_sid_block *sid_block, uint32_t sid_func, + enum srv6_sid_alloc_mode alloc_mode); +extern void zebra_srv6_sid_free(struct zebra_srv6_sid *sid); +extern void delete_zebra_srv6_sid(void *val); + +extern void srv6_manager_get_sid_call(struct zebra_srv6_sid **sid, + struct zserv *client, + struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, + const char *locator_name); +extern void srv6_manager_release_sid_call(struct zserv *client, + struct srv6_sid_ctx *ctx); + +extern void srv6_manager_get_locator_call(struct srv6_locator **locator, + struct zserv *client, + const char *locator_name); + +extern int get_srv6_sid(struct zebra_srv6_sid **sid, struct srv6_sid_ctx *ctx, + struct in6_addr *sid_value, const char *locator_name); +extern int release_srv6_sid(struct zserv *client, + struct zebra_srv6_sid_ctx *zctx); +extern int release_daemon_srv6_sids(struct zserv *client); +extern int srv6_manager_get_sid_response(struct zebra_srv6_sid *sid, + struct zserv *client); + +extern struct zebra_srv6_sid_ctx *zebra_srv6_sid_ctx_alloc(void); +extern void zebra_srv6_sid_ctx_free(struct zebra_srv6_sid_ctx *ctx); +extern void delete_zebra_srv6_sid_ctx(void *val); + #endif /* _ZEBRA_SRV6_H */ diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index d5cd30e64b..c664a9c69f 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -68,6 +68,27 @@ static struct cmd_node srv6_encap_node = { .prompt = "%s(config-srv6-encap)# " }; +static struct cmd_node srv6_sid_formats_node = { + .name = "srv6-formats", + .node = SRV6_SID_FORMATS_NODE, + .parent_node = SRV6_NODE, + .prompt = "%s(config-srv6-formats)# ", +}; + +static struct cmd_node srv6_sid_format_usid_f3216_node = { + .name = "srv6-format-usid-f3216", + .node = SRV6_SID_FORMAT_USID_F3216_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + +static struct cmd_node srv6_sid_format_uncompressed_f4024_node = { + .name = "srv6-format-uncompressed-f4024", + .node = SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + .parent_node = SRV6_SID_FORMATS_NODE, + .prompt = "%s(config-srv6-format)# " +}; + DEFPY (show_srv6_manager, show_srv6_manager_cmd, "show segment-routing srv6 manager [json]", @@ -198,15 +219,32 @@ DEFUN (show_srv6_locator_detail, prefix2str(&locator->prefix, str, sizeof(str)); vty_out(vty, "Name: %s\n", locator->name); vty_out(vty, "Prefix: %s\n", str); - vty_out(vty, "Block-Bit-Len: %u\n", locator->block_bits_length); - vty_out(vty, "Node-Bit-Len: %u\n", locator->node_bits_length); - vty_out(vty, "Function-Bit-Len: %u\n", - locator->function_bits_length); - vty_out(vty, "Argument-Bit-Len: %u\n", - locator->argument_bits_length); + if (locator->sid_format) { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->sid_format->block_len); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->sid_format->node_len); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->sid_format->function_len); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->sid_format->argument_len); + + if (locator->sid_format->type == + SRV6_SID_FORMAT_TYPE_USID) + vty_out(vty, "Behavior: uSID\n"); + } else { + vty_out(vty, "Block-Bit-Len: %u\n", + locator->block_bits_length); + vty_out(vty, "Node-Bit-Len: %u\n", + locator->node_bits_length); + vty_out(vty, "Function-Bit-Len: %u\n", + locator->function_bits_length); + vty_out(vty, "Argument-Bit-Len: %u\n", + locator->argument_bits_length); - if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) - vty_out(vty, "Behavior: uSID\n"); + if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) + vty_out(vty, "Behavior: uSID\n"); + } vty_out(vty, "Chunks:\n"); for (ALL_LIST_ELEMENTS_RO((struct list *)locator->chunks, node, @@ -248,9 +286,30 @@ DEFUN (no_srv6, struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct srv6_locator *locator; struct listnode *node, *nnode; + struct zebra_srv6_sid_block *block; + struct zebra_srv6_sid_ctx *ctx; + + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) { + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } - for (ALL_LIST_ELEMENTS(srv6->locators, node, nnode, locator)) zebra_srv6_locator_delete(locator); + } return CMD_SUCCESS; } @@ -297,12 +356,37 @@ DEFUN (no_srv6_locator, "Segment Routing SRv6 locator\n" "Specify locator-name\n") { + struct zebra_srv6 *srv6 = zebra_srv6_get_default(); + struct zebra_srv6_sid_block *block; + struct listnode *node, *nnode; + struct zebra_srv6_sid_ctx *ctx; struct srv6_locator *locator = zebra_srv6_locator_lookup(argv[2]->arg); if (!locator) { vty_out(vty, "%% Can't find SRv6 locator\n"); return CMD_WARNING_CONFIG_FAILED; } + for (ALL_LIST_ELEMENTS(srv6->sids, node, nnode, ctx)) { + if (!ctx->sid || ctx->sid->locator != locator) + continue; + + if (ctx->sid) + zebra_srv6_sid_free(ctx->sid); + + listnode_delete(srv6->sids, ctx); + zebra_srv6_sid_ctx_free(ctx); + } + + block = locator->sid_block; + if (block) { + block->refcnt--; + if (block->refcnt == 0) { + listnode_delete(srv6->sid_blocks, block); + zebra_srv6_sid_block_free(block); + } + locator->sid_block = NULL; + } + zebra_srv6_locator_delete(locator); return CMD_SUCCESS; } @@ -323,14 +407,37 @@ DEFPY (locator_prefix, VTY_DECLVAR_CONTEXT(srv6_locator, locator); struct srv6_locator_chunk *chunk = NULL; struct listnode *node = NULL; + uint8_t expected_prefixlen; + struct srv6_sid_format *format; locator->prefix = *prefix; func_bit_len = func_bit_len ?: ZEBRA_SRV6_FUNCTION_LENGTH; + expected_prefixlen = prefix->prefixlen; + format = locator->sid_format; + if (format) { + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format->name, + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + } + + if (prefix->prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + prefix->prefixlen, format->name); + return CMD_WARNING_CONFIG_FAILED; + } + /* Resolve optional arguments */ if (block_bit_len == 0 && node_bit_len == 0) { - block_bit_len = - prefix->prefixlen - ZEBRA_SRV6_LOCATOR_NODE_LENGTH; + block_bit_len = prefix->prefixlen - + ZEBRA_SRV6_LOCATOR_NODE_LENGTH; node_bit_len = ZEBRA_SRV6_LOCATOR_NODE_LENGTH; } else if (block_bit_len == 0) { block_bit_len = prefix->prefixlen - node_bit_len; @@ -401,7 +508,8 @@ DEFPY (locator_prefix, } } - zebra_srv6_locator_add(locator); + zebra_srv6_locator_format_set(locator, locator->sid_format); + return CMD_SUCCESS; } @@ -422,8 +530,9 @@ DEFPY (locator_behavior, /* SRv6 locator uSID flag already set, nothing to do */ return CMD_SUCCESS; - /* Remove old locator from zclients */ - zebra_notify_srv6_locator_delete(locator); + if (!locator->sid_format) + /* Remove old locator from zclients */ + zebra_notify_srv6_locator_delete(locator); /* Set/Unset the SRV6_LOCATOR_USID */ if (no) @@ -431,8 +540,75 @@ DEFPY (locator_behavior, else SET_FLAG(locator->flags, SRV6_LOCATOR_USID); - /* Notify the new locator to zclients */ - zebra_notify_srv6_locator_add(locator); + if (!locator->sid_format) + /* Notify the new locator to zclients */ + zebra_srv6_locator_add(locator); + + return CMD_SUCCESS; +} + +DEFPY(locator_sid_format, + locator_sid_format_cmd, + "format $format", + "Configure SRv6 SID format\n" + "Specify usid-f3216 format\n" + "Specify uncompressed-f4024 format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + struct srv6_sid_format *sid_format = NULL; + uint8_t expected_prefixlen; + + expected_prefixlen = locator->prefix.prefixlen; + if (strmatch(format, SRV6_SID_FORMAT_USID_F3216_NAME)) + expected_prefixlen = SRV6_SID_FORMAT_USID_F3216_BLOCK_LEN + + SRV6_SID_FORMAT_USID_F3216_NODE_LEN; + else if (strmatch(format, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + expected_prefixlen = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_BLOCK_LEN + + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE_LEN; + + if (IPV6_ADDR_SAME(&locator->prefix, &in6addr_any)) { + vty_out(vty, + "%% Unexpected configuration sequence: the prefix of the locator is required before configuring the format. Please configure the prefix first and then configure the format.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + if (locator->prefix.prefixlen != expected_prefixlen) { + vty_out(vty, + "%% Locator prefix length '%u' inconsistent with configured format '%s'. Please either use a prefix length that is consistent with the format or change the format.\n", + locator->prefix.prefixlen, format); + return CMD_WARNING_CONFIG_FAILED; + } + + sid_format = srv6_sid_format_lookup(format); + if (!sid_format) { + vty_out(vty, "%% Cannot find SRv6 SID format '%s'\n", format); + return CMD_WARNING_CONFIG_FAILED; + } + + if (sid_format == locator->sid_format) + /* Format has not changed, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, sid_format); + + return CMD_SUCCESS; +} + +DEFPY (no_locator_sid_format, + no_locator_sid_format_cmd, + "no format [WORD]", + NO_STR + "Configure SRv6 SID format\n" + "Specify SRv6 SID format\n") +{ + VTY_DECLVAR_CONTEXT(srv6_locator, locator); + + if (!locator->sid_format) + /* SID format already unset, nothing to do */ + return CMD_SUCCESS; + + zebra_srv6_locator_format_set(locator, NULL); return CMD_SUCCESS; } @@ -469,11 +645,312 @@ DEFPY (no_srv6_src_addr, return CMD_SUCCESS; } +DEFUN_NOSH(srv6_sid_formats, + srv6_sid_formats_cmd, + "formats", + "Segment Routing SRv6 SID formats\n") +{ + vty->node = SRV6_SID_FORMATS_NODE; + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f3216_usid, + srv6_sid_format_f3216_usid_cmd, + "format usid-f3216", + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_USID_F3216_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f3216_usid, + no_srv6_sid_format_f3216_usid_cmd, + "no format usid-f3216", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uSID f3216 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_USID_F3216_NAME); + assert(format); + + format->config.usid.lib_start = SRV6_SID_FORMAT_USID_F3216_LIB_START; + format->config.usid.elib_start = SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = SRV6_SID_FORMAT_USID_F3216_ELIB_END; + format->config.usid.wlib_start = SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = SRV6_SID_FORMAT_USID_F3216_WLIB_END; + format->config.usid.ewlib_start = SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFUN_NOSH (srv6_sid_format_f4024_uncompressed, + srv6_sid_format_uncompressed_cmd, + "format uncompressed-f4024", + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + VTY_PUSH_CONTEXT(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, format); + return CMD_SUCCESS; +} + +DEFUN(no_srv6_sid_format_f4024_uncompressed, + no_srv6_sid_format_f4024_uncompressed_cmd, + "no format uncompressed-f4024", + NO_STR + "Configure SRv6 SID format\n" + "Configure the uncompressed f4024 format\n") +{ + struct srv6_sid_format *format; + + format = srv6_sid_format_lookup(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME); + assert(format); + + format->config.uncompressed.explicit_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib, + srv6_sid_format_usid_lib_cmd, + "local-id-block start (0-4294967295)$start", + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.lib_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib, + no_srv6_sid_format_usid_lib_cmd, + "no local-id-block [start (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the start value for the LIB\n" + "Specify the start value for the LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.lib_start = + SRV6_SID_FORMAT_USID_F3216_LIB_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_lib_explicit, + srv6_sid_format_usid_lib_explicit_cmd, + "local-id-block explicit start (0-4294967295)$start end (0-4294967295)$end", + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.elib_start = start; + format->config.usid.elib_end = end; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_lib_explicit, + no_srv6_sid_format_usid_lib_explicit_cmd, + "no local-id-block explicit [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure LIB\n" + "Configure the Explicit LIB\n" + "Configure the start value for the Explicit LIB\n" + "Specify the start value for the Explicit LIB\n" + "Configure the end value for the Explicit LIB\n" + "Specify the end value for the Explicit LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.elib_start = + SRV6_SID_FORMAT_USID_F3216_ELIB_START; + format->config.usid.elib_end = + SRV6_SID_FORMAT_USID_F3216_ELIB_END; + } else { + assert(0); + } + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wlib, + srv6_sid_format_usid_wlib_cmd, + "wide-local-id-block start (0-4294967295)$start end (0-4294967295)$end", + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.wlib_start = start; + format->config.usid.wlib_end = end; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wlib, + no_srv6_sid_format_usid_wlib_cmd, + "no wide-local-id-block [start (0-4294967295) end (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure the start value for the Wide LIB\n" + "Specify the start value for the Wide LIB\n" + "Configure the end value for the Wide LIB\n" + "Specify the end value for the Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) { + format->config.usid.wlib_start = + SRV6_SID_FORMAT_USID_F3216_WLIB_START; + format->config.usid.wlib_end = + SRV6_SID_FORMAT_USID_F3216_WLIB_END; + } else { + assert(0); + } + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_usid_wide_lib_explicit, + srv6_sid_format_usid_wide_lib_explicit_cmd, + "wide-local-id-block explicit start (0-4294967295)$start", + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.usid.ewlib_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_usid_wide_lib_explicit, + no_srv6_sid_format_usid_wide_lib_explicit_cmd, + "no wide-local-id-block explicit [start (0-4294967295)]", + NO_STR + "Configure Wide LIB\n" + "Configure Explicit Wide LIB\n" + "Configure the start value for the Explicit Wide LIB\n" + "Specify the start value for the Explicit Wide LIB\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_USID_F3216_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_USID_F3216_EWLIB_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(srv6_sid_format_explicit, + srv6_sid_format_explicit_cmd, + "explicit start (0-4294967295)$start", + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + format->config.uncompressed.explicit_start = start; + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + +DEFPY(no_srv6_sid_format_explicit, + no_srv6_sid_format_explicit_cmd, + "no explicit [start (0-4294967295)$start]", + NO_STR + "Configure Explicit range\n" + "Configure the start value for the Explicit range\n" + "Specify the start value for the Explicit range\n") +{ + VTY_DECLVAR_CONTEXT(srv6_sid_format, format); + + if (strmatch(format->name, SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NAME)) + format->config.usid.ewlib_start = + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START; + else + assert(0); + + /* Notify zclients that the format has changed */ + zebra_srv6_sid_format_changed_cb(format); + + return CMD_SUCCESS; +} + static int zebra_sr_config(struct vty *vty) { struct zebra_srv6 *srv6 = zebra_srv6_get_default(); struct listnode *node; struct srv6_locator *locator; + struct srv6_sid_format *format; char str[256]; bool display_source_srv6 = false; @@ -515,6 +992,54 @@ static int zebra_sr_config(struct vty *vty) vty_out(vty, "\n"); if (CHECK_FLAG(locator->flags, SRV6_LOCATOR_USID)) vty_out(vty, " behavior usid\n"); + if (locator->sid_format) { + format = locator->sid_format; + vty_out(vty, " format %s\n", format->name); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); + } + vty_out(vty, " exit\n"); + vty_out(vty, " !\n"); + vty_out(vty, " formats\n"); + for (ALL_LIST_ELEMENTS_RO(srv6->sid_formats, node, format)) { + if (format->type == SRV6_SID_FORMAT_TYPE_UNCOMPRESSED) { + vty_out(vty, " format %s\n", format->name); + if (format->config.uncompressed.explicit_start != + SRV6_SID_FORMAT_UNCOMPRESSED_F4024_EXPLICIT_RANGE_START) + vty_out(vty, " explicit start %u\n", + format->config.uncompressed + .explicit_start); + } + if (format->type == SRV6_SID_FORMAT_TYPE_USID) { + vty_out(vty, " format %s\n", format->name); + if (format->config.usid.lib_start != + SRV6_SID_FORMAT_USID_F3216_LIB_START) + vty_out(vty, + " local-id-block start %u\n", + format->config.usid.lib_start); + if (format->config.usid.elib_start != + SRV6_SID_FORMAT_USID_F3216_ELIB_START || + format->config.usid.elib_end != + SRV6_SID_FORMAT_USID_F3216_ELIB_END) + vty_out(vty, + " local-id-block explicit start %u end %u\n", + format->config.usid.elib_start, + format->config.usid.elib_end); + if (format->config.usid.wlib_start != + SRV6_SID_FORMAT_USID_F3216_WLIB_START || + format->config.usid.wlib_end != + SRV6_SID_FORMAT_USID_F3216_WLIB_END) + vty_out(vty, + " wide-local-id-block start %u end %u\n", + format->config.usid.wlib_start, + format->config.usid.wlib_end); + if (format->config.usid.ewlib_start != + SRV6_SID_FORMAT_USID_F3216_EWLIB_START) + vty_out(vty, + " wide-local-id-block explicit start %u\n", + format->config.usid.ewlib_start); + } vty_out(vty, " exit\n"); vty_out(vty, " !\n"); } @@ -538,11 +1063,17 @@ void zebra_srv6_vty_init(void) install_node(&srv6_locs_node); install_node(&srv6_loc_node); install_node(&srv6_encap_node); + install_node(&srv6_sid_formats_node); + install_node(&srv6_sid_format_usid_f3216_node); + install_node(&srv6_sid_format_uncompressed_f4024_node); install_default(SEGMENT_ROUTING_NODE); install_default(SRV6_NODE); install_default(SRV6_LOCS_NODE); install_default(SRV6_LOC_NODE); install_default(SRV6_ENCAP_NODE); + install_default(SRV6_SID_FORMATS_NODE); + install_default(SRV6_SID_FORMAT_USID_F3216_NODE); + install_default(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE); /* Command for change node */ install_element(CONFIG_NODE, &segment_routing_cmd); @@ -550,14 +1081,44 @@ void zebra_srv6_vty_init(void) install_element(SEGMENT_ROUTING_NODE, &no_srv6_cmd); install_element(SRV6_NODE, &srv6_locators_cmd); install_element(SRV6_NODE, &srv6_encap_cmd); + install_element(SRV6_NODE, &srv6_sid_formats_cmd); install_element(SRV6_LOCS_NODE, &srv6_locator_cmd); install_element(SRV6_LOCS_NODE, &no_srv6_locator_cmd); + install_element(SRV6_SID_FORMATS_NODE, &srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &srv6_sid_format_uncompressed_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f3216_usid_cmd); + install_element(SRV6_SID_FORMATS_NODE, + &no_srv6_sid_format_f4024_uncompressed_cmd); /* Command for configuration */ install_element(SRV6_LOC_NODE, &locator_prefix_cmd); install_element(SRV6_LOC_NODE, &locator_behavior_cmd); + install_element(SRV6_LOC_NODE, &locator_sid_format_cmd); + install_element(SRV6_LOC_NODE, &no_locator_sid_format_cmd); install_element(SRV6_ENCAP_NODE, &srv6_src_addr_cmd); install_element(SRV6_ENCAP_NODE, &no_srv6_src_addr_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wlib_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_USID_F3216_NODE, + &no_srv6_sid_format_usid_wide_lib_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &srv6_sid_format_explicit_cmd); + install_element(SRV6_SID_FORMAT_UNCOMPRESSED_F4024_NODE, + &no_srv6_sid_format_explicit_cmd); /* Command for operation */ install_element(VIEW_NODE, &show_srv6_locator_cmd); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index ae82d20141..5742c38e23 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -3825,6 +3825,20 @@ DEFUN (show_zebra, struct vrf *vrf; struct ttable *table = ttable_new(&ttable_styles[TTSTYLE_BLANK]); char *out; + char timebuf[MONOTIME_STRLEN]; + + time_to_string(zrouter.startup_time, timebuf); + vty_out(vty, "Zebra started%s at time %s", + zrouter.graceful_restart ? " gracefully" : "", timebuf); + + if (zrouter.t_rib_sweep) + vty_out(vty, + "Zebra RIB sweep timer running, remaining time %lds\n", + event_timer_remain_second(zrouter.t_rib_sweep)); + else { + time_to_string(zrouter.rib_sweep_time, timebuf); + vty_out(vty, "Zebra RIB sweep happened at %s", timebuf); + } ttable_rowseps(table, 0, BOTTOM, true, '-'); ttable_add_row(table, "OS|%s(%s)", cmd_system_get(), cmd_release_get()); diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index b8c11e186a..f1ae42e320 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -1356,6 +1356,18 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, { struct zebra_mac *zrmac = NULL; struct ipaddr *vtep = NULL; + struct ipaddr ipv4_vtep; + + /* vtep_ip may be v4 or v6-mapped-v4. But zrmac->fwd_info + * can only contain v4 version. So convert if needed + */ + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep_ip->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4); zrmac = zl3vni_rmac_lookup(zl3vni, rmac); if (!zrmac) { @@ -1369,7 +1381,7 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, return -1; } memset(&zrmac->fwd_info, 0, sizeof(zrmac->fwd_info)); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1383,14 +1395,14 @@ static int zl3vni_remote_rmac_add(struct zebra_l3vni *zl3vni, /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); } else if (!IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &vtep_ip->ipaddr_v4)) { + &(ipv4_vtep.ipaddr_v4))) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "L3VNI %u Remote VTEP change(%pI4 -> %pIA) for RMAC %pEA", zl3vni->vni, &zrmac->fwd_info.r_vtep_ip, vtep_ip, rmac); - zrmac->fwd_info.r_vtep_ip = vtep_ip->ipaddr_v4; + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; vtep = XCALLOC(MTYPE_EVPN_VTEP, sizeof(struct ipaddr)); memcpy(vtep, vtep_ip, sizeof(struct ipaddr)); @@ -1410,36 +1422,29 @@ static void zl3vni_remote_rmac_del(struct zebra_l3vni *zl3vni, struct zebra_mac *zrmac, struct ipaddr *vtep_ip) { - struct ipaddr ipv4_vtep; - if (!zl3vni_nh_lookup(zl3vni, vtep_ip)) { - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &ipv4_vtep.ipaddr_v4); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - /* remove nh from rmac's list */ - l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, &ipv4_vtep); - /* delete nh is same as current selected, fall back to - * one present in the list - */ - if (IPV4_ADDR_SAME(&zrmac->fwd_info.r_vtep_ip, - &ipv4_vtep.ipaddr_v4) && - listcount(zrmac->nh_list)) { + l3vni_rmac_nh_list_nh_delete(zl3vni, zrmac, vtep_ip); + /* If there are remaining entries, use IPv4 from one */ + if (listcount(zrmac->nh_list)) { struct ipaddr *vtep; + struct ipaddr ipv4_vtep; vtep = listgetdata(listhead(zrmac->nh_list)); - zrmac->fwd_info.r_vtep_ip = vtep->ipaddr_v4; + memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); + ipv4_vtep.ipa_type = IPADDR_V4; + if (vtep->ipa_type == IPADDR_V6) + ipv4_mapped_ipv6_to_ipv4(&vtep->ipaddr_v6, + &(ipv4_vtep.ipaddr_v4)); + else + IPV4_ADDR_COPY(&(ipv4_vtep.ipaddr_v4), + &vtep->ipaddr_v4); + zrmac->fwd_info.r_vtep_ip = ipv4_vtep.ipaddr_v4; if (IS_ZEBRA_DEBUG_VXLAN) - zlog_debug( - "L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", - zl3vni->vni, &ipv4_vtep, - &zrmac->fwd_info.r_vtep_ip, - &zrmac->macaddr); + zlog_debug("L3VNI %u Remote VTEP nh change(%pIA -> %pI4) for RMAC %pEA", + zl3vni->vni, vtep_ip, + &zrmac->fwd_info.r_vtep_ip, + &zrmac->macaddr); /* install rmac in kernel */ zl3vni_rmac_install(zl3vni, zrmac); @@ -2531,7 +2536,6 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, const struct prefix *host_prefix) { struct zebra_l3vni *zl3vni = NULL; - struct ipaddr ipv4_vtep; zl3vni = zl3vni_from_vrf(vrf_id); if (!zl3vni || !is_l3vni_oper_up(zl3vni)) @@ -2547,24 +2551,10 @@ void zebra_vxlan_evpn_vrf_route_add(vrf_id_t vrf_id, const struct ethaddr *rmac, svd_remote_nh_add(zl3vni, vtep_ip, rmac, host_prefix); /* - * if the remote vtep is a ipv4 mapped ipv6 address convert it to ipv4 - * address. Rmac is programmed against the ipv4 vtep because we only - * support ipv4 tunnels in the h/w right now - */ - memset(&ipv4_vtep, 0, sizeof(ipv4_vtep)); - ipv4_vtep.ipa_type = IPADDR_V4; - if (vtep_ip->ipa_type == IPADDR_V6) - ipv4_mapped_ipv6_to_ipv4(&vtep_ip->ipaddr_v6, - &(ipv4_vtep.ipaddr_v4)); - else - memcpy(&(ipv4_vtep.ipaddr_v4), &vtep_ip->ipaddr_v4, - sizeof(struct in_addr)); - - /* - * add the rmac - remote rmac to be installed is against the ipv4 + * add the rmac - remote rmac to be installed is against the * nexthop address */ - zl3vni_remote_rmac_add(zl3vni, rmac, &ipv4_vtep); + zl3vni_remote_rmac_add(zl3vni, rmac, vtep_ip); } /* handle evpn vrf route delete */ diff --git a/zebra/zebra_vxlan_if.c b/zebra/zebra_vxlan_if.c index f4b859b861..17ab05c1f3 100644 --- a/zebra/zebra_vxlan_if.c +++ b/zebra/zebra_vxlan_if.c @@ -208,13 +208,13 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); return 0; } - if ((chgflags & ZEBRA_VXLIF_MASTER_MAC_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_MAC_CHANGE) && if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zebra_vxlan_process_l3vni_oper_up(zl3vni); @@ -224,7 +224,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, /* access-vlan change - process oper down, associate with new * svi_if and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->svi_if = NULL; @@ -242,7 +242,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * local-ip change - process oper down, associate with new * local-ip and then process oper up again */ - if (chgflags & ZEBRA_VXLIF_LOCAL_IP_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_LOCAL_IP_CHANGE)) { if (if_is_operative(ifp)) { zebra_vxlan_process_l3vni_oper_down(zl3vni); zl3vni->local_vtep_ip = vxl->vtep_ip; @@ -262,7 +262,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, zl3vni_bridge_if_set(zl3vni, br_if, true /* set */); /* if we have a valid new master, process l3-vni oper up */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) { if (if_is_operative(ifp) && is_l3vni_oper_up(zl3vni)) zebra_vxlan_process_l3vni_oper_up(zl3vni); } @@ -285,7 +285,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, chgflags); /* Removed from bridge? Cleanup and return */ - if ((chgflags & ZEBRA_VXLIF_MASTER_CHANGE) && + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE) && (zif->brslave_info.bridge_ifindex == IFINDEX_INTERNAL)) { /* Delete from client, remove all remote VTEPs */ /* Also, free up all MACs and neighbors. */ @@ -298,7 +298,7 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, } /* Handle other changes. */ - if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { /* Remove all existing local neigh and MACs for this VNI * (including from BGP) */ @@ -341,9 +341,10 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, return 0; /* Inform BGP, if there is a change of interest. */ - if (chgflags & - (ZEBRA_VXLIF_MASTER_CHANGE | ZEBRA_VXLIF_LOCAL_IP_CHANGE | - ZEBRA_VXLIF_MCAST_GRP_CHANGE | ZEBRA_VXLIF_VLAN_CHANGE)) + if (CHECK_FLAG(chgflags, (ZEBRA_VXLIF_MASTER_CHANGE | + ZEBRA_VXLIF_LOCAL_IP_CHANGE | + ZEBRA_VXLIF_MCAST_GRP_CHANGE | + ZEBRA_VXLIF_VLAN_CHANGE))) zebra_evpn_send_add_to_client(zevpn); /* If there is a valid new master or a VLAN mapping change, @@ -351,9 +352,9 @@ static int zebra_vxlan_if_update_vni(struct interface *ifp, * Also, reinstall any remote MACs and neighbors * for this VNI (based on new VLAN). */ - if (chgflags & ZEBRA_VXLIF_MASTER_CHANGE) + if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_MASTER_CHANGE)) zebra_evpn_read_mac_neigh(zevpn, ifp); - else if (chgflags & ZEBRA_VXLIF_VLAN_CHANGE) { + else if (CHECK_FLAG(chgflags, ZEBRA_VXLIF_VLAN_CHANGE)) { struct neigh_walk_ctx n_wctx; zebra_evpn_read_mac_neigh(zevpn, ifp); diff --git a/zebra/zserv.c b/zebra/zserv.c index 27668534ee..a731f7f278 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1031,6 +1031,7 @@ static char *zserv_time_buf(time_t *time1, char *buf, int buflen) /* Display client info details */ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) { + struct client_gr_info *info; char cbuf[ZEBRA_TIME_BUF], rbuf[ZEBRA_TIME_BUF]; char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; time_t connect_time, last_read_time, last_write_time; @@ -1125,6 +1126,45 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) vty_out(vty, "ES-EVI %-12u%-12u%-12u\n", client->local_es_evi_add_cnt, 0, client->local_es_evi_del_cnt); vty_out(vty, "Errors: %u\n", client->error_cnt); + + TAILQ_FOREACH (info, &client->gr_info_queue, gr_info) { + afi_t afi; + bool route_sync_done = true; + char timebuf[MONOTIME_STRLEN]; + + vty_out(vty, "VRF : %s\n", vrf_id_to_name(info->vrf_id)); + vty_out(vty, "Capabilities : "); + switch (info->capabilities) { + case ZEBRA_CLIENT_GR_CAPABILITIES: + vty_out(vty, "Graceful Restart\n"); + break; + case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: + case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: + case ZEBRA_CLIENT_GR_DISABLE: + case ZEBRA_CLIENT_RIB_STALE_TIME: + vty_out(vty, "None\n"); + break; + } + for (afi = AFI_IP; afi < AFI_MAX; afi++) { + if (info->af_enabled[afi]) { + if (info->route_sync[afi]) + vty_out(vty, + "AFI %d enabled, route sync DONE\n", + afi); + else { + vty_out(vty, + "AFI %d enabled, route sync NOT DONE\n", + afi); + route_sync_done = false; + } + } + } + if (route_sync_done) { + time_to_string(info->route_sync_done_time, timebuf); + vty_out(vty, "Route sync finished at %s", timebuf); + } + } + vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n", client->ibuf_fifo->count, client->ibuf_fifo->max_count, client->obuf_fifo->count, client->obuf_fifo->max_count); diff --git a/zebra/zserv.h b/zebra/zserv.h index 57d673060f..87d2b4adbf 100644 --- a/zebra/zserv.h +++ b/zebra/zserv.h @@ -64,6 +64,8 @@ struct client_gr_info { /* Book keeping */ void *stale_client_ptr; struct event *t_stale_removal; + void *client_ptr; + time_t route_sync_done_time; TAILQ_ENTRY(client_gr_info) gr_info; };