diff options
1080 files changed, 31952 insertions, 18864 deletions
diff --git a/.clang-format b/.clang-format index e1897bfa99..c84a29f861 100644 --- a/.clang-format +++ b/.clang-format @@ -15,7 +15,7 @@ AllowAllParametersOfDeclarationOnNextLine: false AlignAfterOpenBracket: true SpaceAfterCStyleCast: false MaxEmptyLinesToKeep: 2 -BreakBeforeBinaryOperators: NonAssignment +BreakBeforeBinaryOperators: None BreakStringLiterals: false SortIncludes: false IncludeCategories: diff --git a/babeld/babel_interface.c b/babeld/babel_interface.c index 615ed9fee3..e725fbffe9 100644 --- a/babeld/babel_interface.c +++ b/babeld/babel_interface.c @@ -484,7 +484,8 @@ DEFUN (babel_set_rtt_min, babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); - babel_ifp->rtt_min = rtt; + /* The value is entered in milliseconds but stored as microseconds. */ + babel_ifp->rtt_min = rtt * 1000; return CMD_SUCCESS; } @@ -504,7 +505,8 @@ DEFUN (babel_set_rtt_max, babel_ifp = babel_get_if_nfo(ifp); assert (babel_ifp != NULL); - babel_ifp->rtt_max = rtt; + /* The value is entered in milliseconds but stored as microseconds. */ + babel_ifp->rtt_max = rtt * 1000; return CMD_SUCCESS; } @@ -1328,8 +1330,29 @@ interface_config_write (struct vty *vty) babel_ifp->update_interval); write++; } - /* Some parameters have different defaults for wired/wireless. */ - if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) { + if (CHECK_FLAG(babel_ifp->flags, BABEL_IF_TIMESTAMPS)) { + vty_out(vty, " babel enable-timestamps\n"); + write++; + } + if (babel_ifp->max_rtt_penalty != BABEL_DEFAULT_MAX_RTT_PENALTY) { + vty_out(vty, " babel max-rtt-penalty %u\n", + babel_ifp->max_rtt_penalty); + write++; + } + if (babel_ifp->rtt_decay != BABEL_DEFAULT_RTT_DECAY) { + vty_out(vty, " babel rtt-decay %u\n", babel_ifp->rtt_decay); + write++; + } + if (babel_ifp->rtt_min != BABEL_DEFAULT_RTT_MIN) { + vty_out(vty, " babel rtt-min %u\n", babel_ifp->rtt_min / 1000); + write++; + } + if (babel_ifp->rtt_max != BABEL_DEFAULT_RTT_MAX) { + vty_out(vty, " babel rtt-max %u\n", babel_ifp->rtt_max / 1000); + write++; + } + /* Some parameters have different defaults for wired/wireless. */ + if (CHECK_FLAG (babel_ifp->flags, BABEL_IF_WIRED)) { if (!CHECK_FLAG (babel_ifp->flags, BABEL_IF_SPLIT_HORIZON)) { vty_out (vty, " no babel split-horizon\n"); write++; @@ -1395,9 +1418,10 @@ babel_interface_allocate (void) babel_ifp->bucket_time = babel_now.tv_sec; babel_ifp->bucket = BUCKET_TOKENS_MAX; babel_ifp->hello_seqno = (frr_weak_random() & 0xFFFF); - babel_ifp->rtt_min = 10000; - babel_ifp->rtt_max = 120000; - babel_ifp->max_rtt_penalty = 150; + babel_ifp->rtt_decay = BABEL_DEFAULT_RTT_DECAY; + babel_ifp->rtt_min = BABEL_DEFAULT_RTT_MIN; + babel_ifp->rtt_max = BABEL_DEFAULT_RTT_MAX; + babel_ifp->max_rtt_penalty = BABEL_DEFAULT_MAX_RTT_PENALTY; babel_ifp->hello_interval = BABEL_DEFAULT_HELLO_INTERVAL; babel_ifp->update_interval = BABEL_DEFAULT_UPDATE_INTERVAL; babel_ifp->channel = BABEL_IF_CHANNEL_INTERFERING; diff --git a/babeld/babel_main.c b/babeld/babel_main.c index 61a800eef4..b29374fee3 100644 --- a/babeld/babel_main.c +++ b/babeld/babel_main.c @@ -115,7 +115,7 @@ babel_sigusr1 (void) zlog_rotate (); } -static struct quagga_signal_t babel_signals[] = +static struct frr_signal_t babel_signals[] = { { .signal = SIGUSR1, diff --git a/babeld/babel_zebra.c b/babeld/babel_zebra.c index d10d418572..d0da93e507 100644 --- a/babeld/babel_zebra.c +++ b/babeld/babel_zebra.c @@ -234,16 +234,20 @@ babel_zebra_connected (struct zclient *zclient) zclient_send_reg_requests (zclient, VRF_DEFAULT); } +static zclient_handler *const babel_handlers[] = { + [ZEBRA_INTERFACE_ADDRESS_ADD] = babel_interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = babel_interface_address_delete, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = babel_zebra_read_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = babel_zebra_read_route, +}; + void babelz_zebra_init(void) { - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, babel_handlers, + array_size(babel_handlers)); zclient_init(zclient, ZEBRA_ROUTE_BABEL, 0, &babeld_privs); zclient->zebra_connected = babel_zebra_connected; - zclient->interface_address_add = babel_interface_address_add; - zclient->interface_address_delete = babel_interface_address_delete; - zclient->redistribute_route_add = babel_zebra_read_route; - zclient->redistribute_route_del = babel_zebra_read_route; install_element(BABEL_NODE, &babel_redistribute_type_cmd); install_element(ENABLE_NODE, &debug_babel_cmd); diff --git a/babeld/babeld.c b/babeld/babeld.c index f61eac000f..0104620cd5 100644 --- a/babeld/babeld.c +++ b/babeld/babeld.c @@ -716,7 +716,7 @@ DEFUN (babel_set_smoothing_half_life, DEFUN (babel_distribute_list, babel_distribute_list_cmd, - "distribute-list [prefix] WORD <in|out> [WORD]", + "distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", "Filter networks in routing updates\n" "Specify a prefix\n" "Access-list name\n" @@ -736,7 +736,7 @@ DEFUN (babel_distribute_list, DEFUN (babel_no_distribute_list, babel_no_distribute_list_cmd, - "no distribute-list [prefix] WORD <in|out> [WORD]", + "no distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", NO_STR "Filter networks in routing updates\n" "Specify a prefix\n" @@ -758,7 +758,7 @@ DEFUN (babel_no_distribute_list, DEFUN (babel_ipv6_distribute_list, babel_ipv6_distribute_list_cmd, - "ipv6 distribute-list [prefix] WORD <in|out> [WORD]", + "ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", "IPv6\n" "Filter networks in routing updates\n" "Specify a prefix\n" @@ -779,7 +779,7 @@ DEFUN (babel_ipv6_distribute_list, DEFUN (babel_no_ipv6_distribute_list, babel_no_ipv6_distribute_list_cmd, - "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]", + "no ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", NO_STR "IPv6\n" "Filter networks in routing updates\n" diff --git a/babeld/babeld.h b/babeld/babeld.h index 4487aae99f..38859f54da 100644 --- a/babeld/babeld.h +++ b/babeld/babeld.h @@ -81,6 +81,11 @@ THE SOFTWARE. #define BABEL_DEFAULT_HELLO_INTERVAL 4000 #define BABEL_DEFAULT_UPDATE_INTERVAL 16000 #define BABEL_DEFAULT_RESEND_DELAY 2000 +#define BABEL_DEFAULT_RTT_DECAY 42 + +/* Values in microseconds */ +#define BABEL_DEFAULT_RTT_MIN 10000 +#define BABEL_DEFAULT_RTT_MAX 120000 /* In units of seconds */ #define BABEL_DEFAULT_SMOOTHING_HALF_LIFE 4 @@ -90,6 +95,7 @@ THE SOFTWARE. #define BABEL_DEFAULT_RXCOST_WIRED 96 #define BABEL_DEFAULT_RXCOST_WIRELESS 256 +#define BABEL_DEFAULT_MAX_RTT_PENALTY 150 /* Babel structure. */ struct babel diff --git a/babeld/route.c b/babeld/route.c index dfd0bfab89..8dd1e40431 100644 --- a/babeld/route.c +++ b/babeld/route.c @@ -166,7 +166,7 @@ resize_route_table(int new_slots) static struct babel_route * insert_route(struct babel_route *route) { - int i, n; + int i, n = 0; assert(!route->installed); diff --git a/babeld/subdir.am b/babeld/subdir.am index c9b6959fca..856cbd13e3 100644 --- a/babeld/subdir.am +++ b/babeld/subdir.am @@ -3,7 +3,6 @@ # if BABELD -noinst_LIBRARIES += babeld/libbabel.a sbin_PROGRAMS += babeld/babeld vtysh_scan += \ babeld/babel_interface.c \ @@ -13,10 +12,11 @@ vtysh_scan += \ vtysh_daemons += babeld endif -babeld_libbabel_a_SOURCES = \ +babeld_babeld_SOURCES = \ babeld/babel_errors.c \ babeld/babel_filter.c \ babeld/babel_interface.c \ + babeld/babel_main.c \ babeld/babel_zebra.c \ babeld/babeld.c \ babeld/kernel.c \ @@ -48,5 +48,4 @@ noinst_HEADERS += \ babeld/xroute.h \ # end -babeld_babeld_SOURCES = babeld/babel_main.c -babeld_babeld_LDADD = babeld/libbabel.a lib/libfrr.la $(LIBCAP) +babeld_babeld_LDADD = lib/libfrr.la $(LIBCAP) diff --git a/bfdd/bfd.c b/bfdd/bfd.c index c66fccb853..f4135fec14 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -315,45 +315,28 @@ int bfd_session_enable(struct bfd_session *bs) vrf = vrf_lookup_by_name(bs->key.vrfname); if (vrf == NULL) { zlog_err( - "session-enable: specified VRF doesn't exists."); + "session-enable: specified VRF %s doesn't exists.", + bs->key.vrfname); return 0; } + } else { + vrf = vrf_lookup_by_id(VRF_DEFAULT); } - if (!vrf_is_backend_netns() && vrf && vrf->vrf_id != VRF_DEFAULT - && !if_lookup_by_name(vrf->name, vrf->vrf_id)) { - zlog_err("session-enable: vrf interface %s not available yet", - vrf->name); - return 0; - } + assert(vrf); if (bs->key.ifname[0]) { - if (vrf) - ifp = if_lookup_by_name(bs->key.ifname, vrf->vrf_id); - else - ifp = if_lookup_by_name_all_vrf(bs->key.ifname); + ifp = if_lookup_by_name(bs->key.ifname, vrf->vrf_id); if (ifp == NULL) { zlog_err( "session-enable: specified interface %s (VRF %s) doesn't exist.", - bs->key.ifname, vrf ? vrf->name : "<all>"); + bs->key.ifname, vrf->name); return 0; } - if (bs->key.ifname[0] && !vrf) { - vrf = vrf_lookup_by_id(ifp->vrf_id); - if (vrf == NULL) { - zlog_err( - "session-enable: specified VRF %u doesn't exist.", - ifp->vrf_id); - return 0; - } - } } /* Assign interface/VRF pointers. */ bs->vrf = vrf; - if (bs->vrf == NULL) - bs->vrf = vrf_lookup_by_id(VRF_DEFAULT); - assert(bs->vrf); /* Assign interface pointer (if any). */ bs->ifp = ifp; @@ -607,10 +590,10 @@ static struct bfd_session *bfd_find_disc(struct sockaddr_any *sa, struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, struct sockaddr_any *peer, struct sockaddr_any *local, - ifindex_t ifindex, vrf_id_t vrfid, + struct interface *ifp, + vrf_id_t vrfid, bool is_mhop) { - struct interface *ifp; struct vrf *vrf; struct bfd_key key; @@ -618,21 +601,8 @@ struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, if (cp->discrs.remote_discr) return bfd_find_disc(peer, ntohl(cp->discrs.remote_discr)); - /* - * Search for session without using discriminator. - * - * XXX: we can't trust `vrfid` because the VRF handling is not - * properly implemented. Meanwhile we should use the interface - * VRF to find out which one it belongs. - */ - ifp = if_lookup_by_index_all_vrf(ifindex); - if (ifp == NULL) { - if (vrfid != VRF_DEFAULT) - vrf = vrf_lookup_by_id(vrfid); - else - vrf = NULL; - } else - vrf = vrf_lookup_by_id(ifp->vrf_id); + /* Search for session without using discriminator. */ + vrf = vrf_lookup_by_id(vrfid); gen_bfd_key(&key, peer, local, is_mhop, ifp ? ifp->name : NULL, vrf ? vrf->name : VRF_DEFAULT_NAME); @@ -669,14 +639,6 @@ int bfd_recvtimer_cb(struct thread *t) case PTM_BFD_INIT: case PTM_BFD_UP: ptm_bfd_sess_dn(bs, BD_CONTROL_EXPIRED); - bfd_recvtimer_update(bs); - break; - - default: - /* Second detect time expiration, zero remote discr (section - * 6.5.1) - */ - bs->discrs.remote_discr = 0; break; } @@ -1256,27 +1218,6 @@ void bs_final_handler(struct bfd_session *bs) /* Apply new transmission timer immediately. */ ptm_bfd_start_xmt_timer(bs, false); - /* - * Detection timeout calculation: - * The minimum detection timeout is the remote detection - * multipler (number of packets to be missed) times the agreed - * transmission interval. - * - * RFC 5880, Section 6.8.4. - * - * TODO: support sending/counting more packets inside detection - * timeout. - */ - if (bs->timers.required_min_rx > bs->remote_timers.desired_min_tx) - bs->detect_TO = bs->remote_detect_mult - * bs->timers.required_min_rx; - else - bs->detect_TO = bs->remote_detect_mult - * bs->remote_timers.desired_min_tx; - - /* Apply new receive timer immediately. */ - bfd_recvtimer_update(bs); - /* Notify watchers about changed timers. */ control_notify_config(BCM_NOTIFY_CONFIG_UPDATE, bs); } diff --git a/bfdd/bfd.h b/bfdd/bfd.h index 7d5b7887c7..dfe1a20303 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -600,7 +600,8 @@ void ptm_bfd_start_xmt_timer(struct bfd_session *bfd, bool is_echo); struct bfd_session *ptm_bfd_sess_find(struct bfd_pkt *cp, struct sockaddr_any *peer, struct sockaddr_any *local, - ifindex_t ifindex, vrf_id_t vrfid, + struct interface *ifp, + vrf_id_t vrfid, bool is_mhop); struct bfd_session *bs_peer_find(struct bfd_peer_cfg *bpc); diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 3d6ca6ddd3..652b914118 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -546,8 +546,6 @@ int bfd_recv_cb(struct thread *t) struct interface *ifp = NULL; struct bfd_vrf_global *bvrf = THREAD_ARG(t); - vrfid = bvrf->vrf->vrf_id; - /* Schedule next read. */ bfd_sd_reschedule(bvrf, sd); @@ -573,13 +571,19 @@ int bfd_recv_cb(struct thread *t) &local, &peer); } - /* update vrf-id because when in vrf-lite mode, - * the socket is on default namespace + /* + * With netns backend, we have a separate socket in each VRF. It means + * that bvrf here is correct and we believe the bvrf->vrf->vrf_id. + * With VRF-lite backend, we have a single socket in the default VRF. + * It means that we can't believe the bvrf->vrf->vrf_id. But in + * VRF-lite, the ifindex is globally unique, so we can retrieve the + * correct vrf_id from the interface. */ + vrfid = bvrf->vrf->vrf_id; if (ifindex) { ifp = if_lookup_by_index(ifindex, vrfid); if (ifp) - vrfid = ifp->vrf_id; + vrfid = ifp->vrf->vrf_id; } /* Implement RFC 5880 6.8.6 */ @@ -628,7 +632,7 @@ int bfd_recv_cb(struct thread *t) } /* Find the session that this packet belongs. */ - bfd = ptm_bfd_sess_find(cp, &peer, &local, ifindex, vrfid, is_mhop); + bfd = ptm_bfd_sess_find(cp, &peer, &local, ifp, vrfid, is_mhop); if (bfd == NULL) { cp_debug(is_mhop, &peer, &local, ifindex, vrfid, "no session found"); @@ -657,7 +661,7 @@ int bfd_recv_cb(struct thread *t) * packet came in. */ if (!is_mhop && bfd->ifp == NULL) - bfd->ifp = if_lookup_by_index(ifindex, vrfid); + bfd->ifp = ifp; /* Log remote discriminator changes. */ if ((bfd->discrs.remote_discr != 0) @@ -693,11 +697,26 @@ int bfd_recv_cb(struct thread *t) /* Handle poll finalization. */ bs_final_handler(bfd); - } else { - /* Received a packet, lets update the receive timer. */ - bfd_recvtimer_update(bfd); } + /* + * Detection timeout calculation: + * The minimum detection timeout is the remote detection + * multipler (number of packets to be missed) times the agreed + * transmission interval. + * + * RFC 5880, Section 6.8.4. + */ + if (bfd->cur_timers.required_min_rx > bfd->remote_timers.desired_min_tx) + bfd->detect_TO = bfd->remote_detect_mult + * bfd->cur_timers.required_min_rx; + else + bfd->detect_TO = bfd->remote_detect_mult + * bfd->remote_timers.desired_min_tx; + + /* Apply new receive timer immediately. */ + bfd_recvtimer_update(bfd); + /* Handle echo timers changes. */ bs_echo_timer_handler(bfd); diff --git a/bfdd/bfdd.c b/bfdd/bfdd.c index 188e47905c..c764941513 100644 --- a/bfdd/bfdd.c +++ b/bfdd/bfdd.c @@ -103,7 +103,7 @@ static void sighup_handler(void) vty_read_config(NULL, bfdd_di.config_file, config_default); } -static struct quagga_signal_t bfd_signals[] = { +static struct frr_signal_t bfd_signals[] = { { .signal = SIGUSR1, .handler = &sigusr1_handler, diff --git a/bfdd/bfdd_cli.c b/bfdd/bfdd_cli.c index 384bb26fd7..d4e12e4f1a 100644 --- a/bfdd/bfdd_cli.c +++ b/bfdd/bfdd_cli.c @@ -92,14 +92,15 @@ DEFUN_YANG( } void bfd_cli_show_header(struct vty *vty, - struct lyd_node *dnode __attribute__((__unused__)), + const struct lyd_node *dnode + __attribute__((__unused__)), bool show_defaults __attribute__((__unused__))) { vty_out(vty, "!\nbfd\n"); } -void bfd_cli_show_header_end(struct vty *vty, - struct lyd_node *dnode __attribute__((__unused__))) +void bfd_cli_show_header_end(struct vty *vty, const struct lyd_node *dnode + __attribute__((__unused__))) { vty_out(vty, "exit\n"); vty_out(vty, "!\n"); @@ -230,7 +231,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -static void _bfd_cli_show_peer(struct vty *vty, struct lyd_node *dnode, +static void _bfd_cli_show_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults __attribute__((__unused__)), bool mhop) { @@ -259,22 +260,20 @@ static void _bfd_cli_show_peer(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void bfd_cli_show_single_hop_peer(struct vty *vty, - struct lyd_node *dnode, +void bfd_cli_show_single_hop_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { _bfd_cli_show_peer(vty, dnode, show_defaults, false); } -void bfd_cli_show_multi_hop_peer(struct vty *vty, - struct lyd_node *dnode, - bool show_defaults) +void bfd_cli_show_multi_hop_peer(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) { _bfd_cli_show_peer(vty, dnode, show_defaults, true); } -void bfd_cli_show_peer_end(struct vty *vty, - struct lyd_node *dnode __attribute__((__unused__))) +void bfd_cli_show_peer_end(struct vty *vty, const struct lyd_node *dnode + __attribute__((__unused__))) { vty_out(vty, " exit\n"); vty_out(vty, " !\n"); @@ -291,7 +290,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_shutdown(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " %sshutdown\n", @@ -309,7 +308,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_passive(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " %spassive-mode\n", @@ -347,7 +346,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_minimum_ttl(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_minimum_ttl(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " minimum-ttl %s\n", yang_dnode_get_string(dnode, NULL)); @@ -364,7 +363,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_mult(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_mult(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " detect-multiplier %s\n", @@ -386,7 +385,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_rx(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_rx(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { uint32_t value = yang_dnode_get_uint32(dnode, NULL); @@ -409,7 +408,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_tx(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_tx(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { uint32_t value = yang_dnode_get_uint32(dnode, NULL); @@ -437,8 +436,8 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) +void bfd_cli_show_echo(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) { vty_out(vty, " %secho-mode\n", yang_dnode_get_bool(dnode, NULL) ? "" : "no "); @@ -487,8 +486,8 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_desired_echo_transmission_interval(struct vty *vty, - struct lyd_node *dnode, bool show_defaults) +void bfd_cli_show_desired_echo_transmission_interval( + struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { uint32_t value = yang_dnode_get_uint32(dnode, NULL); @@ -522,7 +521,8 @@ DEFPY_YANG( } void bfd_cli_show_required_echo_receive_interval(struct vty *vty, - struct lyd_node *dnode, bool show_defaults) + const struct lyd_node *dnode, + bool show_defaults) { uint32_t value = yang_dnode_get_uint32(dnode, NULL); @@ -573,7 +573,7 @@ DEFPY_YANG(no_bfd_profile, no_bfd_profile_cmd, return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_profile(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, "./name")); @@ -654,7 +654,7 @@ DEFPY_YANG(bfd_peer_profile, bfd_peer_profile_cmd, return nb_cli_apply_changes(vty, NULL); } -void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_peer_profile_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " profile %s\n", yang_dnode_get_string(dnode, NULL)); diff --git a/bfdd/bfdd_nb.h b/bfdd/bfdd_nb.h index 874e98691f..d7ac320638 100644 --- a/bfdd/bfdd_nb.h +++ b/bfdd/bfdd_nb.h @@ -195,35 +195,36 @@ bfdd_bfd_sessions_multi_hop_stats_echo_packet_output_count_get_elem( struct nb_cb_get_elem_args *args); /* Optional 'cli_show' callbacks. */ -void bfd_cli_show_header(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_header(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_header_end(struct vty *vty, struct lyd_node *dnode); -void bfd_cli_show_single_hop_peer(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_header_end(struct vty *vty, const struct lyd_node *dnode); +void bfd_cli_show_single_hop_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_multi_hop_peer(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_multi_hop_peer(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_peer_end(struct vty *vty, struct lyd_node *dnode); -void bfd_cli_show_mult(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_peer_end(struct vty *vty, const struct lyd_node *dnode); +void bfd_cli_show_mult(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_tx(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_tx(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_rx(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_rx(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_shutdown(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_echo(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_echo(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void bfd_cli_show_desired_echo_transmission_interval( - struct vty *vty, struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_required_echo_receive_interval( - struct vty *vty, struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_profile(struct vty *vty, struct lyd_node *dnode, + struct vty *vty, const struct lyd_node *dnode, bool show_defaults); +void bfd_cli_show_required_echo_receive_interval(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults); +void bfd_cli_show_profile(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_peer_profile_show(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_peer_profile_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_passive(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_passive(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void bfd_cli_show_minimum_ttl(struct vty *vty, struct lyd_node *dnode, +void bfd_cli_show_minimum_ttl(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); #endif /* _FRR_BFDD_NB_H_ */ diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index a03fb9f216..fc3a178703 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -282,8 +282,7 @@ static void _display_peer_json(struct vty *vty, struct bfd_session *bs) { struct json_object *jo = __display_peer_json(bs); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } struct bfd_vrf_tuple { @@ -353,8 +352,7 @@ static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json) bvt.jo = jo; bfd_id_iterate(_display_peer_json_iter, &bvt); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } static void _display_peer_counter(struct vty *vty, struct bfd_session *bs) @@ -407,8 +405,7 @@ static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs) { struct json_object *jo = __display_peer_counters_json(bs); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg) @@ -472,8 +469,7 @@ static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json bvt.jo = jo; bfd_id_iterate(_display_peer_counter_json_iter, &bvt); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } static void _clear_peer_counter(struct bfd_session *bs) @@ -556,8 +552,7 @@ static void _display_peers_brief(struct vty *vty, const char *vrfname, bool use_ bfd_id_iterate(_display_peer_json_iter, &bvt); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } static struct bfd_session * @@ -579,7 +574,7 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, pl = pl_find(label); if (pl) bs = pl->pl_bs; - } else { + } else if (peer_str) { strtosa(peer_str, &psa); if (local_str) { strtosa(local_str, &lsa); @@ -599,6 +594,9 @@ _find_peer_or_error(struct vty *vty, int argc, struct cmd_token **argv, } bs = bs_peer_find(&bpc); + } else { + vty_out(vty, "%% Invalid arguments\n"); + return NULL; } /* Find peer data. */ diff --git a/bfdd/dplane.c b/bfdd/dplane.c index 4b7f9ba7ac..9dee2a5589 100644 --- a/bfdd/dplane.c +++ b/bfdd/dplane.c @@ -157,8 +157,8 @@ static void bfd_dplane_debug_message(const struct bfddp_message *msg) case ECHO_REPLY: case ECHO_REQUEST: zlog_debug(" [dp_time=%" PRIu64 " bfdd_time=%" PRIu64 "]", - (uint64_t)be64toh(msg->data.echo.dp_time), - (uint64_t)be64toh(msg->data.echo.bfdd_time)); + be64toh(msg->data.echo.dp_time), + be64toh(msg->data.echo.bfdd_time)); break; case DP_ADD_SESSION: @@ -245,21 +245,18 @@ static void bfd_dplane_debug_message(const struct bfddp_message *msg) " packets), " "out %" PRIu64 " bytes (%" PRIu64 " packets)}]", ntohl(msg->data.session_counters.lid), - (uint64_t)be64toh( - msg->data.session_counters.control_input_bytes), - (uint64_t)be64toh(msg->data.session_counters - .control_input_packets), - (uint64_t)be64toh(msg->data.session_counters - .control_output_bytes), - (uint64_t)be64toh(msg->data.session_counters - .control_output_packets), - (uint64_t)be64toh(msg->data.session_counters.echo_input_bytes), - (uint64_t)be64toh( - msg->data.session_counters.echo_input_packets), - (uint64_t)be64toh( - msg->data.session_counters.echo_output_bytes), - (uint64_t)be64toh(msg->data.session_counters - .echo_output_packets)); + be64toh(msg->data.session_counters.control_input_bytes), + be64toh(msg->data.session_counters + .control_input_packets), + be64toh(msg->data.session_counters + .control_output_bytes), + be64toh(msg->data.session_counters + .control_output_packets), + be64toh(msg->data.session_counters.echo_input_bytes), + be64toh(msg->data.session_counters.echo_input_packets), + be64toh(msg->data.session_counters.echo_output_bytes), + be64toh(msg->data.session_counters + .echo_output_packets)); break; } } diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index 838acf450f..bf8f731d50 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -666,9 +666,7 @@ static void bfdd_sessions_enable_interface(struct interface *ifp) struct bfd_session *bs; struct vrf *vrf; - vrf = vrf_lookup_by_id(ifp->vrf_id); - if (!vrf) - return; + vrf = ifp->vrf; TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { bs = bso->bso_bs; @@ -767,8 +765,8 @@ void bfdd_sessions_disable_vrf(struct vrf *vrf) static int bfd_ifp_destroy(struct interface *ifp) { if (bglobal.debug_zebra) - zlog_debug("zclient: delete interface %s (VRF %u)", ifp->name, - ifp->vrf_id); + zlog_debug("zclient: delete interface %s (VRF %s(%u))", + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); bfdd_sessions_disable_interface(ifp); @@ -837,36 +835,39 @@ static int bfdd_interface_address_update(ZAPI_CALLBACK_ARGS) static int bfd_ifp_create(struct interface *ifp) { if (bglobal.debug_zebra) - zlog_debug("zclient: add interface %s (VRF %u)", ifp->name, - ifp->vrf_id); + zlog_debug("zclient: add interface %s (VRF %s(%u))", ifp->name, + ifp->vrf->name, ifp->vrf->vrf_id); bfdd_sessions_enable_interface(ifp); return 0; } -void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) -{ - if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy); - zclient = zclient_new(master, &zclient_options_default); - assert(zclient != NULL); - zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv); - +static zclient_handler *const bfd_handlers[] = { /* * We'll receive all messages through replay, however it will * contain a special field with the real command inside so we * avoid having to create too many handlers. */ - zclient->bfd_dest_replay = bfdd_replay; - - /* Send replay request on zebra connect. */ - zclient->zebra_connected = bfdd_zebra_connected; + [ZEBRA_BFD_DEST_REPLAY] = bfdd_replay, /* Learn about interface VRF. */ - zclient->interface_vrf_update = bfdd_interface_vrf_update; + [ZEBRA_INTERFACE_VRF_UPDATE] = bfdd_interface_vrf_update, /* Learn about new addresses being registered. */ - zclient->interface_address_add = bfdd_interface_address_update; - zclient->interface_address_delete = bfdd_interface_address_update; + [ZEBRA_INTERFACE_ADDRESS_ADD] = bfdd_interface_address_update, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = bfdd_interface_address_update, +}; + +void bfdd_zclient_init(struct zebra_privs_t *bfdd_priv) +{ + if_zapi_callbacks(bfd_ifp_create, NULL, NULL, bfd_ifp_destroy); + zclient = zclient_new(master, &zclient_options_default, bfd_handlers, + array_size(bfd_handlers)); + assert(zclient != NULL); + zclient_init(zclient, ZEBRA_ROUTE_BFD, 0, bfdd_priv); + + /* Send replay request on zebra connect. */ + zclient->zebra_connected = bfdd_zebra_connected; } void bfdd_zclient_register(vrf_id_t vrf_id) diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index 3c67017dc7..d3424b2957 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -1002,8 +1002,6 @@ uint8_t *aspath_snmp_pathseg(struct aspath *as, size_t *varlen) return stream_pnt(snmp_stream); } -#define min(A,B) ((A) < (B) ? (A) : (B)) - static struct assegment *aspath_aggregate_as_set_add(struct aspath *aspath, struct assegment *asset, as_t as) @@ -1060,7 +1058,7 @@ struct aspath *aspath_aggregate(struct aspath *as1, struct aspath *as2) break; /* Minimum segment length. */ - minlen = min(seg1->length, seg2->length); + minlen = MIN(seg1->length, seg2->length); for (match = 0; match < minlen; match++) if (seg1->as[match] != seg2->as[match]) diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7de7a6628f..c2017495a6 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -68,9 +68,6 @@ static const struct message attr_str[] = { {BGP_ATTR_COMMUNITIES, "COMMUNITY"}, {BGP_ATTR_ORIGINATOR_ID, "ORIGINATOR_ID"}, {BGP_ATTR_CLUSTER_LIST, "CLUSTER_LIST"}, - {BGP_ATTR_DPA, "DPA"}, - {BGP_ATTR_ADVERTISER, "ADVERTISER"}, - {BGP_ATTR_RCID_PATH, "RCID_PATH"}, {BGP_ATTR_MP_REACH_NLRI, "MP_REACH_NLRI"}, {BGP_ATTR_MP_UNREACH_NLRI, "MP_UNREACH_NLRI"}, {BGP_ATTR_EXT_COMMUNITIES, "EXT_COMMUNITIES"}, @@ -1073,7 +1070,9 @@ struct attr *bgp_attr_aggregate_intern( new = bgp_attr_intern(&attr); } - aspath_unintern(&new->aspath); + /* Always release the 'intern()'ed AS Path. */ + aspath_unintern(&attr.aspath); + return new; } diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 4995f9a1fd..ed54f42b0a 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -150,6 +150,7 @@ void bgp_peer_config_apply(struct peer *p, struct peer_group *pg) void bgp_peer_bfd_update_source(struct peer *p) { struct bfd_session_params *session = p->bfd_config->session; + const union sockunion *source; bool changed = false; int family; union { @@ -161,44 +162,45 @@ void bgp_peer_bfd_update_source(struct peer *p) if (CHECK_FLAG(p->sflags, PEER_STATUS_GROUP)) return; + /* Figure out the correct source to use. */ + if (CHECK_FLAG(p->flags, PEER_FLAG_UPDATE_SOURCE) && p->update_source) + source = p->update_source; + else + source = p->su_local; + /* Update peer's source/destination addresses. */ bfd_sess_addresses(session, &family, &src.v6, &dst.v6); if (family == AF_INET) { - if ((p->su_local - && p->su_local->sin.sin_addr.s_addr != src.v4.s_addr) + if ((source && source->sin.sin_addr.s_addr != src.v4.s_addr) || p->su.sin.sin_addr.s_addr != dst.v4.s_addr) { if (BGP_DEBUG(bfd, BFD_LIB)) zlog_debug( "%s: address [%pI4->%pI4] to [%pI4->%pI4]", __func__, &src.v4, &dst.v4, - p->su_local ? &p->su_local->sin.sin_addr - : &src.v4, + source ? &source->sin.sin_addr + : &src.v4, &p->su.sin.sin_addr); bfd_sess_set_ipv4_addrs( - session, - p->su_local ? &p->su_local->sin.sin_addr : NULL, + session, source ? &source->sin.sin_addr : NULL, &p->su.sin.sin_addr); changed = true; } } else { - if ((p->su_local - && memcmp(&p->su_local->sin6, &src.v6, sizeof(src.v6))) + if ((source && memcmp(&source->sin6, &src.v6, sizeof(src.v6))) || memcmp(&p->su.sin6, &dst.v6, sizeof(dst.v6))) { if (BGP_DEBUG(bfd, BFD_LIB)) zlog_debug( "%s: address [%pI6->%pI6] to [%pI6->%pI6]", __func__, &src.v6, &dst.v6, - p->su_local - ? &p->su_local->sin6.sin6_addr - : &src.v6, + source ? &source->sin6.sin6_addr + : &src.v6, &p->su.sin6.sin6_addr); - bfd_sess_set_ipv6_addrs( - session, - p->su_local ? &p->su_local->sin6.sin6_addr - : NULL, - &p->su.sin6.sin6_addr); + bfd_sess_set_ipv6_addrs(session, + source ? &source->sin6.sin6_addr + : NULL, + &p->su.sin6.sin6_addr); changed = true; } } diff --git a/bgpd/bgp_bmp.c b/bgpd/bgp_bmp.c index 1bc3fd0dba..1c9852f5c2 100644 --- a/bgpd/bgp_bmp.c +++ b/bgpd/bgp_bmp.c @@ -688,22 +688,32 @@ static int bmp_outgoing_packet(struct peer *peer, uint8_t type, bgp_size_t size, return 0; } -static int bmp_peer_established(struct peer *peer) +static int bmp_peer_status_changed(struct peer *peer) { struct bmp_bgp *bmpbgp = bmp_bgp_find(peer->bgp); + struct bmp_bgp_peer *bbpeer, *bbdopp; frrtrace(1, frr_bgp, bmp_peer_status_changed, peer); if (!bmpbgp) return 0; + if (peer->status == Deleted) { + bbpeer = bmp_bgp_peer_find(peer->qobj_node.nid); + if (bbpeer) { + XFREE(MTYPE_BMP_OPEN, bbpeer->open_rx); + XFREE(MTYPE_BMP_OPEN, bbpeer->open_tx); + bmp_peerh_del(&bmp_peerh, bbpeer); + XFREE(MTYPE_BMP_PEER, bbpeer); + } + return 0; + } + /* Check if this peer just went to Established */ if ((peer->ostatus != OpenConfirm) || !(peer_established(peer))) return 0; if (peer->doppelganger && (peer->doppelganger->status != Deleted)) { - struct bmp_bgp_peer *bbpeer, *bbdopp; - bbpeer = bmp_bgp_peer_get(peer); bbdopp = bmp_bgp_peer_find(peer->doppelganger->qobj_node.nid); if (bbdopp) { @@ -1833,6 +1843,7 @@ static int bmp_active_thread(struct thread *t) socklen_t slen; int status, ret; char buf[SU_ADDRSTRLEN]; + vrf_id_t vrf_id; /* all 3 end up here, though only timer or read+write are active * at a time */ @@ -1843,7 +1854,12 @@ static int bmp_active_thread(struct thread *t) ba->last_err = NULL; if (ba->socket == -1) { - resolver_resolve(&ba->resq, AF_UNSPEC, ba->hostname, + /* get vrf_id */ + if (!ba->targets || !ba->targets->bgp) + vrf_id = VRF_DEFAULT; + else + vrf_id = ba->targets->bgp->vrf_id; + resolver_resolve(&ba->resq, AF_UNSPEC, vrf_id, ba->hostname, bmp_active_resolved); return 0; } @@ -2044,7 +2060,7 @@ DEFPY(bmp_connect, DEFPY(bmp_acl, bmp_acl_cmd, - "[no] <ip|ipv6>$af access-list WORD", + "[no] <ip|ipv6>$af access-list ACCESSLIST_NAME$access_list", NO_STR IP_STR IPV6_STR @@ -2435,7 +2451,7 @@ static int bgp_bmp_module_init(void) { hook_register(bgp_packet_dump, bmp_mirror_packet); hook_register(bgp_packet_send, bmp_outgoing_packet); - hook_register(peer_status_changed, bmp_peer_established); + hook_register(peer_status_changed, bmp_peer_status_changed); hook_register(peer_backward_transition, bmp_peer_backward); hook_register(bgp_process, bmp_process); hook_register(bgp_inst_config_write, bmp_config_write); diff --git a/bgpd/bgp_community.c b/bgpd/bgp_community.c index b187fd9736..a5dafd7757 100644 --- a/bgpd/bgp_community.c +++ b/bgpd/bgp_community.c @@ -921,7 +921,7 @@ static struct community *bgp_aggr_community_lookup( return hash_lookup(aggregate->community_hash, community); } -static void *bgp_aggr_communty_hash_alloc(void *p) +static void *bgp_aggr_community_hash_alloc(void *p) { struct community *ref = (struct community *)p; struct community *community = NULL; @@ -978,7 +978,7 @@ void bgp_compute_aggregate_community_hash(struct bgp_aggregate *aggregate, /* Insert community into hash. */ aggr_community = hash_get(aggregate->community_hash, community, - bgp_aggr_communty_hash_alloc); + bgp_aggr_community_hash_alloc); } /* Increment reference counter. diff --git a/bgpd/bgp_damp.c b/bgpd/bgp_damp.c index 6726dd6160..90b7958c43 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -653,21 +653,42 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, } static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty, - afi_t afi, safi_t safi) + afi_t afi, safi_t safi, bool use_json) { if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { - vty_out(vty, "Half-life time: %lld min\n", - (long long)damp[afi][safi].half_life / 60); - vty_out(vty, "Reuse penalty: %d\n", - damp[afi][safi].reuse_limit); - vty_out(vty, "Suppress penalty: %d\n", - damp[afi][safi].suppress_value); - vty_out(vty, "Max suppress time: %lld min\n", - (long long)damp[afi][safi].max_suppress_time / 60); - vty_out(vty, "Max suppress penalty: %u\n", - damp[afi][safi].ceiling); - vty_out(vty, "\n"); - } else + struct bgp_damp_config *bdc = &damp[afi][safi]; + + if (use_json) { + json_object *json = json_object_new_object(); + + json_object_int_add(json, "halfLifeSecs", + bdc->half_life); + json_object_int_add(json, "reusePenalty", + bdc->reuse_limit); + json_object_int_add(json, "suppressPenalty", + bdc->suppress_value); + json_object_int_add(json, "maxSuppressTimeSecs", + bdc->max_suppress_time); + json_object_int_add(json, "maxSuppressPenalty", + bdc->ceiling); + + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + vty_out(vty, "Half-life time: %lld min\n", + (long long)bdc->half_life / 60); + vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit); + vty_out(vty, "Suppress penalty: %d\n", + bdc->suppress_value); + vty_out(vty, "Max suppress time: %lld min\n", + (long long)bdc->max_suppress_time / 60); + vty_out(vty, "Max suppress penalty: %u\n", + bdc->ceiling); + vty_out(vty, "\n"); + } + } else if (!use_json) vty_out(vty, "dampening not enabled for %s\n", get_afi_safi_str(afi, safi, false)); @@ -678,6 +699,8 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, uint16_t show_flags) { struct bgp *bgp; + bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); + bgp = bgp_get_default(); if (bgp == NULL) { @@ -686,7 +709,8 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, } if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL)) - return bgp_print_dampening_parameters(bgp, vty, afi, safi); + return bgp_print_dampening_parameters(bgp, vty, afi, safi, + use_json); if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) || CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6)) { @@ -697,11 +721,12 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, "Unknown")) continue; - if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON)) + if (!use_json) vty_out(vty, "\nFor address family: %s\n\n", get_afi_safi_str(afi, safi, false)); - bgp_print_dampening_parameters(bgp, vty, afi, safi); + bgp_print_dampening_parameters(bgp, vty, afi, safi, + use_json); } } else { FOREACH_AFI_SAFI (afi, safi) { @@ -709,11 +734,12 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, "Unknown")) continue; - if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON)) + if (!use_json) vty_out(vty, "\nFor address family: %s\n", get_afi_safi_str(afi, safi, false)); - bgp_print_dampening_parameters(bgp, vty, afi, safi); + bgp_print_dampening_parameters(bgp, vty, afi, safi, + use_json); } } return CMD_SUCCESS; diff --git a/bgpd/bgp_debug.c b/bgpd/bgp_debug.c index 856afb05f8..64f71bebc9 100644 --- a/bgpd/bgp_debug.c +++ b/bgpd/bgp_debug.c @@ -160,14 +160,14 @@ static const struct message bgp_notify_update_msg[] = { static const struct message bgp_notify_cease_msg[] = { {BGP_NOTIFY_SUBCODE_UNSPECIFIC, "/Unspecific"}, {BGP_NOTIFY_CEASE_MAX_PREFIX, "/Maximum Number of Prefixes Reached"}, - {BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administratively Shutdown"}, - {BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer Unconfigured"}, - {BGP_NOTIFY_CEASE_ADMIN_RESET, "/Administratively Reset"}, + {BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, "/Administrative Shutdown"}, + {BGP_NOTIFY_CEASE_PEER_UNCONFIG, "/Peer De-configured"}, + {BGP_NOTIFY_CEASE_ADMIN_RESET, "/Administrative Reset"}, {BGP_NOTIFY_CEASE_CONNECT_REJECT, "/Connection Rejected"}, {BGP_NOTIFY_CEASE_CONFIG_CHANGE, "/Other Configuration Change"}, {BGP_NOTIFY_CEASE_COLLISION_RESOLUTION, - "/Connection collision resolution"}, - {BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resource"}, + "/Connection Collision Resolution"}, + {BGP_NOTIFY_CEASE_OUT_OF_RESOURCE, "/Out of Resources"}, {0}}; static const struct message bgp_notify_route_refresh_msg[] = { @@ -509,7 +509,7 @@ const char *bgp_notify_admin_message(char *buf, size_t bufsz, uint8_t *data, return NULL; uint8_t len = data[0]; - if (len > 128 || len > datalen - 1) + if (!len || len > datalen - 1) return NULL; return zlog_sanitize(buf, bufsz, data + 1, len); diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c index 1e95d401aa..5a053a7f34 100644 --- a/bgpd/bgp_ecommunity.c +++ b/bgpd/bgp_ecommunity.c @@ -934,7 +934,7 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter) strlcat(str_buf, " ", str_size); /* Retrieve value field */ - pnt = ecom->val + (i * 8); + pnt = ecom->val + (i * ecom->unit_size); /* High-order octet is the type */ type = *pnt++; diff --git a/bgpd/bgp_evpn_mh.c b/bgpd/bgp_evpn_mh.c index 9316d218a2..2254bc6ba7 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -2191,13 +2191,11 @@ static void bgp_evpn_es_json_vtep_fill(json_object *json_vteps, { json_object *json_vtep_entry; json_object *json_flags; - char ip_buf[INET6_ADDRSTRLEN]; json_vtep_entry = json_object_new_object(); - json_object_string_add( - json_vtep_entry, "vtep_ip", - inet_ntop(AF_INET, &es_vtep->vtep_ip, ip_buf, sizeof(ip_buf))); + json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4", + &es_vtep->vtep_ip); if (es_vtep->flags & (BGP_EVPNES_VTEP_ESR | BGP_EVPNES_VTEP_ACTIVE)) { json_flags = json_object_new_array(); @@ -2314,8 +2312,6 @@ static void bgp_evpn_es_show_entry(struct vty *vty, static void bgp_evpn_es_show_entry_detail(struct vty *vty, struct bgp_evpn_es *es, json_object *json) { - char ip_buf[INET6_ADDRSTRLEN]; - if (json) { json_object *json_flags; json_object *json_incons; @@ -2338,9 +2334,8 @@ static void bgp_evpn_es_show_entry_detail(struct vty *vty, json_array_string_add(json_flags, "bypass"); json_object_object_add(json, "flags", json_flags); } - json_object_string_add(json, "originator_ip", - inet_ntop(AF_INET, &es->originator_ip, - ip_buf, sizeof(ip_buf))); + json_object_string_addf(json, "originator_ip", "%pI4", + &es->originator_ip); json_object_int_add(json, "remoteVniCount", es->remote_es_evi_cnt); json_object_int_add(json, "vrfCount", @@ -2456,11 +2451,8 @@ void bgp_evpn_es_show(struct vty *vty, bool uj, bool detail) } /* print the array of json-ESs */ - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } /* Display specific ES */ @@ -2480,11 +2472,8 @@ void bgp_evpn_es_show_esi(struct vty *vty, esi_t *esi, bool uj) vty_out(vty, "ESI not found\n"); } - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); } /*****************************************************************************/ @@ -3035,12 +3024,8 @@ void bgp_evpn_es_vrf_show(struct vty *vty, bool uj, struct bgp_evpn_es *es) } /* print the array of json-ESs */ - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } /* Display specific ES VRF */ @@ -3714,13 +3699,11 @@ static void bgp_evpn_es_evi_json_vtep_fill(json_object *json_vteps, { json_object *json_vtep_entry; json_object *json_flags; - char ip_buf[INET6_ADDRSTRLEN]; json_vtep_entry = json_object_new_object(); - json_object_string_add( - json_vtep_entry, "vtep_ip", - inet_ntop(AF_INET, &evi_vtep->vtep_ip, ip_buf, sizeof(ip_buf))); + json_object_string_addf(json_vtep_entry, "vtep_ip", "%pI4", + &evi_vtep->vtep_ip); if (evi_vtep->flags & (BGP_EVPN_EVI_VTEP_EAD_PER_ES | BGP_EVPN_EVI_VTEP_EAD_PER_EVI)) { json_flags = json_object_new_array(); @@ -3891,11 +3874,8 @@ void bgp_evpn_es_evi_show(struct vty *vty, bool uj, bool detail) (void (*)(struct hash_bucket *, void *))bgp_evpn_es_evi_show_one_vni_hash_cb, &wctx); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } /* Display specific ES EVI */ @@ -3929,11 +3909,8 @@ void bgp_evpn_es_evi_show_vni(struct vty *vty, vni_t vni, vty_out(vty, "VNI not found\n"); } - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } /***************************************************************************** @@ -4661,12 +4638,8 @@ void bgp_evpn_nh_show(struct vty *vty, bool uj) } /* print the array of json-ESs */ - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } /*****************************************************************************/ diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index aced0177ea..f377c8352b 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -377,7 +377,6 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, json_object *json_import_rtl = NULL; json_object *json_export_rtl = NULL; char buf2[ETHER_ADDR_STRLEN]; - char originator_ip[BUFSIZ] = {0}; json_import_rtl = json_export_rtl = 0; @@ -390,19 +389,15 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, json_object_string_add( json, "rd", prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN)); - json_object_string_add( - json, "originatorIp", - inet_ntop(AF_INET, &bgp_vrf->originator_ip, - originator_ip, sizeof(originator_ip))); + json_object_string_addf(json, "originatorIp", "%pI4", + &bgp_vrf->originator_ip); json_object_string_add(json, "advertiseGatewayMacip", "n/a"); json_object_string_add(json, "advertiseSviMacIp", "n/a"); json_object_string_add(json, "advertisePip", bgp_vrf->evpn_info->advertise_pip ? "Enabled" : "Disabled"); - json_object_string_add(json, "sysIP", - inet_ntop(AF_INET, - &bgp_vrf->evpn_info->pip_ip, - buf1, INET_ADDRSTRLEN)); + json_object_string_addf(json, "sysIP", "%pI4", + &bgp_vrf->evpn_info->pip_ip); json_object_string_add(json, "sysMac", prefix_mac2str(&bgp_vrf->evpn_info->pip_rmac, buf2, sizeof(buf2))); @@ -483,7 +478,6 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) json_object *json_import_rtl = NULL; json_object *json_export_rtl = NULL; struct bgp *bgp_evpn; - char buf[BUFSIZ] = {0}; bgp_evpn = bgp_get_evpn(); @@ -497,12 +491,10 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) json_object_string_add( json, "rd", prefix_rd2str(&vpn->prd, buf1, sizeof(buf1))); - json_object_string_add(json, "originatorIp", - inet_ntop(AF_INET, &vpn->originator_ip, - buf, sizeof(buf))); - json_object_string_add( - json, "mcastGroup", - inet_ntop(AF_INET, &vpn->mcast_grp, buf, sizeof(buf))); + json_object_string_addf(json, "originatorIp", "%pI4", + &vpn->originator_ip); + json_object_string_addf(json, "mcastGroup", "%pI4", + &vpn->mcast_grp); /* per vni knob is enabled -- Enabled * Global knob is enabled -- Active * default -- Disabled @@ -933,7 +925,6 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, json_object *json_export_rtl = NULL; char buf1[10]; char buf2[INET6_ADDRSTRLEN]; - char buf3[BUFSIZ] = {0}; char rt_buf[25]; char *ecom_str; struct listnode *node, *nnode; @@ -956,9 +947,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, json_object_int_add(json_vni, "vni", bgp->l3vni); json_object_string_add(json_vni, "type", "L3"); json_object_string_add(json_vni, "inKernel", "True"); - json_object_string_add(json_vni, "originatorIp", - inet_ntop(AF_INET, &bgp->originator_ip, - buf3, sizeof(buf3))); + json_object_string_addf(json_vni, "originatorIp", "%pI4", + &bgp->originator_ip); json_object_string_add( json_vni, "rd", prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN)); @@ -968,10 +958,8 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, json_object_string_add( json_vni, "advertisePip", bgp->evpn_info->advertise_pip ? "Enabled" : "Disabled"); - json_object_string_add(json_vni, "sysIP", - inet_ntop(AF_INET, - &bgp->evpn_info->pip_ip, buf3, - sizeof(buf3))); + json_object_string_addf(json_vni, "sysIP", "%pI4", + &bgp->evpn_info->pip_ip); json_object_string_add(json_vni, "sysMAC", prefix_mac2str(&bgp->evpn_info->pip_rmac, buf2, sizeof(buf2))); @@ -1060,7 +1048,6 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[]) struct bgpevpn *vpn = (struct bgpevpn *)bucket->data; char buf1[10]; char buf2[RD_ADDRSTRLEN]; - char buf3[BUFSIZ] = {0}; char rt_buf[25]; char *ecom_str; struct listnode *node, *nnode; @@ -1090,12 +1077,10 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[]) json_object_string_add( json_vni, "rd", prefix_rd2str(&vpn->prd, buf2, sizeof(buf2))); - json_object_string_add(json_vni, "originatorIp", - inet_ntop(AF_INET, &vpn->originator_ip, - buf3, sizeof(buf3))); - json_object_string_add(json_vni, "mcastGroup", - inet_ntop(AF_INET, &vpn->mcast_grp, buf3, - sizeof(buf3))); + json_object_string_addf(json_vni, "originatorIp", "%pI4", + &vpn->originator_ip); + json_object_string_addf(json_vni, "mcastGroup", "%pI4", + &vpn->mcast_grp); /* per vni knob is enabled -- Enabled * Global knob is enabled -- Active * default -- Disabled @@ -1207,7 +1192,6 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, char rd_str[RD_ADDRSTRLEN]; char buf[BUFSIZ]; int no_display; - char router_id[BUFSIZ] = {0}; unsigned long output_count = 0; unsigned long total_count = 0; @@ -1296,14 +1280,11 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, json_object_int_add( json, "bgpTableVersion", tbl_ver); - json_object_string_add( + json_object_string_addf( json, "bgpLocalRouterId", - inet_ntop( - AF_INET, - &bgp->router_id, - router_id, - sizeof(router_id))); + "%pI4", + &bgp->router_id); json_object_int_add( json, "defaultLocPrf", @@ -1364,10 +1345,12 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, json_prefix_info = json_object_new_object(); - json_object_string_add( - json_prefix_info, "prefix", - prefix2str((struct prefix_evpn *)p, buf, - BUFSIZ)); + prefix2str((struct prefix_evpn *)p, buf, + BUFSIZ); + + json_object_string_addf( + json_prefix_info, "prefix", "%pFX", + (struct prefix_evpn *)p); json_object_int_add(json_prefix_info, "prefixLen", p->prefixlen); @@ -1387,9 +1370,7 @@ static int bgp_show_ethernet_vpn(struct vty *vty, struct prefix_rd *prd, if (use_json) { json_object_int_add(json, "numPrefix", output_count); json_object_int_add(json, "totalPrefix", total_count); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { if (output_count == 0) vty_out(vty, "No prefixes displayed, %ld exist\n", @@ -4408,14 +4389,8 @@ DEFUN(show_bgp_l2vpn_evpn_vni, evpn_show_vni(vty, bgp_evpn, vni, json); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, - JSON_C_TO_STRING_PRETTY - | JSON_C_TO_STRING_NOSLASHESCAPE)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -4693,11 +4668,8 @@ DEFUN(show_bgp_l2vpn_evpn_route, evpn_show_all_routes(vty, bgp, type, json, detail); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -4757,11 +4729,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd, else evpn_show_route_rd(vty, bgp, &prd, type, json); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -4843,11 +4812,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_rd_macip, else evpn_show_route_rd_macip(vty, bgp, &prd, &mac, &ip, json); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -4887,11 +4853,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_esi, evpn_show_routes_esi(vty, bgp, &esi, json); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -4957,11 +4920,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni, show_bgp_l2vpn_evpn_route_vni_cmd, evpn_show_routes_vni(vty, bgp, vni, type, vtep_ip, json); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5027,11 +4987,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_macip, evpn_show_route_vni_macip(vty, bgp, vni, &mac, &ip, json); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5085,11 +5042,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_multicast, evpn_show_route_vni_multicast(vty, bgp, vni, orig_ip, json); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5148,11 +5102,8 @@ DEFUN(show_bgp_l2vpn_evpn_route_vni_all, evpn_show_routes_vni_all(vty, bgp, vtep_ip, json, da); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5184,12 +5135,8 @@ DEFPY_HIDDEN( if (uj) json = json_object_new_object(); bgp_evpn_show_routes_mac_ip_evi_es(vty, esi_p, json, !!detail); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5221,12 +5168,8 @@ DEFPY_HIDDEN( if (uj) json = json_object_new_object(); bgp_evpn_show_routes_mac_ip_global_es(vty, esi_p, json, !!detail); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5258,11 +5201,8 @@ DEFUN(show_bgp_l2vpn_evpn_vrf_import_rt, evpn_show_vrf_import_rts(vty, bgp_evpn, json); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5294,11 +5234,8 @@ DEFUN(show_bgp_l2vpn_evpn_import_rt, evpn_show_import_rts(vty, bgp, json); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -5781,7 +5718,6 @@ DEFUN (show_bgp_vrf_l3vni_info, { char buf[ETHER_ADDR_STRLEN]; char buf1[INET6_ADDRSTRLEN]; - char originator_ip[BUFSIZ] = {0}; int idx_vrf = 3; const char *name = NULL; struct bgp *bgp = NULL; @@ -5845,10 +5781,8 @@ DEFUN (show_bgp_vrf_l3vni_info, prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN)); } else { json_object_string_add(json, "vrf", name); - json_object_string_add(json, "local-ip", - inet_ntop(AF_INET, &bgp->originator_ip, - originator_ip, - sizeof(originator_ip))); + json_object_string_addf(json, "local-ip", "%pI4", + &bgp->originator_ip); json_object_int_add(json, "l3vni", bgp->l3vni); json_object_string_add( json, "rmac", @@ -5883,11 +5817,8 @@ DEFUN (show_bgp_vrf_l3vni_info, prefix_rd2str(&bgp->vrf_prd, buf1, RD_ADDRSTRLEN)); } - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } diff --git a/bgpd/bgp_filter.c b/bgpd/bgp_filter.c index 641cc7605f..fc9fc1e523 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -440,7 +440,7 @@ bool config_bgp_aspath_validate(const char *regstr) } DEFUN(as_path, bgp_as_path_cmd, - "bgp as-path access-list WORD [seq (0-4294967295)] <deny|permit> LINE...", + "bgp as-path access-list AS_PATH_FILTER_NAME [seq (0-4294967295)] <deny|permit> LINE...", BGP_STR "BGP autonomous system path filter\n" "Specify an access list name\n" @@ -460,7 +460,7 @@ DEFUN(as_path, bgp_as_path_cmd, int64_t seqnum = ASPATH_SEQ_NUMBER_AUTO; /* Retrieve access list name */ - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "AS_PATH_FILTER_NAME", &idx); char *alname = argv[idx]->arg; if (argv_find(argv, argc, "(0-4294967295)", &idx)) @@ -509,7 +509,7 @@ DEFUN(as_path, bgp_as_path_cmd, } DEFUN(no_as_path, no_bgp_as_path_cmd, - "no bgp as-path access-list WORD [seq (0-4294967295)] <deny|permit> LINE...", + "no bgp as-path access-list AS_PATH_FILTER_NAME [seq (0-4294967295)] <deny|permit> LINE...", NO_STR BGP_STR "BGP autonomous system path filter\n" @@ -529,7 +529,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, regex_t *regex; char *aslistname = - argv_find(argv, argc, "WORD", &idx) ? argv[idx]->arg : NULL; + argv_find(argv, argc, "AS_PATH_FILTER_NAME", &idx) ? argv[idx]->arg : NULL; /* Lookup AS list from AS path list. */ aslist = as_list_lookup(aslistname); @@ -586,7 +586,7 @@ DEFUN(no_as_path, no_bgp_as_path_cmd, DEFUN (no_as_path_all, no_bgp_as_path_all_cmd, - "no bgp as-path access-list WORD", + "no bgp as-path access-list AS_PATH_FILTER_NAME", NO_STR BGP_STR "BGP autonomous system path filter\n" @@ -653,7 +653,7 @@ static void as_list_show_all(struct vty *vty, json_object *json) DEFUN (show_as_path_access_list, show_bgp_as_path_access_list_cmd, - "show bgp as-path-access-list WORD [json]", + "show bgp as-path-access-list AS_PATH_FILTER_NAME [json]", SHOW_STR BGP_STR "List AS path access lists\n" @@ -672,19 +672,15 @@ DEFUN (show_as_path_access_list, if (aslist) as_list_show(vty, aslist, json); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } ALIAS (show_as_path_access_list, show_ip_as_path_access_list_cmd, - "show ip as-path-access-list WORD [json]", + "show ip as-path-access-list AS_PATH_FILTER_NAME [json]", SHOW_STR IP_STR "List AS path access lists\n" @@ -707,12 +703,8 @@ DEFUN (show_as_path_access_list_all, as_list_show_all(vty, json); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -753,6 +745,20 @@ static struct cmd_node as_list_node = { .config_write = config_write_as_list, }; +static void bgp_aspath_filter_cmd_completion(vector comps, + struct cmd_token *token) +{ + struct as_list *aslist; + + for (aslist = as_list_master.str.head; aslist; aslist = aslist->next) + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, aslist->name)); +} + +static const struct cmd_variable_handler aspath_filter_handlers[] = { + {.tokenname = "AS_PATH_FILTER_NAME", + .completions = bgp_aspath_filter_cmd_completion}, + {.completions = NULL}}; + /* Register functions. */ void bgp_filter_init(void) { @@ -766,6 +772,8 @@ void bgp_filter_init(void) install_element(VIEW_NODE, &show_ip_as_path_access_list_cmd); install_element(VIEW_NODE, &show_bgp_as_path_access_list_all_cmd); install_element(VIEW_NODE, &show_ip_as_path_access_list_all_cmd); + + cmd_variable_handler_register(aspath_filter_handlers); } void bgp_filter_reset(void) diff --git a/bgpd/bgp_flowspec_vty.c b/bgpd/bgp_flowspec_vty.c index 11487ed847..8873ca5c0c 100644 --- a/bgpd/bgp_flowspec_vty.c +++ b/bgpd/bgp_flowspec_vty.c @@ -449,11 +449,7 @@ int bgp_show_table_flowspec(struct vty *vty, struct bgp *bgp, afi_t afi, pi, display, json_paths); } if (use_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_paths, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json_paths); + vty_json(vty, json_paths); json_paths = NULL; } } diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index 5b997867e0..1e9dd21fd1 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -48,6 +48,7 @@ #include "bgpd/bgp_dump.h" #include "bgpd/bgp_open.h" #include "bgpd/bgp_advertise.h" +#include "bgpd/bgp_community.h" #include "bgpd/bgp_updgrp.h" #include "bgpd/bgp_nht.h" #include "bgpd/bgp_bfd.h" @@ -297,6 +298,7 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) peer->afc_adv[afi][safi] = from_peer->afc_adv[afi][safi]; peer->afc_recv[afi][safi] = from_peer->afc_recv[afi][safi]; peer->orf_plist[afi][safi] = from_peer->orf_plist[afi][safi]; + peer->llgr[afi][safi] = from_peer->llgr[afi][safi]; } if (bgp_getsockname(peer) < 0) { @@ -352,6 +354,9 @@ static struct peer *peer_xfer_conn(struct peer *from_peer) structure. */ void bgp_timer_set(struct peer *peer) { + afi_t afi; + safi_t safi; + switch (peer->status) { case Idle: /* First entry point of peer's finite state machine. In Idle @@ -465,6 +470,10 @@ void bgp_timer_set(struct peer *peer) case Deleted: BGP_TIMER_OFF(peer->t_gr_restart); BGP_TIMER_OFF(peer->t_gr_stale); + + FOREACH_AFI_SAFI (afi, safi) + BGP_TIMER_OFF(peer->t_llgr_stale[afi][safi]); + BGP_TIMER_OFF(peer->t_pmax_restart); BGP_TIMER_OFF(peer->t_refresh_stalepath); /* fallthru */ @@ -509,8 +518,7 @@ static int bgp_connect_timer(struct thread *thread) peer = THREAD_ARG(thread); /* stop the DelayOpenTimer if it is running */ - if (peer->t_delayopen) - BGP_TIMER_OFF(peer->t_delayopen); + BGP_TIMER_OFF(peer->t_delayopen); assert(!peer->t_write); assert(!peer->t_read); @@ -642,22 +650,132 @@ const char *const peer_down_str[] = {"", "Reached received prefix count", "Socket Error"}; -static int bgp_graceful_restart_timer_expire(struct thread *thread) +static void bgp_graceful_restart_timer_off(struct peer *peer) { - struct peer *peer; afi_t afi; safi_t safi; - peer = THREAD_ARG(thread); - - /* NSF delete stale route */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) - if (peer->nsf[afi][safi]) - bgp_clear_stale_route(peer, afi, safi); + FOREACH_AFI_SAFI (afi, safi) + if (CHECK_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_LLGR_WAIT)) + return; UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); BGP_TIMER_OFF(peer->t_gr_stale); + bgp_timer_set(peer); +} + +static int bgp_llgr_stale_timer_expire(struct thread *thread) +{ + struct peer_af *paf; + struct peer *peer; + afi_t afi; + safi_t safi; + + paf = THREAD_ARG(thread); + + peer = paf->peer; + afi = paf->afi; + safi = paf->safi; + + /* If the timer for the "Long-lived Stale Time" expires before the + * session is re-established, the helper MUST delete all the + * stale routes from the neighbor that it is retaining. + */ + if (bgp_debug_neighbor_events(peer)) + zlog_debug("%s Long-lived stale timer (%s) expired", peer->host, + get_afi_safi_str(afi, safi, false)); + + UNSET_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_LLGR_WAIT); + + bgp_clear_stale_route(peer, afi, safi); + + bgp_graceful_restart_timer_off(peer); + + return 0; +} + +static void bgp_set_llgr_stale(struct peer *peer, afi_t afi, safi_t safi) +{ + struct bgp_dest *dest; + struct bgp_path_info *pi; + struct bgp_table *table; + struct attr attr; + + if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { + for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; + dest = bgp_route_next(dest)) { + struct bgp_dest *rm; + + table = bgp_dest_get_bgp_table_info(dest); + if (!table) + continue; + + for (rm = bgp_table_top(table); rm; + rm = bgp_route_next(rm)) + for (pi = bgp_dest_get_bgp_path_info(rm); pi; + pi = pi->next) { + if (pi->peer != peer) + continue; + + if (pi->attr->community && + community_include( + pi->attr->community, + COMMUNITY_NO_LLGR)) + continue; + + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%s Long-lived set stale community (LLGR_STALE) for: %pFX", + peer->host, &dest->p); + + attr = *pi->attr; + bgp_attr_add_llgr_community(&attr); + pi->attr = bgp_attr_intern(&attr); + bgp_recalculate_afi_safi_bestpaths( + peer->bgp, afi, safi); + + break; + } + } + } else { + for (dest = bgp_table_top(peer->bgp->rib[afi][safi]); dest; + dest = bgp_route_next(dest)) + for (pi = bgp_dest_get_bgp_path_info(dest); pi; + pi = pi->next) { + if (pi->peer != peer) + continue; + + if (pi->attr->community && + community_include(pi->attr->community, + COMMUNITY_NO_LLGR)) + continue; + + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%s Long-lived set stale community (LLGR_STALE) for: %pFX", + peer->host, &dest->p); + + attr = *pi->attr; + bgp_attr_add_llgr_community(&attr); + pi->attr = bgp_attr_intern(&attr); + bgp_recalculate_afi_safi_bestpaths(peer->bgp, + afi, safi); + + break; + } + } +} + +static int bgp_graceful_restart_timer_expire(struct thread *thread) +{ + struct peer *peer, *tmp_peer; + struct listnode *node, *nnode; + struct peer_af *paf; + afi_t afi; + safi_t safi; + + peer = THREAD_ARG(thread); if (bgp_debug_neighbor_events(peer)) { zlog_debug("%s graceful restart timer expired", peer->host); @@ -665,7 +783,54 @@ static int bgp_graceful_restart_timer_expire(struct thread *thread) peer->host); } - bgp_timer_set(peer); + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->nsf[afi][safi]) + continue; + + /* Once the "Restart Time" period ends, the LLGR period is + * said to have begun and the following procedures MUST be + * performed: + * + * The helper router MUST start a timer for the + * "Long-lived Stale Time". + * + * The helper router MUST attach the LLGR_STALE community + * for the stale routes being retained. Note that this + * requirement implies that the routes would need to be + * readvertised, to disseminate the modified community. + */ + if (peer->llgr[afi][safi].stale_time) { + paf = peer_af_find(peer, afi, safi); + if (!paf) + continue; + + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%s Long-lived stale timer (%s) started for %d sec", + peer->host, + get_afi_safi_str(afi, safi, false), + peer->llgr[afi][safi].stale_time); + + SET_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_LLGR_WAIT); + + bgp_set_llgr_stale(peer, afi, safi); + bgp_clear_stale_route(peer, afi, safi); + + thread_add_timer(bm->master, + bgp_llgr_stale_timer_expire, paf, + peer->llgr[afi][safi].stale_time, + &peer->t_llgr_stale[afi][safi]); + + for (ALL_LIST_ELEMENTS(peer->bgp->peer, node, nnode, + tmp_peer)) + bgp_announce_route(tmp_peer, afi, safi, false); + } else { + bgp_clear_stale_route(peer, afi, safi); + } + } + + bgp_graceful_restart_timer_off(peer); return 0; } @@ -756,8 +921,8 @@ void bgp_update_delay_end(struct bgp *bgp) bgp->implicit_eors = 0; bgp->explicit_eors = 0; - quagga_timestamp(3, bgp->update_delay_end_time, - sizeof(bgp->update_delay_end_time)); + frr_timestamp(3, bgp->update_delay_end_time, + sizeof(bgp->update_delay_end_time)); /* * Add an end-of-initial-update marker to the main process queues so @@ -804,8 +969,8 @@ void bgp_start_routeadv(struct bgp *bgp) if (bgp->main_peers_update_hold) return; - quagga_timestamp(3, bgp->update_delay_peers_resume_time, - sizeof(bgp->update_delay_peers_resume_time)); + frr_timestamp(3, bgp->update_delay_peers_resume_time, + sizeof(bgp->update_delay_peers_resume_time)); for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (!peer_established(peer)) @@ -830,8 +995,7 @@ void bgp_adjust_routeadv(struct peer *peer) * different * duration and schedule write thread immediately. */ - if (peer->t_routeadv) - BGP_TIMER_OFF(peer->t_routeadv); + BGP_TIMER_OFF(peer->t_routeadv); peer->synctime = bgp_clock(); /* If suppress fib pending is enabled, route is advertised to @@ -1057,8 +1221,8 @@ static void bgp_update_delay_begin(struct bgp *bgp) thread_add_timer(bm->master, bgp_establish_wait_timer, bgp, bgp->v_establish_wait, &bgp->t_establish_wait); - quagga_timestamp(3, bgp->update_delay_begin_time, - sizeof(bgp->update_delay_begin_time)); + frr_timestamp(3, bgp->update_delay_begin_time, + sizeof(bgp->update_delay_begin_time)); } static void bgp_update_delay_process_status_change(struct peer *peer) diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index 3c8f2f3668..c101cf917b 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -244,6 +244,10 @@ void bgp_reg_dereg_for_label(struct bgp_dest *dest, struct bgp_path_info *pi, p = bgp_dest_get_prefix(dest); + if (BGP_DEBUG(labelpool, LABELPOOL)) + zlog_debug("%s: %pFX: %s ", __func__, p, + (reg ? "reg" : "dereg")); + if (reg) { assert(pi); /* @@ -440,8 +444,8 @@ int bgp_nlri_parse_label(struct peer *peer, struct attr *attr, if (attr) { bgp_update(peer, &p, addpath_id, attr, packet->afi, - SAFI_UNICAST, ZEBRA_ROUTE_BGP, - BGP_ROUTE_NORMAL, NULL, &label, 1, 0, NULL); + safi, ZEBRA_ROUTE_BGP, BGP_ROUTE_NORMAL, + NULL, &label, 1, 0, NULL); } else { bgp_withdraw(peer, &p, addpath_id, attr, packet->afi, SAFI_UNICAST, ZEBRA_ROUTE_BGP, diff --git a/bgpd/bgp_label.h b/bgpd/bgp_label.h index d227cf7241..cafcc8e9c7 100644 --- a/bgpd/bgp_label.h +++ b/bgpd/bgp_label.h @@ -65,7 +65,7 @@ static inline int bgp_is_withdraw_label(mpls_label_t *label) return 0; } -static inline int bgp_is_valid_label(mpls_label_t *label) +static inline int bgp_is_valid_label(const mpls_label_t *label) { uint8_t *t = (uint8_t *)label; if (!t) @@ -99,7 +99,7 @@ static inline void bgp_unregister_for_label(struct bgp_dest *dest) } /* Label stream to value */ -static inline uint32_t label_pton(mpls_label_t *label) +static inline uint32_t label_pton(const mpls_label_t *label) { uint8_t *t = (uint8_t *)label; return ((((unsigned int)t[0]) << 12) | (((unsigned int)t[1]) << 4) diff --git a/bgpd/bgp_labelpool.c b/bgpd/bgp_labelpool.c index fcb2df9d6f..1bc7b62304 100644 --- a/bgpd/bgp_labelpool.c +++ b/bgpd/bgp_labelpool.c @@ -638,10 +638,7 @@ DEFUN(show_bgp_labelpool_summary, show_bgp_labelpool_summary_cmd, json_object_int_add(json, "LabelChunks", listcount(lp->chunks)); json_object_int_add(json, "Pending", lp->pending_count); json_object_int_add(json, "Reconnects", lp->reconnect_count); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { vty_out(vty, "Labelpool Summary\n"); vty_out(vty, "-----------------\n"); @@ -738,12 +735,8 @@ DEFUN(show_bgp_labelpool_ledger, show_bgp_labelpool_ledger_cmd, break; } } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -833,12 +826,8 @@ DEFUN(show_bgp_labelpool_inuse, show_bgp_labelpool_inuse_cmd, break; } } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -911,12 +900,8 @@ DEFUN(show_bgp_labelpool_requests, show_bgp_labelpool_requests_cmd, break; } } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -962,12 +947,8 @@ DEFUN(show_bgp_labelpool_chunks, show_bgp_labelpool_chunks_cmd, vty_out(vty, "%-10u %-10u\n", chunk->first, chunk->last); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } diff --git a/bgpd/bgp_main.c b/bgpd/bgp_main.c index 08776d200f..6a01a6137c 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -90,7 +90,7 @@ void sigusr1(void); static void bgp_exit(int); static void bgp_vrf_terminate(void); -static struct quagga_signal_t bgp_signals[] = { +static struct frr_signal_t bgp_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 1d727d267a..ba66bf3b6e 100644 --- a/bgpd/bgp_mpath.c +++ b/bgpd/bgp_mpath.c @@ -181,6 +181,20 @@ int bgp_path_info_nexthop_cmp(struct bgp_path_info *bpi1, } } + /* + * If both nexthops are same then check + * if they belong to same VRF + */ + if (!compare && bpi1->attr->nh_type != NEXTHOP_TYPE_BLACKHOLE) { + if (bpi1->extra && bpi1->extra->bgp_orig && bpi2->extra + && bpi2->extra->bgp_orig) { + if (bpi1->extra->bgp_orig->vrf_id + != bpi2->extra->bgp_orig->vrf_id) { + compare = 1; + } + } + } + return compare; } @@ -508,7 +522,7 @@ static void bgp_path_info_mpath_attr_set(struct bgp_path_info *path, * Compare and sync up the multipath list with the mp_list generated by * bgp_best_selection */ -void bgp_path_info_mpath_update(struct bgp_dest *dest, +void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *new_best, struct bgp_path_info *old_best, struct list *mp_list, @@ -553,11 +567,11 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, if (debug) zlog_debug( - "%pRN: starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw u%" PRIu64, - bgp_dest_to_rnode(dest), + "%pRN(%s): starting mpath update, newbest %s num candidates %d old-mpath-count %d old-cum-bw u%" PRIu64, + bgp_dest_to_rnode(dest), bgp->name_pretty, new_best ? new_best->peer->host : "NONE", - mp_list ? listcount(mp_list) : 0, - old_mpath_count, old_cum_bw); + mp_list ? listcount(mp_list) : 0, old_mpath_count, + old_cum_bw); /* * We perform an ordered walk through both lists in parallel. @@ -589,8 +603,8 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, if (debug) zlog_debug( - "%pRN: comparing candidate %s with existing mpath %s", - bgp_dest_to_rnode(dest), + "%pRN(%s): comparing candidate %s with existing mpath %s", + bgp_dest_to_rnode(dest), bgp->name_pretty, tmp_info ? tmp_info->peer->host : "NONE", cur_mpath ? cur_mpath->peer->host : "NONE"); @@ -734,9 +748,9 @@ void bgp_path_info_mpath_update(struct bgp_dest *dest, if (debug) zlog_debug( - "%pRN: New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw u%" PRIu64, - bgp_dest_to_rnode(dest), mpath_count, - mpath_changed ? "YES" : "NO", + "%pRN(%s): New mpath count (incl newbest) %d mpath-change %s all_paths_lb %d cum_bw u%" PRIu64, + bgp_dest_to_rnode(dest), bgp->name_pretty, + mpath_count, mpath_changed ? "YES" : "NO", all_paths_lb, cum_bw); if (mpath_changed diff --git a/bgpd/bgp_mpath.h b/bgpd/bgp_mpath.h index a07e48159e..5476297c3d 100644 --- a/bgpd/bgp_mpath.h +++ b/bgpd/bgp_mpath.h @@ -64,7 +64,7 @@ extern void bgp_mp_list_init(struct list *); extern void bgp_mp_list_clear(struct list *); extern void bgp_mp_list_add(struct list *mp_list, struct bgp_path_info *mpinfo); extern void bgp_mp_dmed_deselect(struct bgp_path_info *dmed_best); -extern void bgp_path_info_mpath_update(struct bgp_dest *dest, +extern void bgp_path_info_mpath_update(struct bgp *bgp, struct bgp_dest *dest, struct bgp_path_info *new_best, struct bgp_path_info *old_best, struct list *mp_list, diff --git a/bgpd/bgp_mplsvpn.c b/bgpd/bgp_mplsvpn.c index 659029b04c..e24c1ab764 100644 --- a/bgpd/bgp_mplsvpn.c +++ b/bgpd/bgp_mplsvpn.c @@ -779,10 +779,7 @@ leak_update(struct bgp *bgp, /* destination bgp instance */ * schemes that could be implemented in the future. * */ - for (bpi_ultimate = source_bpi; - bpi_ultimate->extra && bpi_ultimate->extra->parent; - bpi_ultimate = bpi_ultimate->extra->parent) - ; + bpi_ultimate = bgp_get_imported_bpi_ultimate(source_bpi); /* * match parent @@ -1619,10 +1616,7 @@ vpn_leak_to_vrf_update_onevrf(struct bgp *bgp_vrf, /* to */ if (!CHECK_FLAG(bgp_vrf->af_flags[afi][safi], BGP_CONFIG_VRF_TO_VRF_IMPORT)) { /* work back to original route */ - for (bpi_ultimate = path_vpn; - bpi_ultimate->extra && bpi_ultimate->extra->parent; - bpi_ultimate = bpi_ultimate->extra->parent) - ; + bpi_ultimate = bgp_get_imported_bpi_ultimate(path_vpn); /* * if original route was unicast, diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c index c77e240855..19ae137208 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -588,7 +588,7 @@ static void bgp_nht_ifp_handle(struct interface *ifp, bool up) { struct bgp *bgp; - bgp = bgp_lookup_by_vrf_id(ifp->vrf_id); + bgp = ifp->vrf->info; if (!bgp) return; @@ -611,7 +611,8 @@ void bgp_nht_ifp_down(struct interface *ifp) static int bgp_nht_ifp_initial(struct thread *thread) { ifindex_t ifindex = THREAD_VAL(thread); - struct interface *ifp = if_lookup_by_index_all_vrf(ifindex); + struct bgp *bgp = THREAD_ARG(thread); + struct interface *ifp = if_lookup_by_index(ifindex, bgp->vrf_id); if (!ifp) return 0; @@ -657,14 +658,14 @@ void bgp_nht_interface_events(struct peer *peer) return; if (bnc->ifindex) - thread_add_event(bm->master, bgp_nht_ifp_initial, NULL, + thread_add_event(bm->master, bgp_nht_ifp_initial, bnc->bgp, bnc->ifindex, NULL); } void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) { struct bgp_nexthop_cache_head *tree = NULL; - struct bgp_nexthop_cache *bnc; + struct bgp_nexthop_cache *bnc_nhc, *bnc_import; struct bgp *bgp; struct zapi_route nhr; afi_t afi; @@ -685,22 +686,38 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) } afi = family2afi(nhr.prefix.family); - if (command == ZEBRA_NEXTHOP_UPDATE) - tree = &bgp->nexthop_cache_table[afi]; - else if (command == ZEBRA_IMPORT_CHECK_UPDATE) - tree = &bgp->import_check_table[afi]; + tree = &bgp->nexthop_cache_table[afi]; - bnc = bnc_find(tree, &nhr.prefix, nhr.srte_color); - if (!bnc) { + bnc_nhc = bnc_find(tree, &nhr.prefix, nhr.srte_color); + if (!bnc_nhc) { if (BGP_DEBUG(nht, NHT)) zlog_debug( - "parse nexthop update(%pFX(%u)(%s)): bnc info not found", + "parse nexthop update(%pFX(%u)(%s)): bnc info not found for nexthop cache", + &nhr.prefix, nhr.srte_color, bgp->name_pretty); + } else + bgp_process_nexthop_update(bnc_nhc, &nhr); + + tree = &bgp->import_check_table[afi]; + + bnc_import = bnc_find(tree, &nhr.prefix, nhr.srte_color); + if (!bnc_import) { + if (BGP_DEBUG(nht, NHT)) + zlog_debug( + "parse nexthop update(%pFX(%u)(%s)): bnc info not found for import check", &nhr.prefix, nhr.srte_color, bgp->name_pretty); return; + } else { + if (nhr.type == ZEBRA_ROUTE_BGP + || !prefix_same(&bnc_import->prefix, &nhr.prefix)) { + if (BGP_DEBUG(nht, NHT)) + zlog_debug( + "%s: Import Check does not resolve to the same prefix for %pFX received %pFX", + __func__, &bnc_import->prefix, &nhr.prefix); + return; + } + bgp_process_nexthop_update(bnc_import, &nhr); } - bgp_process_nexthop_update(bnc, &nhr); - /* * HACK: if any BGP route is dependant on an SR-policy that doesn't * exist, zebra will never send NH updates relative to that policy. In @@ -712,12 +729,12 @@ void bgp_parse_nexthop_update(int command, vrf_id_t vrf_id) * which should provide a better infrastructure to solve this issue in * a more efficient and elegant way. */ - if (nhr.srte_color == 0) { + if (nhr.srte_color == 0 && bnc_nhc) { struct bgp_nexthop_cache *bnc_iter; frr_each (bgp_nexthop_cache, &bgp->nexthop_cache_table[afi], bnc_iter) { - if (!prefix_same(&bnc->prefix, &bnc_iter->prefix) + if (!prefix_same(&bnc_import->prefix, &bnc_iter->prefix) || bnc_iter->srte_color == 0 || CHECK_FLAG(bnc_iter->flags, BGP_NEXTHOP_VALID)) continue; @@ -843,6 +860,7 @@ static int make_prefix(int afi, struct bgp_path_info *pi, struct prefix *p) static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) { bool exact_match = false; + bool resolve_via_default = false; int ret; if (!zclient) @@ -863,11 +881,12 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) "%s: We have not connected yet, cannot send nexthops", __func__); } - if ((command == ZEBRA_NEXTHOP_REGISTER - || command == ZEBRA_IMPORT_ROUTE_REGISTER) - && (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED) - || CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH))) - exact_match = true; + if (command == ZEBRA_NEXTHOP_REGISTER) { + if (CHECK_FLAG(bnc->flags, BGP_NEXTHOP_CONNECTED)) + exact_match = true; + if (CHECK_FLAG(bnc->flags, BGP_STATIC_ROUTE_EXACT_MATCH)) + resolve_via_default = true; + } if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("%s: sending cmd %s for %pFX (vrf %s)", __func__, @@ -875,17 +894,16 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) bnc->bgp->name_pretty); ret = zclient_send_rnh(zclient, command, &bnc->prefix, exact_match, - bnc->bgp->vrf_id); - /* TBD: handle the failure */ - if (ret == ZCLIENT_SEND_FAILURE) + resolve_via_default, bnc->bgp->vrf_id); + if (ret == ZCLIENT_SEND_FAILURE) { flog_warn(EC_BGP_ZEBRA_SEND, "sendmsg_nexthop: zclient_send_message() failed"); + return; + } - if ((command == ZEBRA_NEXTHOP_REGISTER) - || (command == ZEBRA_IMPORT_ROUTE_REGISTER)) + if (command == ZEBRA_NEXTHOP_REGISTER) SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); - else if ((command == ZEBRA_NEXTHOP_UNREGISTER) - || (command == ZEBRA_IMPORT_ROUTE_UNREGISTER)) + else if (command == ZEBRA_NEXTHOP_UNREGISTER) UNSET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); return; } @@ -910,10 +928,7 @@ static void register_zebra_rnh(struct bgp_nexthop_cache *bnc, return; } - if (is_bgp_import_route) - sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_REGISTER); - else - sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER); + sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_REGISTER); } /** @@ -935,10 +950,7 @@ static void unregister_zebra_rnh(struct bgp_nexthop_cache *bnc, return; } - if (is_bgp_import_route) - sendmsg_zebra_rnh(bnc, ZEBRA_IMPORT_ROUTE_UNREGISTER); - else - sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER); + sendmsg_zebra_rnh(bnc, ZEBRA_NEXTHOP_UNREGISTER); } /** @@ -1287,12 +1299,11 @@ static void bgp_l3nhg_zebra_init(void) } -#define min(A, B) ((A) < (B) ? (A) : (B)) void bgp_l3nhg_init(void) { uint32_t id_max; - id_max = min(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024); + id_max = MIN(ZEBRA_NHG_PROTO_SPACING - 1, 16 * 1024); bf_init(bgp_nh_id_bitmap, id_max); bf_assign_zero_index(bgp_nh_id_bitmap); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index f1dfebdc1b..6bdefd0e9b 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -42,6 +42,66 @@ #include "bgpd/bgp_vty.h" #include "bgpd/bgp_memory.h" +static const struct message capcode_str[] = { + {CAPABILITY_CODE_MP, "MultiProtocol Extensions"}, + {CAPABILITY_CODE_REFRESH, "Route Refresh"}, + {CAPABILITY_CODE_ORF, "Cooperative Route Filtering"}, + {CAPABILITY_CODE_RESTART, "Graceful Restart"}, + {CAPABILITY_CODE_AS4, "4-octet AS number"}, + {CAPABILITY_CODE_ADDPATH, "AddPath"}, + {CAPABILITY_CODE_DYNAMIC, "Dynamic"}, + {CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding"}, + {CAPABILITY_CODE_DYNAMIC_OLD, "Dynamic (Old)"}, + {CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)"}, + {CAPABILITY_CODE_ORF_OLD, "ORF (Old)"}, + {CAPABILITY_CODE_FQDN, "FQDN"}, + {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"}, + {CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"}, + {CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart"}, + {0}}; + +/* Minimum sizes for length field of each cap (so not inc. the header) */ +static const size_t cap_minsizes[] = { + [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, + [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, + [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, + [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, + [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, + [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN, + [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, + [CAPABILITY_CODE_DYNAMIC_OLD] = CAPABILITY_CODE_DYNAMIC_LEN, + [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN, + [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, + [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN, + [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN, + [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, + [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, + [CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN, +}; + +/* value the capability must be a multiple of. + * 0-data capabilities won't be checked against this. + * Other capabilities whose data doesn't fall on convenient boundaries for this + * table should be set to 1. + */ +static const size_t cap_modsizes[] = { + [CAPABILITY_CODE_MP] = 4, + [CAPABILITY_CODE_REFRESH] = 1, + [CAPABILITY_CODE_ORF] = 1, + [CAPABILITY_CODE_RESTART] = 1, + [CAPABILITY_CODE_AS4] = 4, + [CAPABILITY_CODE_ADDPATH] = 4, + [CAPABILITY_CODE_DYNAMIC] = 1, + [CAPABILITY_CODE_DYNAMIC_OLD] = 1, + [CAPABILITY_CODE_ENHE] = 6, + [CAPABILITY_CODE_REFRESH_OLD] = 1, + [CAPABILITY_CODE_ORF_OLD] = 1, + [CAPABILITY_CODE_FQDN] = 1, + [CAPABILITY_CODE_ENHANCED_RR] = 1, + [CAPABILITY_CODE_EXT_MESSAGE] = 1, + [CAPABILITY_CODE_LLGR] = 1, +}; + /* BGP-4 Multiprotocol Extentions lead us to the complex world. We can negotiate remote peer supports extentions or not. But if remote-peer doesn't supports negotiation process itself. We would @@ -264,9 +324,9 @@ static int bgp_capability_mp(struct peer *peer, struct capability_header *hdr) bgp_capability_mp_data(s, &mpc); if (bgp_debug_neighbor_events(peer)) - zlog_debug("%s OPEN has MP_EXT CAP for afi/safi: %s/%s", - peer->host, iana_afi2str(mpc.afi), - iana_safi2str(mpc.safi)); + zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s", + peer->host, lookup_msg(capcode_str, hdr->code, NULL), + iana_afi2str(mpc.afi), iana_safi2str(mpc.safi)); /* Convert AFI, SAFI to internal values, check. */ if (bgp_map_afi_safi_iana2int(mpc.afi, mpc.safi, &afi, &safi)) @@ -466,8 +526,6 @@ static int bgp_capability_restart(struct peer *peer, peer->v_gr_restart = restart_flag_time; if (bgp_debug_neighbor_events(peer)) { - zlog_debug("%s OPEN has Graceful Restart capability", - peer->host); zlog_debug("%s Peer has%srestarted. Restart Time : %d", peer->host, CHECK_FLAG(peer->cap, PEER_CAP_RESTART_BIT_RCV) @@ -517,6 +575,53 @@ static int bgp_capability_restart(struct peer *peer, return 0; } +static int bgp_capability_llgr(struct peer *peer, + struct capability_header *caphdr) +{ + struct stream *s = BGP_INPUT(peer); + size_t end = stream_get_getp(s) + caphdr->length; + + SET_FLAG(peer->cap, PEER_CAP_LLGR_RCV); + + while (stream_get_getp(s) + 4 <= end) { + afi_t afi; + safi_t safi; + iana_afi_t pkt_afi = stream_getw(s); + iana_safi_t pkt_safi = stream_getc(s); + uint8_t flags = stream_getc(s); + uint32_t stale_time = stream_get3(s); + + if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi, &safi)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%s Addr-family %s/%s(afi/safi) not supported. Ignore the Long-lived Graceful Restart capability for this AFI/SAFI", + peer->host, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + } else if (!peer->afc[afi][safi] + || !CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_RCV)) { + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%s Addr-family %s/%s(afi/safi) not enabled. Ignore the Long-lived Graceful Restart capability", + peer->host, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi)); + } else { + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%s Addr-family %s/%s(afi/safi) Long-lived Graceful Restart capability stale time %u sec", + peer->host, iana_afi2str(pkt_afi), + iana_safi2str(pkt_safi), stale_time); + + peer->llgr[afi][safi].flags = flags; + peer->llgr[afi][safi].stale_time = + MIN(stale_time, peer->bgp->llgr_stale_time); + SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_LLGR_AF_RCV); + } + } + + return 0; +} + /* Unlike other capability parsing routines, this one returns 0 on error */ static as_t bgp_capability_as4(struct peer *peer, struct capability_header *hdr) { @@ -580,9 +685,10 @@ static int bgp_capability_addpath(struct peer *peer, if (bgp_debug_neighbor_events(peer)) zlog_debug( - "%s OPEN has AddPath CAP for afi/safi: %s/%s%s%s", - peer->host, iana_afi2str(pkt_afi), - iana_safi2str(pkt_safi), + "%s OPEN has %s capability for afi/safi: %s/%s%s%s", + peer->host, + lookup_msg(capcode_str, hdr->code, NULL), + iana_afi2str(pkt_afi), iana_safi2str(pkt_safi), (send_receive & BGP_ADDPATH_RX) ? ", receive" : "", (send_receive & BGP_ADDPATH_TX) ? ", transmit" @@ -763,63 +869,6 @@ static int bgp_capability_hostname(struct peer *peer, return 0; } -static const struct message capcode_str[] = { - {CAPABILITY_CODE_MP, "MultiProtocol Extensions"}, - {CAPABILITY_CODE_REFRESH, "Route Refresh"}, - {CAPABILITY_CODE_ORF, "Cooperative Route Filtering"}, - {CAPABILITY_CODE_RESTART, "Graceful Restart"}, - {CAPABILITY_CODE_AS4, "4-octet AS number"}, - {CAPABILITY_CODE_ADDPATH, "AddPath"}, - {CAPABILITY_CODE_DYNAMIC, "Dynamic"}, - {CAPABILITY_CODE_ENHE, "Extended Next Hop Encoding"}, - {CAPABILITY_CODE_DYNAMIC_OLD, "Dynamic (Old)"}, - {CAPABILITY_CODE_REFRESH_OLD, "Route Refresh (Old)"}, - {CAPABILITY_CODE_ORF_OLD, "ORF (Old)"}, - {CAPABILITY_CODE_FQDN, "FQDN"}, - {CAPABILITY_CODE_ENHANCED_RR, "Enhanced Route Refresh"}, - {CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"}, - {0}}; - -/* Minimum sizes for length field of each cap (so not inc. the header) */ -static const size_t cap_minsizes[] = { - [CAPABILITY_CODE_MP] = CAPABILITY_CODE_MP_LEN, - [CAPABILITY_CODE_REFRESH] = CAPABILITY_CODE_REFRESH_LEN, - [CAPABILITY_CODE_ORF] = CAPABILITY_CODE_ORF_LEN, - [CAPABILITY_CODE_RESTART] = CAPABILITY_CODE_RESTART_LEN, - [CAPABILITY_CODE_AS4] = CAPABILITY_CODE_AS4_LEN, - [CAPABILITY_CODE_ADDPATH] = CAPABILITY_CODE_ADDPATH_LEN, - [CAPABILITY_CODE_DYNAMIC] = CAPABILITY_CODE_DYNAMIC_LEN, - [CAPABILITY_CODE_DYNAMIC_OLD] = CAPABILITY_CODE_DYNAMIC_LEN, - [CAPABILITY_CODE_ENHE] = CAPABILITY_CODE_ENHE_LEN, - [CAPABILITY_CODE_REFRESH_OLD] = CAPABILITY_CODE_REFRESH_LEN, - [CAPABILITY_CODE_ORF_OLD] = CAPABILITY_CODE_ORF_LEN, - [CAPABILITY_CODE_FQDN] = CAPABILITY_CODE_MIN_FQDN_LEN, - [CAPABILITY_CODE_ENHANCED_RR] = CAPABILITY_CODE_ENHANCED_LEN, - [CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN, -}; - -/* value the capability must be a multiple of. - * 0-data capabilities won't be checked against this. - * Other capabilities whose data doesn't fall on convenient boundaries for this - * table should be set to 1. - */ -static const size_t cap_modsizes[] = { - [CAPABILITY_CODE_MP] = 4, - [CAPABILITY_CODE_REFRESH] = 1, - [CAPABILITY_CODE_ORF] = 1, - [CAPABILITY_CODE_RESTART] = 1, - [CAPABILITY_CODE_AS4] = 4, - [CAPABILITY_CODE_ADDPATH] = 4, - [CAPABILITY_CODE_DYNAMIC] = 1, - [CAPABILITY_CODE_DYNAMIC_OLD] = 1, - [CAPABILITY_CODE_ENHE] = 6, - [CAPABILITY_CODE_REFRESH_OLD] = 1, - [CAPABILITY_CODE_ORF_OLD] = 1, - [CAPABILITY_CODE_FQDN] = 1, - [CAPABILITY_CODE_ENHANCED_RR] = 1, - [CAPABILITY_CODE_EXT_MESSAGE] = 1, -}; - /** * Parse given capability. * XXX: This is reading into a stream, but not using stream API @@ -955,6 +1004,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length, case CAPABILITY_CODE_RESTART: ret = bgp_capability_restart(peer, &caphdr); break; + case CAPABILITY_CODE_LLGR: + ret = bgp_capability_llgr(peer, &caphdr); + break; case CAPABILITY_CODE_DYNAMIC: case CAPABILITY_CODE_DYNAMIC_OLD: SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV); @@ -1046,7 +1098,7 @@ static bool strict_capability_same(struct peer *peer) /* peek into option, stores ASN to *as4 if the AS4 capability was found. * Returns 0 if no as4 found, as4cap value otherwise. */ -as_t peek_for_as4_capability(struct peer *peer, uint8_t length) +as_t peek_for_as4_capability(struct peer *peer, uint16_t length) { struct stream *s = BGP_INPUT(peer); size_t orig_getp = stream_get_getp(s); @@ -1062,7 +1114,7 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length) */ while (stream_get_getp(s) < end) { uint8_t opt_type; - uint8_t opt_length; + uint16_t opt_length; /* Check the length. */ if (stream_get_getp(s) + 2 > end) @@ -1070,7 +1122,9 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length) /* Fetch option type and length. */ opt_type = stream_getc(s); - opt_length = stream_getc(s); + opt_length = BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer) + ? stream_getw(s) + : stream_getc(s); /* Option length check. */ if (stream_get_getp(s) + opt_length > end) @@ -1118,7 +1172,8 @@ end: * * @param[out] mp_capability @see bgp_capability_parse() for semantics. */ -int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability) +int bgp_open_option_parse(struct peer *peer, uint16_t length, + int *mp_capability) { int ret = 0; uint8_t *error; @@ -1137,7 +1192,7 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability) while (stream_get_getp(s) < end) { uint8_t opt_type; - uint8_t opt_length; + uint16_t opt_length; /* Must have at least an OPEN option header */ if (STREAM_READABLE(s) < 2) { @@ -1149,11 +1204,14 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability) /* Fetch option type and length. */ opt_type = stream_getc(s); - opt_length = stream_getc(s); + opt_length = BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer) + ? stream_getw(s) + : stream_getc(s); /* Option length check. */ if (STREAM_READABLE(s) < opt_length) { - zlog_info("%s Option length error", peer->host); + zlog_info("%s Option length error (%d)", peer->host, + opt_length); bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return -1; @@ -1257,9 +1315,10 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability) } static void bgp_open_capability_orf(struct stream *s, struct peer *peer, - afi_t afi, safi_t safi, uint8_t code) + afi_t afi, safi_t safi, uint8_t code, + bool ext_opt_params) { - uint8_t cap_len; + uint16_t cap_len; uint8_t orf_len; unsigned long capp; unsigned long orfp; @@ -1273,7 +1332,8 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer, stream_putc(s, BGP_OPEN_OPT_CAP); capp = stream_get_endp(s); /* Set Capability Len Pointer */ - stream_putc(s, 0); /* Capability Length */ + ext_opt_params ? stream_putw(s, 0) + : stream_putc(s, 0); /* Capability Length */ stream_putc(s, code); /* Capability Code */ orfp = stream_get_endp(s); /* Set ORF Len Pointer */ stream_putc(s, 0); /* ORF Length */ @@ -1321,11 +1381,12 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer, /* Total Capability Len. */ cap_len = stream_get_endp(s) - capp - 1; - stream_putc_at(s, capp, cap_len); + ext_opt_params ? stream_putw_at(s, capp, cap_len) + : stream_putc_at(s, capp, cap_len); } static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, - unsigned long cp) + bool ext_opt_params) { int len; iana_afi_t pkt_afi; @@ -1347,7 +1408,8 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); capp = stream_get_endp(s); /* Set Capability Len Pointer */ - stream_putc(s, 0); /* Capability Length */ + ext_opt_params ? stream_putw(s, 0) + : stream_putc(s, 0); /* Capability Length */ stream_putc(s, CAPABILITY_CODE_RESTART); /* Set Restart Capability Len Pointer */ rcapp = stream_get_endp(s); @@ -1402,14 +1464,65 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer, /* Total Capability Len. */ len = stream_get_endp(s) - capp - 1; - stream_putc_at(s, capp, len); + ext_opt_params ? stream_putw_at(s, capp, len - 1) + : stream_putc_at(s, capp, len); +} + +static void bgp_peer_send_llgr_capability(struct stream *s, struct peer *peer, + bool ext_opt_params) +{ + int len; + iana_afi_t pkt_afi; + afi_t afi; + safi_t safi; + iana_safi_t pkt_safi; + unsigned long capp = 0; + unsigned long rcapp = 0; + + if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV)) + return; + + SET_FLAG(peer->cap, PEER_CAP_LLGR_ADV); + + stream_putc(s, BGP_OPEN_OPT_CAP); + capp = stream_get_endp(s); /* Set Capability Len Pointer */ + ext_opt_params ? stream_putw(s, 0) + : stream_putc(s, 0); /* Capability Length */ + stream_putc(s, CAPABILITY_CODE_LLGR); + + rcapp = stream_get_endp(s); + stream_putc(s, 0); + + FOREACH_AFI_SAFI (afi, safi) { + if (!peer->afc[afi][safi]) + continue; + + bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi, &pkt_safi); + + stream_putw(s, pkt_afi); + stream_putc(s, pkt_safi); + stream_putc(s, LLGR_F_BIT); + stream_put3(s, peer->bgp->llgr_stale_time); + + SET_FLAG(peer->af_cap[afi][safi], PEER_CAP_LLGR_AF_ADV); + } + + /* Total Long-lived Graceful Restart capability Len. */ + len = stream_get_endp(s) - rcapp - 1; + stream_putc_at(s, rcapp, len); + + /* Total Capability Len. */ + len = stream_get_endp(s) - capp - 1; + ext_opt_params ? stream_putw_at(s, capp, len - 1) + : stream_putc_at(s, capp, len); } /* Fill in capability open option to the packet. */ -void bgp_open_capability(struct stream *s, struct peer *peer) +uint16_t bgp_open_capability(struct stream *s, struct peer *peer, + bool ext_opt_params) { - uint8_t len; - unsigned long cp, capp, rcapp; + uint16_t len; + unsigned long cp, capp, rcapp, eopl = 0; iana_afi_t pkt_afi; afi_t afi; safi_t safi; @@ -1418,16 +1531,26 @@ void bgp_open_capability(struct stream *s, struct peer *peer) uint8_t afi_safi_count = 0; int adv_addpath_tx = 0; - /* Remember current pointer for Opt Parm Len. */ + /* Non-Ext OP Len. */ cp = stream_get_endp(s); - - /* Opt Parm Len. */ stream_putc(s, 0); + if (ext_opt_params) { + /* Non-Ext OP Len. */ + stream_putc_at(s, cp, BGP_OPEN_NON_EXT_OPT_LEN); + + /* Non-Ext OP Type */ + stream_putc(s, BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH); + + /* Extended Opt. Parm. Length */ + eopl = stream_get_endp(s); + stream_putw(s, 0); + } + /* Do not send capability. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN) || CHECK_FLAG(peer->flags, PEER_FLAG_DONT_CAPABILITY)) - return; + return 0; /* MP capability for configured AFI, SAFI */ FOREACH_AFI_SAFI (afi, safi) { @@ -1438,7 +1561,9 @@ void bgp_open_capability(struct stream *s, struct peer *peer) peer->afc_adv[afi][safi] = 1; stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, CAPABILITY_CODE_MP_LEN + 2); + ext_opt_params + ? stream_putw(s, CAPABILITY_CODE_MP_LEN + 2) + : stream_putc(s, CAPABILITY_CODE_MP_LEN + 2); stream_putc(s, CAPABILITY_CODE_MP); stream_putc(s, CAPABILITY_CODE_MP_LEN); stream_putw(s, pkt_afi); @@ -1458,7 +1583,13 @@ void bgp_open_capability(struct stream *s, struct peer *peer) */ SET_FLAG(peer->cap, PEER_CAP_ENHE_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, CAPABILITY_CODE_ENHE_LEN + 2); + ext_opt_params + ? stream_putw(s, + CAPABILITY_CODE_ENHE_LEN + + 2) + : stream_putc(s, + CAPABILITY_CODE_ENHE_LEN + + 2); stream_putc(s, CAPABILITY_CODE_ENHE); stream_putc(s, CAPABILITY_CODE_ENHE_LEN); @@ -1479,25 +1610,29 @@ void bgp_open_capability(struct stream *s, struct peer *peer) /* Route refresh. */ SET_FLAG(peer->cap, PEER_CAP_REFRESH_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2); + ext_opt_params ? stream_putw(s, CAPABILITY_CODE_REFRESH_LEN + 2) + : stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2); stream_putc(s, CAPABILITY_CODE_REFRESH_OLD); stream_putc(s, CAPABILITY_CODE_REFRESH_LEN); stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2); + ext_opt_params ? stream_putw(s, CAPABILITY_CODE_REFRESH_LEN + 2) + : stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2); stream_putc(s, CAPABILITY_CODE_REFRESH); stream_putc(s, CAPABILITY_CODE_REFRESH_LEN); /* Enhanced Route Refresh. */ SET_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN + 2); + ext_opt_params ? stream_putw(s, CAPABILITY_CODE_ENHANCED_LEN + 2) + : stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN + 2); stream_putc(s, CAPABILITY_CODE_ENHANCED_RR); stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN); /* AS4 */ SET_FLAG(peer->cap, PEER_CAP_AS4_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, CAPABILITY_CODE_AS4_LEN + 2); + ext_opt_params ? stream_putw(s, CAPABILITY_CODE_AS4_LEN + 2) + : stream_putc(s, CAPABILITY_CODE_AS4_LEN + 2); stream_putc(s, CAPABILITY_CODE_AS4); stream_putc(s, CAPABILITY_CODE_AS4_LEN); if (peer->change_local_as) @@ -1509,7 +1644,8 @@ void bgp_open_capability(struct stream *s, struct peer *peer) /* Extended Message Support */ SET_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2); + ext_opt_params ? stream_putw(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2) + : stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2); stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE); stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN); @@ -1528,7 +1664,11 @@ void bgp_open_capability(struct stream *s, struct peer *peer) SET_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count) + 2); + ext_opt_params + ? stream_putw(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count) + + 2) + : stream_putc(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count) + + 2); stream_putc(s, CAPABILITY_CODE_ADDPATH); stream_putc(s, CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count); @@ -1575,9 +1715,11 @@ void bgp_open_capability(struct stream *s, struct peer *peer) || CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_ORF_PREFIX_RM)) { bgp_open_capability_orf(s, peer, afi, safi, - CAPABILITY_CODE_ORF_OLD); + CAPABILITY_CODE_ORF_OLD, + ext_opt_params); bgp_open_capability_orf(s, peer, afi, safi, - CAPABILITY_CODE_ORF); + CAPABILITY_CODE_ORF, + ext_opt_params); } } @@ -1585,11 +1727,15 @@ void bgp_open_capability(struct stream *s, struct peer *peer) if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) { SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2); + ext_opt_params + ? stream_putw(s, CAPABILITY_CODE_DYNAMIC_LEN + 2) + : stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2); stream_putc(s, CAPABILITY_CODE_DYNAMIC_OLD); stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN); stream_putc(s, BGP_OPEN_OPT_CAP); - stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2); + ext_opt_params + ? stream_putw(s, CAPABILITY_CODE_DYNAMIC_LEN + 2) + : stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2); stream_putc(s, CAPABILITY_CODE_DYNAMIC); stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN); } @@ -1599,7 +1745,8 @@ void bgp_open_capability(struct stream *s, struct peer *peer) SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV); stream_putc(s, BGP_OPEN_OPT_CAP); rcapp = stream_get_endp(s); /* Ptr to length placeholder */ - stream_putc(s, 0); /* dummy len for now */ + ext_opt_params ? stream_putw(s, 0) + : stream_putc(s, 0); /* Capability Length */ stream_putc(s, CAPABILITY_CODE_FQDN); capp = stream_get_endp(s); stream_putc(s, 0); /* dummy len for now */ @@ -1621,7 +1768,9 @@ void bgp_open_capability(struct stream *s, struct peer *peer) /* Set the lengths straight */ len = stream_get_endp(s) - rcapp - 1; - stream_putc_at(s, rcapp, len); + ext_opt_params ? stream_putw_at(s, rcapp, len - 1) + : stream_putc_at(s, rcapp, len); + len = stream_get_endp(s) - capp - 1; stream_putc_at(s, capp, len); @@ -1632,9 +1781,18 @@ void bgp_open_capability(struct stream *s, struct peer *peer) cmd_domainname_get()); } - bgp_peer_send_gr_capability(s, peer, cp); + bgp_peer_send_gr_capability(s, peer, ext_opt_params); + bgp_peer_send_llgr_capability(s, peer, ext_opt_params); /* Total Opt Parm Len. */ len = stream_get_endp(s) - cp - 1; - stream_putc_at(s, cp, len); + + if (ext_opt_params) { + len = stream_get_endp(s) - eopl - 2; + stream_putw_at(s, eopl, len); + } else { + stream_putc_at(s, cp, len); + } + + return len; } diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h index bc6eedac85..c04816c006 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -50,6 +50,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_DYNAMIC 67 /* Dynamic Capability */ #define CAPABILITY_CODE_ADDPATH 69 /* Addpath Capability */ #define CAPABILITY_CODE_ENHANCED_RR 70 /* Enhanced Route Refresh capability */ +#define CAPABILITY_CODE_LLGR 71 /* Long-lived Graceful Restart */ #define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capability */ #define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */ #define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */ @@ -66,6 +67,7 @@ struct graceful_restart_af { #define CAPABILITY_CODE_ENHE_LEN 6 /* NRLI AFI = 2, SAFI = 2, Nexthop AFI = 2 */ #define CAPABILITY_CODE_MIN_FQDN_LEN 2 #define CAPABILITY_CODE_ENHANCED_LEN 0 +#define CAPABILITY_CODE_LLGR_LEN 0 #define CAPABILITY_CODE_ORF_LEN 5 #define CAPABILITY_CODE_EXT_MESSAGE_LEN 0 /* Extended Message Support */ @@ -88,10 +90,22 @@ struct graceful_restart_af { #define RESTART_R_BIT 0x8000 #define RESTART_F_BIT 0x80 -extern int bgp_open_option_parse(struct peer *, uint8_t, int *); -extern void bgp_open_capability(struct stream *, struct peer *); +/* Long-lived Graceful Restart */ +#define LLGR_F_BIT 0x80 + +/* Optional Parameters */ +#define BGP_OPEN_NON_EXT_OPT_LEN 255 /* Non-Ext OP Len. */ +#define BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH 255 /* Non-Ext OP Type */ +#define BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer) \ + (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS) \ + || CHECK_FLAG(peer->sflags, PEER_STATUS_EXT_OPT_PARAMS_LENGTH)) + +extern int bgp_open_option_parse(struct peer *peer, uint16_t length, + int *mp_capability); +extern uint16_t bgp_open_capability(struct stream *s, struct peer *peer, + bool ext_opt_params); extern void bgp_capability_vty_out(struct vty *vty, struct peer *peer, bool use_json, json_object *json_neigh); -extern as_t peek_for_as4_capability(struct peer *, uint8_t); +extern as_t peek_for_as4_capability(struct peer *peer, uint16_t length); #endif /* _QUAGGA_BGP_OPEN_H */ diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index de9a89523b..4bb08404d6 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -106,17 +106,14 @@ int bgp_packet_set_marker(struct stream *s, uint8_t type) * Size field is set to the size of the stream passed. * * @param s the stream containing the packet - * @return the size of the stream */ -int bgp_packet_set_size(struct stream *s) +void bgp_packet_set_size(struct stream *s) { int cp; /* Preserve current pointer. */ cp = stream_get_endp(s); stream_putw_at(s, BGP_MARKER_SIZE, cp); - - return cp; } /* @@ -561,7 +558,7 @@ void bgp_keepalive_send(struct peer *peer) bgp_packet_set_marker(s, BGP_MSG_KEEPALIVE); /* Set packet size. */ - (void)bgp_packet_set_size(s); + bgp_packet_set_size(s); /* Dump packet if debug option is set. */ /* bgp_packet_dump (s); */ @@ -608,11 +605,25 @@ void bgp_open_send(struct peer *peer) stream_putw(s, send_holdtime); /* Hold Time */ stream_put_in_addr(s, &peer->local_id); /* BGP Identifier */ - /* Set capability code. */ - bgp_open_capability(s, peer); + /* Set capabilities */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) { + (void)bgp_open_capability(s, peer, true); + } 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) { + stream_free(tmp); + (void)bgp_open_capability(s, peer, true); + } else { + stream_copy(s, tmp); + stream_free(tmp); + } + } /* Set BGP packet length. */ - (void)bgp_packet_set_size(s); + bgp_packet_set_size(s); if (bgp_debug_neighbor_events(peer)) zlog_debug( @@ -939,7 +950,7 @@ void bgp_route_refresh_send(struct peer *peer, afi_t afi, safi_t safi, } /* Set packet size. */ - (void)bgp_packet_set_size(s); + bgp_packet_set_size(s); if (bgp_debug_neighbor_events(peer)) { if (!orf_refresh) @@ -997,7 +1008,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi, } /* Set packet size. */ - (void)bgp_packet_set_size(s); + bgp_packet_set_size(s); /* Add packet to the peer. */ bgp_packet_add(peer, s); @@ -1136,7 +1147,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) { int ret; uint8_t version; - uint8_t optlen; + uint16_t optlen; uint16_t holdtime; uint16_t send_holdtime; as_t remote_as; @@ -1157,19 +1168,40 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) memcpy(notify_data_remote_id, stream_pnt(peer->curr), 4); remote_id.s_addr = stream_get_ipv4(peer->curr); - /* Receive OPEN message log */ - if (bgp_debug_neighbor_events(peer)) - zlog_debug( - "%s rcv OPEN, version %d, remote-as (in open) %u, holdtime %d, id %pI4", - peer->host, version, remote_as, holdtime, &remote_id); - /* BEGIN to read the capability here, but dont do it yet */ mp_capability = 0; optlen = stream_getc(peer->curr); + /* 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)) { + uint8_t opttype; + + opttype = stream_getc(peer->curr); + if (opttype == BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH) { + optlen = stream_getw(peer->curr); + SET_FLAG(peer->sflags, + PEER_STATUS_EXT_OPT_PARAMS_LENGTH); + } + } + + /* Receive OPEN message log */ + if (bgp_debug_neighbor_events(peer)) + zlog_debug( + "%s rcv OPEN%s, version %d, remote-as (in open) %u, holdtime %d, id %pI4", + peer->host, + CHECK_FLAG(peer->sflags, + PEER_STATUS_EXT_OPT_PARAMS_LENGTH) + ? " (Extended)" + : "", + version, remote_as, holdtime, &remote_id); + if (optlen != 0) { /* If not enough bytes, it is an error. */ if (STREAM_READABLE(peer->curr) < optlen) { + flog_err(EC_BGP_PKT_OPEN, + "%s: stream has not enough bytes (%u)", + peer->host, optlen); bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR, BGP_NOTIFY_OPEN_MALFORMED_ATTR); return BGP_Stop; @@ -1837,11 +1869,11 @@ static int bgp_update_receive(struct peer *peer, bgp_size_t size) if (peer->nsf[afi][safi]) bgp_clear_stale_route(peer, afi, safi); - zlog_info( - "%s: rcvd End-of-RIB for %s from %s in vrf %s", - __func__, get_afi_safi_str(afi, safi, false), - peer->host, vrf ? vrf->name : VRF_DEFAULT_NAME); - } + zlog_info( + "%s: rcvd End-of-RIB for %s from %s in vrf %s", + __func__, get_afi_safi_str(afi, safi, false), + peer->host, vrf ? vrf->name : VRF_DEFAULT_NAME); + } } /* Everything is done. We unintern temporary structures which diff --git a/bgpd/bgp_packet.h b/bgpd/bgp_packet.h index d69c862304..280d3ec174 100644 --- a/bgpd/bgp_packet.h +++ b/bgpd/bgp_packet.h @@ -77,7 +77,7 @@ extern void bgp_update_implicit_eors(struct peer *); extern void bgp_check_update_delay(struct bgp *); extern int bgp_packet_set_marker(struct stream *s, uint8_t type); -extern int bgp_packet_set_size(struct stream *s); +extern void bgp_packet_set_size(struct stream *s); extern int bgp_generate_updgrp_packets(struct thread *); extern int bgp_process_packet(struct thread *); diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 0eb3cc61e3..3836d5f24b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -102,6 +102,10 @@ DEFINE_HOOK(bgp_rpki_prefix_status, const struct prefix *prefix), (peer, attr, prefix)); +/* Render dest to prefix_rd based on safi */ +static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, + safi_t safi); + /* Extern from bgp_dump.c */ extern const char *bgp_origin_str[]; extern const char *bgp_origin_long_str[]; @@ -303,22 +307,10 @@ struct bgp_path_info *bgp_path_info_unlock(struct bgp_path_info *path) path->lock--; if (path->lock == 0) { -#if 0 - zlog_debug ("%s: unlocked and freeing", __func__); - zlog_backtrace (LOG_DEBUG); -#endif bgp_path_info_free(path); return NULL; } -#if 0 - if (path->lock == 1) - { - zlog_debug ("%s: unlocked to 1", __func__); - zlog_backtrace (LOG_DEBUG); - } -#endif - return path; } @@ -544,6 +536,25 @@ void bgp_path_info_path_with_addpath_rx_str(struct bgp_path_info *pi, char *buf, snprintf(buf, buf_len, "path %s", pi->peer->host); } + +/* + * Get the ultimate path info. + */ +struct bgp_path_info *bgp_get_imported_bpi_ultimate(struct bgp_path_info *info) +{ + struct bgp_path_info *bpi_ultimate; + + if (info->sub_type != BGP_ROUTE_IMPORTED) + return info; + + for (bpi_ultimate = info; + bpi_ultimate->extra && bpi_ultimate->extra->parent; + bpi_ultimate = bpi_ultimate->extra->parent) + ; + + return bpi_ultimate; +} + /* Compare two bgp route entity. If 'new' is preferable over 'exist' return 1. */ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, @@ -583,6 +594,7 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, bool old_proxy; bool new_proxy; bool new_origin, exist_origin; + struct bgp_path_info *bpi_ultimate; *paths_eq = 0; @@ -594,29 +606,59 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 0; } - if (debug) - bgp_path_info_path_with_addpath_rx_str(new, new_buf, + if (debug) { + bpi_ultimate = bgp_get_imported_bpi_ultimate(new); + bgp_path_info_path_with_addpath_rx_str(bpi_ultimate, new_buf, sizeof(new_buf)); + } if (exist == NULL) { *reason = bgp_path_selection_first; if (debug) - zlog_debug("%s: %s is the initial bestpath", pfx_buf, - new_buf); + zlog_debug("%s(%s): %s is the initial bestpath", + pfx_buf, bgp->name_pretty, new_buf); return 1; } if (debug) { - bgp_path_info_path_with_addpath_rx_str(exist, exist_buf, + bpi_ultimate = bgp_get_imported_bpi_ultimate(exist); + bgp_path_info_path_with_addpath_rx_str(bpi_ultimate, exist_buf, sizeof(exist_buf)); - zlog_debug("%s: Comparing %s flags 0x%x with %s flags 0x%x", - pfx_buf, new_buf, new->flags, exist_buf, - exist->flags); + zlog_debug("%s(%s): Comparing %s flags 0x%x with %s flags 0x%x", + pfx_buf, bgp->name_pretty, new_buf, new->flags, + exist_buf, exist->flags); } newattr = new->attr; existattr = exist->attr; + /* A BGP speaker that has advertised the "Long-lived Graceful Restart + * Capability" to a neighbor MUST perform the following upon receiving + * a route from that neighbor with the "LLGR_STALE" community, or upon + * attaching the "LLGR_STALE" community itself per Section 4.2: + * + * Treat the route as the least-preferred in route selection (see + * below). See the Risks of Depreferencing Routes section (Section 5.2) + * for a discussion of potential risks inherent in doing this. + */ + if (newattr->community && + community_include(newattr->community, COMMUNITY_LLGR_STALE)) { + if (debug) + zlog_debug( + "%s: %s wins over %s due to LLGR_STALE community", + pfx_buf, new_buf, exist_buf); + return 0; + } + + if (existattr->community && + community_include(existattr->community, COMMUNITY_LLGR_STALE)) { + if (debug) + zlog_debug( + "%s: %s loses to %s due to LLGR_STALE community", + pfx_buf, new_buf, exist_buf); + return 1; + } + new_p = bgp_dest_get_prefix(new->net); /* For EVPN routes, we cannot just go by local vs remote, we have to @@ -855,6 +897,14 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, return 0; } + /* Here if these are imported routes then get ultimate pi for + * path compare. + */ + new = bgp_get_imported_bpi_ultimate(new); + exist = bgp_get_imported_bpi_ultimate(exist); + newattr = new->attr; + existattr = exist->attr; + /* 4. AS path length check. */ if (!CHECK_FLAG(bgp->flags, BGP_FLAG_ASPATH_IGNORE)) { int exist_hops = aspath_count_hops(existattr->aspath); @@ -1685,6 +1735,36 @@ static void bgp_peer_as_override(struct bgp *bgp, afi_t afi, safi_t safi, } } +void bgp_attr_add_llgr_community(struct attr *attr) +{ + struct community *old; + struct community *new; + struct community *merge; + struct community *llgr; + + old = attr->community; + llgr = community_str2com("llgr-stale"); + + assert(llgr); + + if (old) { + merge = community_merge(community_dup(old), llgr); + + if (old->refcnt == 0) + community_free(&old); + + new = community_uniq_sort(merge); + community_free(&merge); + } else { + new = community_dup(llgr); + } + + community_free(&llgr); + + attr->community = new; + attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_COMMUNITIES); +} + void bgp_attr_add_gshut_community(struct attr *attr) { struct community *old; @@ -2054,7 +2134,7 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, if ((CHECK_FLAG(peer->af_flags[afi][safi], PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED) && IN6_IS_ADDR_LINKLOCAL(&attr->mp_nexthop_local)) - || (!reflect + || (!reflect && !transparent && IN6_IS_ADDR_LINKLOCAL(&peer->nexthop.v6_local) && peer->shared_network && (from == bgp->peer_self @@ -2160,6 +2240,20 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi, } } + /* A BGP speaker that has advertised the "Long-lived Graceful Restart + * Capability" to a neighbor MUST perform the following upon receiving + * a route from that neighbor with the "LLGR_STALE" community, or upon + * attaching the "LLGR_STALE" community itself per Section 4.2: + * + * The route SHOULD NOT be advertised to any neighbor from which the + * Long-lived Graceful Restart Capability has not been received. + */ + if (attr->community && + community_include(attr->community, COMMUNITY_LLGR_STALE) && + !CHECK_FLAG(peer->cap, PEER_CAP_LLGR_RCV) && + !CHECK_FLAG(peer->cap, PEER_CAP_LLGR_ADV)) + return false; + /* After route-map has been applied, we check to see if the nexthop to * be carried in the attribute (that is used for the announcement) can * be cleared off or not. We do this in all cases where we would be @@ -2400,8 +2494,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, bgp_path_info_path_with_addpath_rx_str( new_select, path_buf, sizeof(path_buf)); zlog_debug( - "%pBD: %s is the bestpath from AS %u", - dest, path_buf, + "%pBD(%s): %s is the bestpath from AS %u", + dest, bgp->name_pretty, path_buf, aspath_get_first_as( new_select->attr->aspath)); } @@ -2477,8 +2571,8 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, else snprintf(path_buf, sizeof(path_buf), "NONE"); zlog_debug( - "%pBD: After path selection, newbest is %s oldbest was %s", - dest, path_buf, + "%pBD(%s): After path selection, newbest is %s oldbest was %s", + dest, bgp->name_pretty, path_buf, old_select ? old_select->peer->host : "NONE"); } @@ -2493,8 +2587,9 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, if (pi == new_select) { if (debug) zlog_debug( - "%pBD: %s is the bestpath, add to the multipath list", - dest, path_buf); + "%pBD(%s): %s is the bestpath, add to the multipath list", + dest, bgp->name_pretty, + path_buf); bgp_mp_list_add(&mp_list, pi); continue; } @@ -2530,7 +2625,7 @@ void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, } } - bgp_path_info_mpath_update(dest, new_select, old_select, &mp_list, + bgp_path_info_mpath_update(bgp, dest, new_select, old_select, &mp_list, mpath_cfg); bgp_path_info_mpath_aggregate_update(new_select, old_select); bgp_mp_list_clear(&mp_list); @@ -2591,9 +2686,14 @@ void subgroup_process_announce_selected(struct update_subgroup *subgrp, /* Route is selected, if the route is already installed * in FIB, then it is advertised */ - if (advertise) - bgp_adj_out_set_subgroup(dest, subgrp, &attr, - selected); + if (advertise) { + if (!bgp_check_withdrawal(bgp, dest)) + bgp_adj_out_set_subgroup( + dest, subgrp, &attr, selected); + else + bgp_adj_out_unset_subgroup( + dest, subgrp, 1, addpath_tx_id); + } } else bgp_adj_out_unset_subgroup(dest, subgrp, 1, addpath_tx_id); @@ -2712,6 +2812,28 @@ static void bgp_process_evpn_route_injection(struct bgp *bgp, afi_t afi, } /* + * Utility to determine whether a particular path_info should use + * the IMPLICIT_NULL label. This is pretty specialized: it's only called + * in a path where we basically _know_ this is a BGP-LU route. + */ +static bool bgp_lu_need_imp_null(const struct bgp_path_info *new_select) +{ + /* Certain types get imp null; so do paths where the nexthop is + * not labeled. + */ + if (new_select->sub_type == BGP_ROUTE_STATIC + || new_select->sub_type == BGP_ROUTE_AGGREGATE + || new_select->sub_type == BGP_ROUTE_REDISTRIBUTE) + return true; + else if (new_select->extra == NULL || + !bgp_is_valid_label(&new_select->extra->label[0])) + /* TODO -- should be configurable? */ + return true; + else + return false; +} + +/* * old_select = The old best path * new_select = the new best path * @@ -2749,8 +2871,8 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, } /* Is it end of initial update? (after startup) */ if (!dest) { - quagga_timestamp(3, bgp->update_delay_zebra_resume_time, - sizeof(bgp->update_delay_zebra_resume_time)); + frr_timestamp(3, bgp->update_delay_zebra_resume_time, + sizeof(bgp->update_delay_zebra_resume_time)); bgp->main_zebra_update_hold = 0; FOREACH_AFI_SAFI (afi, safi) { @@ -2767,8 +2889,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, debug = bgp_debug_bestpath(dest); if (debug) - zlog_debug("%s: p=%pBD afi=%s, safi=%s start", __func__, dest, - afi2str(afi), safi2str(safi)); + zlog_debug("%s: p=%pBDi(%s) afi=%s, safi=%s start", __func__, + dest, bgp->name_pretty, afi2str(afi), + safi2str(safi)); /* The best path calculation for the route is deferred if * BGP_NODE_SELECT_DEFER is set @@ -2802,11 +2925,7 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, * implicit-null for local routes, aggregate * and redistributed routes */ - if (new_select->sub_type == BGP_ROUTE_STATIC - || new_select->sub_type - == BGP_ROUTE_AGGREGATE - || new_select->sub_type - == BGP_ROUTE_REDISTRIBUTE) { + if (bgp_lu_need_imp_null(new_select)) { if (CHECK_FLAG( dest->flags, BGP_NODE_REGISTERED_FOR_LABEL) @@ -2834,9 +2953,9 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, if (debug) zlog_debug( - "%s: p=%pBD afi=%s, safi=%s, old_select=%p, new_select=%p", - __func__, dest, afi2str(afi), safi2str(safi), - old_select, new_select); + "%s: p=%pBD(%s) afi=%s, safi=%s, old_select=%p, new_select=%p", + __func__, dest, bgp->name_pretty, afi2str(afi), + safi2str(safi), old_select, new_select); /* If best route remains the same and this is not due to user-initiated * clear, see exactly what needs to be done. @@ -2853,6 +2972,11 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, if (bgp_fibupd_safi(safi) && !bgp_option_check(BGP_OPT_NO_FIB)) { + if (BGP_SUPPRESS_FIB_ENABLED(bgp) + && new_select->sub_type == BGP_ROUTE_NORMAL) + SET_FLAG(dest->flags, + BGP_NODE_FIB_INSTALL_PENDING); + if (new_select->type == ZEBRA_ROUTE_BGP && (new_select->sub_type == BGP_ROUTE_NORMAL || new_select->sub_type @@ -2952,11 +3076,16 @@ static void bgp_process_main_one(struct bgp *bgp, struct bgp_dest *dest, /* FIB update. */ if (bgp_fibupd_safi(safi) && (bgp->inst_type != BGP_INSTANCE_TYPE_VIEW) && !bgp_option_check(BGP_OPT_NO_FIB)) { + if (new_select && new_select->type == ZEBRA_ROUTE_BGP && (new_select->sub_type == BGP_ROUTE_NORMAL || new_select->sub_type == BGP_ROUTE_AGGREGATE || new_select->sub_type == BGP_ROUTE_IMPORTED)) { + if (BGP_SUPPRESS_FIB_ENABLED(bgp)) + SET_FLAG(dest->flags, + BGP_NODE_FIB_INSTALL_PENDING); + /* if this is an evpn imported type-5 prefix, * we need to withdraw the route first to clear * the nh neigh and the RMAC entry. @@ -3605,6 +3734,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, uint8_t pi_type = 0; uint8_t pi_sub_type = 0; bool force_evpn_import = false; + safi_t orig_safi = safi; if (frrtrace_enabled(frr_bgp, process_update)) { char pfxprint[PREFIX2STR_BUFFER]; @@ -3619,6 +3749,10 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, #endif int same_attr = 0; + /* Special case for BGP-LU - map LU safi to ordinary unicast safi */ + if (orig_safi == SAFI_LABELED_UNICAST) + safi = SAFI_UNICAST; + memset(&new_attr, 0, sizeof(struct attr)); new_attr.label_index = BGP_INVALID_LABEL_INDEX; new_attr.label = MPLS_INVALID_LABEL; @@ -3706,7 +3840,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, } /* Apply incoming filter. */ - if (bgp_input_filter(peer, p, attr, afi, safi) == FILTER_DENY) { + if (bgp_input_filter(peer, p, attr, afi, orig_safi) == FILTER_DENY) { peer->stat_pfx_filter++; reason = "filter;"; goto filtered; @@ -3749,7 +3883,7 @@ int bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id, * commands, so we need bgp_attr_flush in the error paths, until we * intern * the attr (which takes over the memory references) */ - if (bgp_input_modifier(peer, p, &new_attr, afi, safi, NULL, label, + if (bgp_input_modifier(peer, p, &new_attr, afi, orig_safi, NULL, label, num_labels, dest) == RMAP_DENY) { peer->stat_pfx_filter++; @@ -5206,6 +5340,11 @@ void bgp_clear_adj_in(struct peer *peer, afi_t afi, safi_t safi) } } +/* If any of the routes from the peer have been marked with the NO_LLGR + * community, either as sent by the peer, or as the result of a configured + * policy, they MUST NOT be retained, but MUST be removed as per the normal + * operation of [RFC4271]. + */ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) { struct bgp_dest *dest; @@ -5228,10 +5367,29 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) pi = pi->next) { if (pi->peer != peer) continue; + if (CHECK_FLAG( + peer->af_sflags[afi][safi], + PEER_STATUS_LLGR_WAIT) && + pi->attr->community && + !community_include( + pi->attr->community, + COMMUNITY_NO_LLGR)) + break; if (!CHECK_FLAG(pi->flags, BGP_PATH_STALE)) break; + /* + * If this is VRF leaked route + * process for withdraw. + */ + if (pi->sub_type == + BGP_ROUTE_IMPORTED && + peer->bgp->inst_type == + BGP_INSTANCE_TYPE_DEFAULT) + vpn_leak_to_vrf_withdraw( + peer->bgp, pi); + bgp_rib_remove(rm, pi, peer, afi, safi); break; } @@ -5243,8 +5401,23 @@ void bgp_clear_stale_route(struct peer *peer, afi_t afi, safi_t safi) pi = pi->next) { if (pi->peer != peer) continue; + if (CHECK_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_LLGR_WAIT) && + pi->attr->community && + !community_include(pi->attr->community, + COMMUNITY_NO_LLGR)) + break; if (!CHECK_FLAG(pi->flags, BGP_PATH_STALE)) break; + if (safi == SAFI_UNICAST && + (peer->bgp->inst_type == + BGP_INSTANCE_TYPE_VRF || + peer->bgp->inst_type == + BGP_INSTANCE_TYPE_DEFAULT)) + vpn_leak_from_vrf_withdraw( + bgp_get_default(), peer->bgp, + pi); + bgp_rib_remove(dest, pi, peer, afi, safi); break; } @@ -8276,6 +8449,7 @@ void bgp_redistribute_add(struct bgp *bgp, struct prefix *p, bgp_aggregate_increment(bgp, p, new, afi, SAFI_UNICAST); bgp_path_info_add(bn, new); bgp_dest_unlock_node(bn); + SET_FLAG(bn->flags, BGP_NODE_FIB_INSTALLED); bgp_process(bgp, bn, afi, SAFI_UNICAST); if ((bgp->inst_type == BGP_INSTANCE_TYPE_VRF) @@ -8360,7 +8534,6 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p, { int len = 0; char buf[BUFSIZ]; - char buf2[BUFSIZ]; if (p->family == AF_INET) { if (!json) { @@ -8371,8 +8544,7 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p, &p->u.prefix, buf, BUFSIZ)); json_object_int_add(json, "prefixLen", p->prefixlen); - prefix2str(p, buf2, PREFIX_STRLEN); - json_object_string_add(json, "network", buf2); + json_object_string_addf(json, "network", "%pFX", p); json_object_int_add(json, "version", dest->version); } } else if (p->family == AF_ETHERNET) { @@ -8396,8 +8568,7 @@ static void route_vty_out_route(struct bgp_dest *dest, const struct prefix *p, &p->u.prefix, buf, BUFSIZ)); json_object_int_add(json, "prefixLen", p->prefixlen); - prefix2str(p, buf2, PREFIX_STRLEN); - json_object_string_add(json, "network", buf2); + json_object_string_addf(json, "network", "%pFX", p); json_object_int_add(json, "version", dest->version); } } @@ -8415,8 +8586,7 @@ enum bgp_display_type { normal_list, }; -static const char * -bgp_path_selection_reason2str(enum bgp_path_selection_reason reason) +const char *bgp_path_selection_reason2str(enum bgp_path_selection_reason reason) { switch (reason) { case bgp_path_selection_none: @@ -8710,14 +8880,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } } else if (safi == SAFI_EVPN) { if (json_paths) { - char buf[BUFSIZ] = {0}; - json_nexthop_global = json_object_new_object(); - json_object_string_add(json_nexthop_global, "ip", - inet_ntop(AF_INET, - &attr->nexthop, buf, - sizeof(buf))); + json_object_string_addf(json_nexthop_global, "ip", + "%pI4", &attr->nexthop); if (path->peer->hostname) json_object_string_add(json_nexthop_global, @@ -8745,16 +8911,13 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } else if (safi == SAFI_FLOWSPEC) { if (attr->nexthop.s_addr != INADDR_ANY) { if (json_paths) { - char buf[BUFSIZ] = {0}; - json_nexthop_global = json_object_new_object(); json_object_string_add(json_nexthop_global, "afi", "ipv4"); - json_object_string_add( - json_nexthop_global, "ip", - inet_ntop(AF_INET, &attr->nexthop, buf, - sizeof(buf))); + json_object_string_addf(json_nexthop_global, + "ip", "%pI4", + &attr->nexthop); if (path->peer->hostname) json_object_string_add( @@ -8784,14 +8947,10 @@ void route_vty_out(struct vty *vty, const struct prefix *p, } } else if (p->family == AF_INET && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { if (json_paths) { - char buf[BUFSIZ] = {0}; - json_nexthop_global = json_object_new_object(); - json_object_string_add(json_nexthop_global, "ip", - inet_ntop(AF_INET, - &attr->nexthop, buf, - sizeof(buf))); + json_object_string_addf(json_nexthop_global, "ip", + "%pI4", &attr->nexthop); if (path->peer->hostname) json_object_string_add(json_nexthop_global, @@ -8820,14 +8979,11 @@ void route_vty_out(struct vty *vty, const struct prefix *p, /* IPv6 Next Hop */ else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { - char buf[BUFSIZ]; - if (json_paths) { json_nexthop_global = json_object_new_object(); - json_object_string_add( - json_nexthop_global, "ip", - inet_ntop(AF_INET6, &attr->mp_nexthop_global, - buf, BUFSIZ)); + json_object_string_addf(json_nexthop_global, "ip", + "%pI6", + &attr->mp_nexthop_global); if (path->peer->hostname) json_object_string_add(json_nexthop_global, @@ -8845,11 +9001,9 @@ void route_vty_out(struct vty *vty, const struct prefix *p, == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) || (path->peer->conf_if)) { json_nexthop_ll = json_object_new_object(); - json_object_string_add( - json_nexthop_ll, "ip", - inet_ntop(AF_INET6, - &attr->mp_nexthop_local, buf, - BUFSIZ)); + json_object_string_addf( + json_nexthop_ll, "ip", "%pI6", + &attr->mp_nexthop_local); if (path->peer->hostname) json_object_string_add( @@ -9093,8 +9247,7 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, BUFSIZ)); json_object_int_add(json_net, "prefixLen", p->prefixlen); - prefix2str(p, buff, PREFIX_STRLEN); - json_object_string_add(json_net, "network", buff); + json_object_string_addf(json_net, "network", "%pFX", p); } } else route_vty_out_route(dest, p, vty, NULL, wide); @@ -9102,42 +9255,27 @@ void route_vty_out_tmp(struct vty *vty, struct bgp_dest *dest, /* Print attribute */ if (attr) { if (use_json) { - char buf[BUFSIZ] = {0}; - if (p->family == AF_INET && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP) - json_object_string_add( - json_net, "nextHop", - inet_ntop( - AF_INET, - &attr->mp_nexthop_global_in, - buf, sizeof(buf))); + json_object_string_addf( + json_net, "nextHop", "%pI4", + &attr->mp_nexthop_global_in); else - json_object_string_add( - json_net, "nextHop", - inet_ntop(AF_INET, - &attr->nexthop, buf, - sizeof(buf))); + json_object_string_addf( + json_net, "nextHop", "%pI4", + &attr->nexthop); } else if (p->family == AF_INET6 || BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { - char buf[BUFSIZ]; - - json_object_string_add( - json_net, "nextHopGlobal", - inet_ntop(AF_INET6, - &attr->mp_nexthop_global, buf, - BUFSIZ)); + json_object_string_addf( + json_net, "nextHopGlobal", "%pI6", + &attr->mp_nexthop_global); } else if (p->family == AF_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) { - char buf[BUFSIZ] = {0}; - - json_object_string_add( - json_net, "nextHop", - inet_ntop(AF_INET, - &attr->mp_nexthop_global_in, - buf, sizeof(buf))); + json_object_string_addf( + json_net, "nextHop", "%pI4", + &attr->mp_nexthop_global_in); } if (attr->flag @@ -9256,25 +9394,19 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p, && ((safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP))) || (safi == SAFI_EVPN && !BGP_ATTR_NEXTHOP_AFI_IP6(attr)) || (!BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - char buf[BUFSIZ] = {0}; - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { if (json) - json_object_string_add( - json_out, "mpNexthopGlobalIn", - inet_ntop(AF_INET, - &attr->mp_nexthop_global_in, - buf, sizeof(buf))); + json_object_string_addf( + json_out, "mpNexthopGlobalIn", "%pI4", + &attr->mp_nexthop_global_in); else vty_out(vty, "%-16pI4", &attr->mp_nexthop_global_in); } else { if (json) - json_object_string_add( - json_out, "nexthop", - inet_ntop(AF_INET, &attr->nexthop, buf, - sizeof(buf))); + json_object_string_addf(json_out, "nexthop", + "%pI4", &attr->nexthop); else vty_out(vty, "%-16pI4", &attr->nexthop); } @@ -9286,11 +9418,9 @@ void route_vty_out_tag(struct vty *vty, const struct prefix *p, if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL) { if (json) - json_object_string_add( - json_out, "mpNexthopGlobalIn", - inet_ntop(AF_INET6, - &attr->mp_nexthop_global, - buf_a, sizeof(buf_a))); + json_object_string_addf( + json_out, "mpNexthopGlobalIn", "%pI6", + &attr->mp_nexthop_global); else vty_out(vty, "%s", inet_ntop(AF_INET6, @@ -9864,14 +9994,10 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) { if (json_paths) { - char buf[BUFSIZ] = {0}; - json_object_int_add(json_path, "aggregatorAs", attr->aggregator_as); - json_object_string_add(json_path, "aggregatorId", - inet_ntop(AF_INET, - &attr->aggregator_addr, - buf, sizeof(buf))); + json_object_string_addf(json_path, "aggregatorId", + "%pI4", &attr->aggregator_addr); } else { vty_out(vty, ", (aggregated by %u %pI4)", attr->aggregator_as, &attr->aggregator_addr); @@ -9921,16 +10047,12 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, || bn_p->family == AF_EVPN) && (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN || !BGP_ATTR_NEXTHOP_AFI_IP6(attr))) { - char buf[BUFSIZ] = {0}; - if (safi == SAFI_MPLS_VPN || safi == SAFI_ENCAP || safi == SAFI_EVPN) { if (json_paths) { - json_object_string_add( - json_nexthop_global, "ip", - inet_ntop(AF_INET, - &attr->mp_nexthop_global_in, - buf, sizeof(buf))); + json_object_string_addf( + json_nexthop_global, "ip", "%pI4", + &attr->mp_nexthop_global_in); if (path->peer->hostname) json_object_string_add( @@ -9947,10 +10069,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, } } else { if (json_paths) { - json_object_string_add( - json_nexthop_global, "ip", - inet_ntop(AF_INET, &attr->nexthop, buf, - sizeof(buf))); + json_object_string_addf(json_nexthop_global, + "ip", "%pI4", + &attr->nexthop); if (path->peer->hostname) json_object_string_add( @@ -9972,10 +10093,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, "ipv4"); } else { if (json_paths) { - json_object_string_add( - json_nexthop_global, "ip", - inet_ntop(AF_INET6, &attr->mp_nexthop_global, - buf, INET6_ADDRSTRLEN)); + json_object_string_addf(json_nexthop_global, "ip", + "%pI6", + &attr->mp_nexthop_global); if (path->peer->hostname) json_object_string_add(json_nexthop_global, @@ -10047,16 +10167,11 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, vty_out(vty, " from :: "); } - if (json_paths) { - char buf[BUFSIZ] = {0}; - - json_object_string_add(json_peer, "routerId", - inet_ntop(AF_INET, - &bgp->router_id, buf, - sizeof(buf))); - } else { + if (json_paths) + json_object_string_addf(json_peer, "routerId", "%pI4", + &bgp->router_id); + else vty_out(vty, "(%pI4)", &bgp->router_id); - } } /* We RXed this path from one of our peers */ @@ -10067,10 +10182,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, sockunion2str(&path->peer->su, buf, SU_ADDRSTRLEN)); - json_object_string_add(json_peer, "routerId", - inet_ntop(AF_INET, - &path->peer->remote_id, - buf1, sizeof(buf1))); + json_object_string_addf(json_peer, "routerId", "%pI4", + &path->peer->remote_id); if (path->peer->hostname) json_object_string_add(json_peer, "hostname", @@ -10170,10 +10283,8 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, if (attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { if (json_paths) { json_nexthop_ll = json_object_new_object(); - json_object_string_add( - json_nexthop_ll, "ip", - inet_ntop(AF_INET6, &attr->mp_nexthop_local, - buf, INET6_ADDRSTRLEN)); + json_object_string_addf(json_nexthop_ll, "ip", "%pI6", + &attr->mp_nexthop_local); if (path->peer->hostname) json_object_string_add(json_nexthop_ll, @@ -10436,10 +10547,9 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_ORIGINATOR_ID)) { if (json_paths) - json_object_string_add( - json_path, "originatorId", - inet_ntop(AF_INET, &attr->originator_id, - buf, sizeof(buf))); + json_object_string_addf(json_path, + "originatorId", "%pI4", + &attr->originator_id); else vty_out(vty, " Originator: %pI4", &attr->originator_id); @@ -10671,21 +10781,6 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, #define BGP_SHOW_DAMP_HEADER " Network From Reuse Path\n" #define BGP_SHOW_FLAP_HEADER " Network From Flaps Duration Reuse Path\n" -static int bgp_show_prefix_list(struct vty *vty, struct bgp *bgp, - const char *prefix_list_str, afi_t afi, - safi_t safi, enum bgp_show_type type); -static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp, - const char *filter, afi_t afi, safi_t safi, - enum bgp_show_type type); -static int bgp_show_route_map(struct vty *vty, struct bgp *bgp, - const char *rmap_str, afi_t afi, safi_t safi, - enum bgp_show_type type); -static int bgp_show_community_list(struct vty *vty, struct bgp *bgp, - const char *com, int exact, afi_t afi, - safi_t safi); -static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp, - const char *prefix, afi_t afi, safi_t safi, - enum bgp_show_type type); static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr, afi_t afi, safi_t safi, enum bgp_show_type type, bool use_json); @@ -10695,14 +10790,15 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp, static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, struct bgp_table *table, enum bgp_show_type type, - void *output_arg, char *rd, int is_last, + void *output_arg, const char *rd, int is_last, unsigned long *output_cum, unsigned long *total_cum, unsigned long *json_header_depth, uint16_t show_flags, enum rpki_states rpki_target_state) { struct bgp_path_info *pi; struct bgp_dest *dest; - int header = 1; + bool header = true; + bool json_detail_header = false; int display; unsigned long output_count = 0; unsigned long total_count = 0; @@ -10714,7 +10810,7 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, bool all = CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL); if (output_cum && *output_cum != 0) - header = 0; + header = false; if (use_json && !*json_header_depth) { if (all) @@ -10744,10 +10840,19 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, vty_out(vty, " \"%s\" : { ", rd); } + /* Check for 'json detail', where we need header output once per dest */ + if (use_json && CHECK_FLAG(show_flags, BGP_SHOW_OPT_DETAIL) && + type != bgp_show_type_dampend_paths && + type != bgp_show_type_damp_neighbor && + type != bgp_show_type_flap_statistics && + type != bgp_show_type_flap_neighbor) + json_detail_header = true; + /* Start processing of routes. */ for (dest = bgp_table_top(table); dest; dest = bgp_route_next(dest)) { const struct prefix *dest_p = bgp_dest_get_prefix(dest); enum rpki_states rpki_curr_state = RPKI_NOT_BEING_USED; + bool json_detail = json_detail_header; pi = bgp_dest_get_bgp_path_info(dest); if (pi == NULL) @@ -10999,8 +11104,28 @@ static int bgp_show_table(struct vty *vty, struct bgp *bgp, safi_t safi, else vty_out(vty, (wide ? BGP_SHOW_HEADER_WIDE : BGP_SHOW_HEADER)); - header = 0; + header = false; + + } else if (json_detail && json_paths != NULL) { + const struct prefix_rd *prd; + json_object *jtemp; + + /* Use common detail header, for most types; + * need a json 'object'. + */ + + jtemp = json_object_new_object(); + prd = bgp_rd_from_dest(dest, safi); + + route_vty_out_detail_header( + vty, bgp, dest, prd, table->afi, + safi, jtemp); + + json_object_array_add(json_paths, jtemp); + + json_detail = false; } + if (rd != NULL && !display && !output_count) { if (!use_json) vty_out(vty, @@ -11159,6 +11284,7 @@ int bgp_show_table_rd(struct vty *vty, struct bgp *bgp, safi_t safi, } return CMD_SUCCESS; } + static int bgp_show(struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, enum bgp_show_type type, void *output_arg, uint16_t show_flags, enum rpki_states rpki_target_state) @@ -11243,7 +11369,8 @@ static void bgp_show_all_instances_routes_vty(struct vty *vty, afi_t afi, /* Header of detailed BGP route information */ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, - struct bgp_dest *dest, struct prefix_rd *prd, + struct bgp_dest *dest, + const struct prefix_rd *prd, afi_t afi, safi_t safi, json_object *json) { struct bgp_path_info *pi; @@ -11251,7 +11378,6 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, struct peer *peer; struct listnode *node, *nnode; char buf1[RD_ADDRSTRLEN]; - char prefix_str[BUFSIZ]; int count = 0; int best = 0; int suppress = 0; @@ -11305,8 +11431,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, dest->version); } else { - json_object_string_add(json, "prefix", - prefix2str(p, prefix_str, sizeof(prefix_str))); + json_object_string_addf(json, "prefix", "%pFX", p); json_object_int_add(json, "version", dest->version); } @@ -11397,7 +11522,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, ", attach RT as-is for VPNv6 route filtering"); else if (llgr_stale) vty_out(vty, - ", mark routes to be retained for a longer time. Requeres support for Long-lived BGP Graceful Restart"); + ", mark routes to be retained for a longer time. Requires support for Long-lived BGP Graceful Restart"); else if (no_llgr) vty_out(vty, ", mark routes to not be treated according to Long-lived BGP Graceful Restart operations"); @@ -11453,7 +11578,7 @@ void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, } } -static void bgp_show_path_info(struct prefix_rd *pfx_rd, +static void bgp_show_path_info(const struct prefix_rd *pfx_rd, struct bgp_dest *bgp_node, struct vty *vty, struct bgp *bgp, afi_t afi, safi_t safi, json_object *json, enum bgp_path_type pathtype, @@ -11513,6 +11638,23 @@ static void bgp_show_path_info(struct prefix_rd *pfx_rd, } } +/* + * Return rd based on safi + */ +static const struct prefix_rd *bgp_rd_from_dest(const struct bgp_dest *dest, + safi_t safi) +{ + switch (safi) { + case SAFI_MPLS_VPN: + case SAFI_ENCAP: + case SAFI_EVPN: + return (struct prefix_rd *)(bgp_dest_get_prefix(dest)); + default: + return NULL; + + } +} + /* Display specified route of BGP table. */ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, struct bgp_table *rib, const char *ip_str, @@ -11661,10 +11803,7 @@ static int bgp_show_route_in_table(struct vty *vty, struct bgp *bgp, } if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY | - JSON_C_TO_STRING_NOSLASHESCAPE)); - json_object_free(json); + vty_json(vty, json); } else { if (!display) { vty_out(vty, "%% Network not in table\n"); @@ -11999,45 +12138,28 @@ DEFUN(show_ip_bgp_afi_safi_statistics, show_ip_bgp_afi_safi_statistics_cmd, return ret; } -/* BGP route print out function without JSON */ -DEFPY(show_ip_bgp, show_ip_bgp_cmd, +DEFPY(show_ip_bgp_dampening_params, show_ip_bgp_dampening_params_cmd, "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR " [" BGP_SAFI_WITH_LABEL_CMD_STR - "]]\ - <[all$all] dampening <parameters>\ - |route-map WORD\ - |prefix-list WORD\ - |filter-list WORD\ - |community-list <(1-500)|COMMUNITY_LIST_NAME> [exact-match]\ - |A.B.C.D/M longer-prefixes\ - |X:X::X:X/M longer-prefixes\ - >", + "]] [all$all] dampening parameters [json]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_WITH_LABEL_HELP_STR "Display the entries for all address families\n" "Display detailed information about dampening\n" "Display detail of configured dampening parameters\n" - "Display routes matching the route-map\n" - "A route-map to match on\n" - "Display routes conforming to the prefix-list\n" - "Prefix-list name\n" - "Display routes conforming to the filter-list\n" - "Regular expression access list name\n" - "Display routes matching the community-list\n" - "community-list number\n" - "community-list name\n" - "Exact match of the communities\n" - "IPv4 prefix\n" - "Display route and more specific routes\n" - "IPv6 prefix\n" - "Display route and more specific routes\n") + JSON_STR) { afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; - int exact_match = 0; struct bgp *bgp = NULL; int idx = 0; uint16_t show_flags = 0; + bool uj = use_json(argc, argv); + + if (uj) { + argc--; + SET_FLAG(show_flags, BGP_SHOW_OPT_JSON); + } /* [<ipv4|ipv6> [all]] */ if (all) { @@ -12054,43 +12176,11 @@ DEFPY(show_ip_bgp, show_ip_bgp_cmd, if (!idx) return CMD_WARNING; - if (argv_find(argv, argc, "dampening", &idx)) { - if (argv_find(argv, argc, "parameters", &idx)) - return bgp_show_dampening_parameters(vty, afi, safi, - show_flags); - } - - if (argv_find(argv, argc, "prefix-list", &idx)) - return bgp_show_prefix_list(vty, bgp, argv[idx + 1]->arg, afi, - safi, bgp_show_type_prefix_list); - - if (argv_find(argv, argc, "filter-list", &idx)) - return bgp_show_filter_list(vty, bgp, argv[idx + 1]->arg, afi, - safi, bgp_show_type_filter_list); - - if (argv_find(argv, argc, "route-map", &idx)) - return bgp_show_route_map(vty, bgp, argv[idx + 1]->arg, afi, - safi, bgp_show_type_route_map); - - if (argv_find(argv, argc, "community-list", &idx)) { - const char *clist_number_or_name = argv[++idx]->arg; - if (++idx < argc && strmatch(argv[idx]->text, "exact-match")) - exact_match = 1; - return bgp_show_community_list(vty, bgp, clist_number_or_name, - exact_match, afi, safi); - } - /* prefix-longer */ - if (argv_find(argv, argc, "A.B.C.D/M", &idx) - || argv_find(argv, argc, "X:X::X:X/M", &idx)) - return bgp_show_prefix_longer(vty, bgp, argv[idx]->arg, afi, - safi, - bgp_show_type_prefix_longer); - - return CMD_WARNING; + return bgp_show_dampening_parameters(vty, afi, safi, show_flags); } -/* BGP route print out function with JSON */ -DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, +/* BGP route print out function */ +DEFPY(show_ip_bgp, show_ip_bgp_cmd, "show [ip] bgp [<view|vrf> VIEWVRFNAME] [" BGP_AFI_CMD_STR " [" BGP_SAFI_WITH_LABEL_CMD_STR "]]\ @@ -12102,9 +12192,15 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, |accept-own|accept-own-nexthop|route-filter-v6\ |route-filter-v4|route-filter-translated-v6\ |route-filter-translated-v4] [exact-match]\ + |community-list <(1-500)|COMMUNITY_LIST_NAME> [exact-match]\ + |filter-list AS_PATH_FILTER_NAME\ + |prefix-list WORD\ + |route-map WORD\ |rpki <invalid|valid|notfound>\ |version (1-4294967295)\ |alias ALIAS_NAME\ + |A.B.C.D/M longer-prefixes\ + |X:X::X:X/M longer-prefixes\ ] [json$uj [detail$detail] | wide$wide]", SHOW_STR IP_STR BGP_STR BGP_INSTANCE_HELP_STR BGP_AFI_HELP_STR BGP_SAFI_WITH_LABEL_HELP_STR @@ -12129,6 +12225,16 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, "RT translated VPNv6 route filtering (well-known community)\n" "RT translated VPNv4 route filtering (well-known community)\n" "Exact match of the communities\n" + "Community-list number\n" + "Community-list name\n" + "Display routes matching the community-list\n" + "Exact match of the communities\n" + "Display routes conforming to the filter-list\n" + "Regular expression access list name\n" + "Display routes conforming to the prefix-list\n" + "Prefix-list name\n" + "Display routes matching the route-map\n" + "A route-map to match on\n" "RPKI route types\n" "A valid path as determined by rpki\n" "A invalid path as determined by rpki\n" @@ -12136,19 +12242,23 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, "Display prefixes with matching version numbers\n" "Version number and above\n" "Display prefixes with matching BGP community alias\n" - "BGP community alias\n" JSON_STR + "BGP community alias\n" + "IPv4 prefix\n" + "Display route and more specific routes\n" + "IPv6 prefix\n" + "Display route and more specific routes\n" + JSON_STR "Display detailed version of JSON output\n" "Increase table width for longer prefixes\n") { afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; enum bgp_show_type sh_type = bgp_show_type_normal; + void *output_arg = NULL; struct bgp *bgp = NULL; int idx = 0; int exact_match = 0; char *community = NULL; - char *prefix_version = NULL; - char *bgp_community_alias = NULL; bool first = true; uint16_t show_flags = 0; enum rpki_states rpki_target_state = RPKI_NOT_BEING_USED; @@ -12211,6 +12321,75 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, sh_type = bgp_show_type_community_all; } + if (argv_find(argv, argc, "community-list", &idx)) { + const char *clist_number_or_name = argv[++idx]->arg; + struct community_list *list; + + if (argv_find(argv, argc, "exact-match", &idx)) + exact_match = 1; + + list = community_list_lookup(bgp_clist, clist_number_or_name, 0, + COMMUNITY_LIST_MASTER); + if (list == NULL) { + vty_out(vty, + "%% %s is not a valid community-list name\n", + clist_number_or_name); + return CMD_WARNING; + } + + if (exact_match) + sh_type = bgp_show_type_community_list_exact; + else + sh_type = bgp_show_type_community_list; + output_arg = list; + } + + if (argv_find(argv, argc, "filter-list", &idx)) { + const char *filter = argv[++idx]->arg; + struct as_list *as_list; + + as_list = as_list_lookup(filter); + if (as_list == NULL) { + vty_out(vty, + "%% %s is not a valid AS-path access-list name\n", + filter); + return CMD_WARNING; + } + + sh_type = bgp_show_type_filter_list; + output_arg = as_list; + } + + if (argv_find(argv, argc, "prefix-list", &idx)) { + const char *prefix_list_str = argv[++idx]->arg; + struct prefix_list *plist; + + plist = prefix_list_lookup(afi, prefix_list_str); + if (plist == NULL) { + vty_out(vty, "%% %s is not a valid prefix-list name\n", + prefix_list_str); + return CMD_WARNING; + } + + sh_type = bgp_show_type_prefix_list; + output_arg = plist; + } + + if (argv_find(argv, argc, "route-map", &idx)) { + const char *rmap_str = argv[++idx]->arg; + struct route_map *rmap; + + rmap = route_map_lookup_by_name(rmap_str); + if (!rmap) { + vty_out(vty, "%% %s is not a valid route-map name\n", + rmap_str); + return CMD_WARNING; + } + + sh_type = bgp_show_type_route_map; + output_arg = rmap; + } + if (argv_find(argv, argc, "rpki", &idx)) { sh_type = bgp_show_type_rpki; if (argv_find(argv, argc, "valid", &idx)) @@ -12222,13 +12401,28 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, /* Display prefixes with matching version numbers */ if (argv_find(argv, argc, "version", &idx)) { sh_type = bgp_show_type_prefix_version; - prefix_version = argv[idx + 1]->arg; + output_arg = argv[idx + 1]->arg; } /* Display prefixes with matching BGP community alias */ if (argv_find(argv, argc, "alias", &idx)) { sh_type = bgp_show_type_community_alias; - bgp_community_alias = argv[idx + 1]->arg; + output_arg = argv[idx + 1]->arg; + } + + /* prefix-longer */ + if (argv_find(argv, argc, "A.B.C.D/M", &idx) + || argv_find(argv, argc, "X:X::X:X/M", &idx)) { + const char *prefix_str = argv[idx]->arg; + struct prefix p; + + if (!str2prefix(prefix_str, &p)) { + vty_out(vty, "%% Malformed Prefix\n"); + return CMD_WARNING; + } + + sh_type = bgp_show_type_prefix_longer; + output_arg = &p; } if (!all) { @@ -12237,17 +12431,10 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, return bgp_show_community(vty, bgp, community, exact_match, afi, safi, show_flags); - else if (prefix_version) - return bgp_show(vty, bgp, afi, safi, sh_type, - prefix_version, show_flags, - rpki_target_state); - else if (bgp_community_alias) + else return bgp_show(vty, bgp, afi, safi, sh_type, - bgp_community_alias, show_flags, + output_arg, show_flags, rpki_target_state); - else - return bgp_show(vty, bgp, afi, safi, sh_type, NULL, - show_flags, rpki_target_state); } else { /* show <ip> bgp ipv4 all: AFI_IP, show <ip> bgp ipv6 all: * AFI_IP6 */ @@ -12282,19 +12469,9 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, bgp_show_community(vty, bgp, community, exact_match, afi, safi, show_flags); - else if (prefix_version) - return bgp_show(vty, bgp, afi, safi, - sh_type, prefix_version, - show_flags, - rpki_target_state); - else if (bgp_community_alias) - return bgp_show( - vty, bgp, afi, safi, sh_type, - bgp_community_alias, show_flags, - rpki_target_state); else bgp_show(vty, bgp, afi, safi, sh_type, - NULL, show_flags, + output_arg, show_flags, rpki_target_state); if (uj) vty_out(vty, "}\n"); @@ -12324,14 +12501,9 @@ DEFPY(show_ip_bgp_json, show_ip_bgp_json_cmd, bgp_show_community(vty, bgp, community, exact_match, afi, safi, show_flags); - else if (prefix_version) - return bgp_show(vty, bgp, afi, safi, - sh_type, prefix_version, - show_flags, - rpki_target_state); else bgp_show(vty, bgp, afi, safi, sh_type, - NULL, show_flags, + output_arg, show_flags, rpki_target_state); if (uj) vty_out(vty, "}\n"); @@ -12467,7 +12639,7 @@ DEFPY (show_ip_bgp_instance_all, JSON_STR "Increase table width for longer prefixes\n") { - afi_t afi = AFI_IP; + afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; struct bgp *bgp = NULL; int idx = 0; @@ -12519,59 +12691,6 @@ static int bgp_show_regexp(struct vty *vty, struct bgp *bgp, const char *regstr, return rc; } -static int bgp_show_prefix_list(struct vty *vty, struct bgp *bgp, - const char *prefix_list_str, afi_t afi, - safi_t safi, enum bgp_show_type type) -{ - struct prefix_list *plist; - uint16_t show_flags = 0; - - plist = prefix_list_lookup(afi, prefix_list_str); - if (plist == NULL) { - vty_out(vty, "%% %s is not a valid prefix-list name\n", - prefix_list_str); - return CMD_WARNING; - } - - return bgp_show(vty, bgp, afi, safi, type, plist, show_flags, - RPKI_NOT_BEING_USED); -} - -static int bgp_show_filter_list(struct vty *vty, struct bgp *bgp, - const char *filter, afi_t afi, safi_t safi, - enum bgp_show_type type) -{ - struct as_list *as_list; - uint16_t show_flags = 0; - - as_list = as_list_lookup(filter); - if (as_list == NULL) { - vty_out(vty, "%% %s is not a valid AS-path access-list name\n", - filter); - return CMD_WARNING; - } - - return bgp_show(vty, bgp, afi, safi, type, as_list, show_flags, - RPKI_NOT_BEING_USED); -} - -static int bgp_show_route_map(struct vty *vty, struct bgp *bgp, - const char *rmap_str, afi_t afi, safi_t safi, - enum bgp_show_type type) -{ - struct route_map *rmap; - uint16_t show_flags = 0; - - rmap = route_map_lookup_by_name(rmap_str); - if (!rmap) { - vty_out(vty, "%% %s is not a valid route-map name\n", rmap_str); - return CMD_WARNING; - } - - return bgp_show(vty, bgp, afi, safi, type, rmap, show_flags, - RPKI_NOT_BEING_USED); -} - static int bgp_show_community(struct vty *vty, struct bgp *bgp, const char *comstr, int exact, afi_t afi, safi_t safi, uint16_t show_flags) @@ -12594,47 +12713,6 @@ static int bgp_show_community(struct vty *vty, struct bgp *bgp, return ret; } -static int bgp_show_community_list(struct vty *vty, struct bgp *bgp, - const char *com, int exact, afi_t afi, - safi_t safi) -{ - struct community_list *list; - uint16_t show_flags = 0; - - list = community_list_lookup(bgp_clist, com, 0, COMMUNITY_LIST_MASTER); - if (list == NULL) { - vty_out(vty, "%% %s is not a valid community-list name\n", com); - return CMD_WARNING; - } - - return bgp_show(vty, bgp, afi, safi, - (exact ? bgp_show_type_community_list_exact - : bgp_show_type_community_list), - list, show_flags, RPKI_NOT_BEING_USED); -} - -static int bgp_show_prefix_longer(struct vty *vty, struct bgp *bgp, - const char *prefix, afi_t afi, safi_t safi, - enum bgp_show_type type) -{ - int ret; - struct prefix *p; - uint16_t show_flags = 0; - - p = prefix_new(); - - ret = str2prefix(prefix, p); - if (!ret) { - vty_out(vty, "%% Malformed Prefix\n"); - return CMD_WARNING; - } - - ret = bgp_show(vty, bgp, afi, safi, type, p, show_flags, - RPKI_NOT_BEING_USED); - prefix_free(&p); - return ret; -} - enum bgp_stats { BGP_STATS_MAXBITLEN = 0, BGP_STATS_RIB, @@ -13190,9 +13268,7 @@ static int bgp_peer_counts(struct vty *vty, struct peer *peer, afi_t afi, json, "recommended", "Please report this bug, with the above command output"); } - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { if (peer->hostname @@ -13363,15 +13439,12 @@ static void show_adj_route_header(struct vty *vty, struct bgp *bgp, json_object *json_ocode, bool wide) { uint64_t version = table ? table->version : 0; - char buf[BUFSIZ] = {0}; if (*header1) { if (json) { json_object_int_add(json, "bgpTableVersion", version); - json_object_string_add(json, "bgpLocalRouterId", - inet_ntop(AF_INET, - &bgp->router_id, buf, - sizeof(buf))); + json_object_string_addf(json, "bgpLocalRouterId", + "%pI4", &bgp->router_id); json_object_int_add(json, "defaultLocPrf", bgp->default_local_pref); json_object_int_add(json, "localAS", bgp->as); @@ -13433,29 +13506,15 @@ show_adj_route(struct vty *vty, struct peer *peer, struct bgp_table *table, bgp = peer->bgp; - if (!bgp) { - if (use_json) { - json_object_string_add(json, "alert", "no BGP"); - vty_out(vty, "%s\n", json_object_to_json_string(json)); - json_object_free(json); - } else - vty_out(vty, "%% No bgp\n"); - return; - } - subgrp = peer_subgroup(peer, afi, safi); if (type == bgp_show_adj_route_advertised && subgrp && CHECK_FLAG(subgrp->sflags, SUBGRP_STATUS_DEFAULT_ORIGINATE)) { - char buf[BUFSIZ] = {0}; - if (use_json) { json_object_int_add(json, "bgpTableVersion", table->version); - json_object_string_add(json, "bgpLocalRouterId", - inet_ntop(AF_INET, - &bgp->router_id, buf, - sizeof(buf))); + json_object_string_addf(json, "bgpLocalRouterId", + "%pI4", &bgp->router_id); json_object_int_add(json, "defaultLocPrf", bgp->default_local_pref); json_object_int_add(json, "localAS", bgp->as); @@ -13683,6 +13742,9 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, "No such neighbor or address family"); vty_out(vty, "%s\n", json_object_to_json_string(json)); json_object_free(json); + json_object_free(json_ar); + json_object_free(json_scode); + json_object_free(json_ocode); } else vty_out(vty, "%% No such neighbor or address family\n"); @@ -13699,6 +13761,9 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, "Inbound soft reconfiguration not enabled"); vty_out(vty, "%s\n", json_object_to_json_string(json)); json_object_free(json); + json_object_free(json_ar); + json_object_free(json_scode); + json_object_free(json_ocode); } else vty_out(vty, "%% Inbound soft reconfiguration not enabled\n"); @@ -13763,18 +13828,17 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, json_object_int_add(json, "filteredPrefixCounter", filtered_count); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - - if (!output_count && !filtered_count) { + /* + * These fields only give up ownership to `json` when `header1` + * is used (set to zero). See code in `show_adj_route` and + * `show_adj_route_header`. + */ + if (header1 == 1) { json_object_free(json_scode); json_object_free(json_ocode); } - if (json) - json_object_free(json); - + vty_json(vty, json); } else if (output_count > 0) { if (filtered_count > 0) vty_out(vty, @@ -14070,7 +14134,7 @@ DEFUN (show_ip_bgp_flowspec_routes_detailed, "Detailed information on flowspec entries\n" JSON_STR) { - afi_t afi = AFI_IP; + afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; struct bgp *bgp = NULL; int idx = 0; @@ -14563,7 +14627,7 @@ DEFUN (no_ipv6_bgp_distance_source_access_list, DEFUN (bgp_damp_set, bgp_damp_set_cmd, - "bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]]", + "bgp dampening [(1-45) [(1-20000) (1-50000) (1-255)]]", "BGP Specific commands\n" "Enable route-flap dampening\n" "Half-life time for the penalty\n" @@ -14609,7 +14673,7 @@ DEFUN (bgp_damp_set, DEFUN (bgp_damp_unset, bgp_damp_unset_cmd, - "no bgp dampening [(1-45) [(1-20000) (1-20000) (1-255)]]", + "no bgp dampening [(1-45) [(1-20000) (1-50000) (1-255)]]", NO_STR "BGP Specific commands\n" "Enable route-flap dampening\n" @@ -15097,10 +15161,10 @@ void bgp_route_init(void) install_element(BGP_IPV4L_NODE, &aggregate_addressv4_cmd); install_element(VIEW_NODE, &show_ip_bgp_instance_all_cmd); - install_element(VIEW_NODE, &show_ip_bgp_cmd); install_element(VIEW_NODE, &show_ip_bgp_afi_safi_statistics_cmd); install_element(VIEW_NODE, &show_ip_bgp_l2vpn_evpn_statistics_cmd); - install_element(VIEW_NODE, &show_ip_bgp_json_cmd); + install_element(VIEW_NODE, &show_ip_bgp_dampening_params_cmd); + install_element(VIEW_NODE, &show_ip_bgp_cmd); install_element(VIEW_NODE, &show_ip_bgp_route_cmd); install_element(VIEW_NODE, &show_ip_bgp_regexp_cmd); install_element(VIEW_NODE, &show_ip_bgp_statistics_all_cmd); diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 37bf675b67..741690a028 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -90,6 +90,9 @@ enum bgp_show_adj_route_type { /* Maximum number of sids we can process or send with a prefix. */ #define BGP_MAX_SIDS 6 +/* Maximum buffer length for storing BGP best path selection reason */ +#define BGP_MAX_SELECTION_REASON_STR_BUF 32 + /* Error codes for handling NLRI */ #define BGP_NLRI_PARSE_OK 0 #define BGP_NLRI_PARSE_ERROR_PREFIX_OVERFLOW -1 @@ -584,6 +587,33 @@ static inline bool bgp_check_advertise(struct bgp *bgp, struct bgp_dest *dest) (!bgp_option_check(BGP_OPT_NO_FIB)))); } +/* + * If we have a fib result and it failed to install( or was withdrawn due + * to better admin distance we need to send down the wire a withdrawal. + * This function assumes that bgp_check_advertise was already returned + * as good to go. + */ +static inline bool bgp_check_withdrawal(struct bgp *bgp, struct bgp_dest *dest) +{ + struct bgp_path_info *pi; + + if (!BGP_SUPPRESS_FIB_ENABLED(bgp)) + return false; + + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) + continue; + + if (pi->sub_type != BGP_ROUTE_NORMAL) + return true; + } + + if (CHECK_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED)) + return false; + + return true; +} + /* called before bgp_process() */ DECLARE_HOOK(bgp_process, (struct bgp * bgp, afi_t afi, safi_t safi, struct bgp_dest *bn, @@ -630,6 +660,8 @@ extern struct bgp_dest *bgp_afi_node_get(struct bgp_table *table, afi_t afi, struct prefix_rd *prd); extern struct bgp_path_info *bgp_path_info_lock(struct bgp_path_info *path); extern struct bgp_path_info *bgp_path_info_unlock(struct bgp_path_info *path); +extern struct bgp_path_info * +bgp_get_imported_bpi_ultimate(struct bgp_path_info *info); extern void bgp_path_info_add(struct bgp_dest *dest, struct bgp_path_info *pi); extern void bgp_path_info_extra_free(struct bgp_path_info_extra **extra); extern void bgp_path_info_reap(struct bgp_dest *dest, struct bgp_path_info *pi); @@ -770,6 +802,7 @@ extern int bgp_path_info_cmp_compatible(struct bgp *bgp, struct bgp_path_info *exist, char *pfx_buf, afi_t afi, safi_t safi, enum bgp_path_selection_reason *reason); +extern void bgp_attr_add_llgr_community(struct attr *attr); extern void bgp_attr_add_gshut_community(struct attr *attr); extern void bgp_best_selection(struct bgp *bgp, struct bgp_dest *dest, @@ -781,7 +814,7 @@ extern bool bgp_zebra_has_route_changed(struct bgp_path_info *selected); extern void route_vty_out_detail_header(struct vty *vty, struct bgp *bgp, struct bgp_dest *dest, - struct prefix_rd *prd, afi_t afi, + const struct prefix_rd *prd, afi_t afi, safi_t safi, json_object *json); extern void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, @@ -803,4 +836,6 @@ extern void bgp_aggregate_toggle_suppressed(struct bgp_aggregate *aggregate, const struct prefix *p, afi_t afi, safi_t safi, bool suppress); extern void subgroup_announce_reset_nhop(uint8_t family, struct attr *attr); +const char * +bgp_path_selection_reason2str(enum bgp_path_selection_reason reason); #endif /* _QUAGGA_BGP_ROUTE_H */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 835576a079..c42e3c9b94 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -725,6 +725,57 @@ static const struct route_map_rule_cmd route_match_ip_next_hop_prefix_list_free }; +/* `match ipv6 next-hop prefix-list PREFIXLIST_NAME' */ +static enum route_map_cmd_result_t +route_match_ipv6_next_hop_prefix_list(void *rule, const struct prefix *prefix, + void *object) +{ + struct prefix_list *plist; + struct bgp_path_info *path; + struct prefix_ipv6 p; + + if (prefix->family == AF_INET6) { + path = object; + p.family = AF_INET6; + p.prefix = path->attr->mp_nexthop_global; + p.prefixlen = IPV6_MAX_BITLEN; + + plist = prefix_list_lookup(AFI_IP6, (char *)rule); + if (!plist) + return RMAP_NOMATCH; + + if (prefix_list_apply(plist, &p) == PREFIX_PERMIT) + return RMAP_MATCH; + + if (path->attr->mp_nexthop_len + == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + p.prefix = path->attr->mp_nexthop_local; + if (prefix_list_apply(plist, &p) == PREFIX_PERMIT) + return RMAP_MATCH; + } + } + + return RMAP_NOMATCH; +} + +static void *route_match_ipv6_next_hop_prefix_list_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void route_match_ipv6_next_hop_prefix_list_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static const struct route_map_rule_cmd + route_match_ipv6_next_hop_prefix_list_cmd = { + "ipv6 next-hop prefix-list", + route_match_ipv6_next_hop_prefix_list, + route_match_ipv6_next_hop_prefix_list_compile, + route_match_ipv6_next_hop_prefix_list_free +}; + /* `match ip next-hop type <blackhole>' */ static enum route_map_cmd_result_t @@ -1148,7 +1199,7 @@ route_match_vrl_source_vrf(void *rule, const struct prefix *prefix, if (strncmp(vrf_name, "n/a", VRF_NAMSIZ) == 0) return RMAP_NOMATCH; - if (path->extra == NULL) + if (path->extra == NULL || path->extra->bgp_orig == NULL) return RMAP_NOMATCH; if (strncmp(vrf_name, vrf_id_to_name(path->extra->bgp_orig->vrf_id), @@ -1688,10 +1739,10 @@ route_match_interface(void *rule, const struct prefix *prefix, void *object) path = object; - if (!path) + if (!path || !path->peer || !path->peer->bgp) return RMAP_NOMATCH; - ifp = if_lookup_by_name_all_vrf((char *)rule); + ifp = if_lookup_by_name((char *)rule, path->peer->bgp->vrf_id); if (ifp == NULL || ifp->ifindex != path->attr->nh_ifindex) return RMAP_NOMATCH; @@ -3023,10 +3074,60 @@ static const struct route_map_rule_cmd route_match_ipv6_address_cmd = { route_match_ipv6_address_free }; +/* `match ipv6 next-hop ACCESSLIST6_NAME' */ +static enum route_map_cmd_result_t +route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, void *object) +{ + struct bgp_path_info *path; + struct access_list *alist; + struct prefix_ipv6 p; + + if (prefix->family == AF_INET6) { + path = object; + p.family = AF_INET6; + p.prefix = path->attr->mp_nexthop_global; + p.prefixlen = IPV6_MAX_BITLEN; + + alist = access_list_lookup(AFI_IP6, (char *)rule); + if (!alist) + return RMAP_NOMATCH; + + if (access_list_apply(alist, &p) == FILTER_PERMIT) + return RMAP_MATCH; + + if (path->attr->mp_nexthop_len + == BGP_ATTR_NHLEN_IPV6_GLOBAL_AND_LL) { + p.prefix = path->attr->mp_nexthop_local; + if (access_list_apply(alist, &p) == FILTER_PERMIT) + return RMAP_MATCH; + } + } + + return RMAP_NOMATCH; +} + +static void *route_match_ipv6_next_hop_compile(const char *arg) +{ + return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg); +} + +static void route_match_ipv6_next_hop_free(void *rule) +{ + XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); +} + +static const struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = { + "ipv6 next-hop", + route_match_ipv6_next_hop, + route_match_ipv6_next_hop_compile, + route_match_ipv6_next_hop_free +}; + /* `match ipv6 next-hop IP_ADDRESS' */ static enum route_map_cmd_result_t -route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, void *object) +route_match_ipv6_next_hop_address(void *rule, const struct prefix *prefix, + void *object) { struct in6_addr *addr = rule; struct bgp_path_info *path; @@ -3043,7 +3144,7 @@ route_match_ipv6_next_hop(void *rule, const struct prefix *prefix, void *object) return RMAP_NOMATCH; } -static void *route_match_ipv6_next_hop_compile(const char *arg) +static void *route_match_ipv6_next_hop_address_compile(const char *arg) { struct in6_addr *address; int ret; @@ -3059,16 +3160,16 @@ static void *route_match_ipv6_next_hop_compile(const char *arg) return address; } -static void route_match_ipv6_next_hop_free(void *rule) +static void route_match_ipv6_next_hop_address_free(void *rule) { XFREE(MTYPE_ROUTE_MAP_COMPILED, rule); } -static const struct route_map_rule_cmd route_match_ipv6_next_hop_cmd = { - "ipv6 next-hop", - route_match_ipv6_next_hop, - route_match_ipv6_next_hop_compile, - route_match_ipv6_next_hop_free +static const struct route_map_rule_cmd route_match_ipv6_next_hop_address_cmd = { + "ipv6 next-hop address", + route_match_ipv6_next_hop_address, + route_match_ipv6_next_hop_address_compile, + route_match_ipv6_next_hop_address_free }; /* `match ip next-hop IP_ADDRESS' */ @@ -4004,7 +4105,7 @@ static void bgp_route_map_event(const char *rmap_name) DEFUN_YANG (match_mac_address, match_mac_address_cmd, - "match mac address WORD", + "match mac address ACCESSLIST_MAC_NAME", MATCH_STR "mac address\n" "Match address of route\n" @@ -4024,7 +4125,7 @@ DEFUN_YANG (match_mac_address, DEFUN_YANG (no_match_mac_address, no_match_mac_address_cmd, - "no match mac address WORD", + "no match mac address ACCESSLIST_MAC_NAME", NO_STR MATCH_STR "mac\n" @@ -4576,13 +4677,11 @@ DEFUN_YANG (no_match_probability, DEFPY_YANG (match_ip_route_source, match_ip_route_source_cmd, - "match ip route-source <(1-199)|(1300-2699)|WORD>", + "match ip route-source ACCESSLIST4_NAME", MATCH_STR IP_STR "Match advertising source address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" - "IP standard access-list name\n") + "IP Access-list name\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:ip-route-source']"; @@ -4602,14 +4701,12 @@ DEFPY_YANG (match_ip_route_source, DEFUN_YANG (no_match_ip_route_source, no_match_ip_route_source_cmd, - "no match ip route-source [<(1-199)|(1300-2699)|WORD>]", + "no match ip route-source [ACCESSLIST4_NAME]", NO_STR MATCH_STR IP_STR "Match advertising source address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" - "IP standard access-list name\n") + "IP Access-list name\n") { const char *xpath = "./match-condition[condition='frr-bgp-route-map:ip-route-source']"; @@ -4620,7 +4717,7 @@ DEFUN_YANG (no_match_ip_route_source, DEFUN_YANG (match_ip_route_source_prefix_list, match_ip_route_source_prefix_list_cmd, - "match ip route-source prefix-list WORD", + "match ip route-source prefix-list PREFIXLIST_NAME", MATCH_STR IP_STR "Match advertising source address of route\n" @@ -4644,7 +4741,7 @@ DEFUN_YANG (match_ip_route_source_prefix_list, DEFUN_YANG (no_match_ip_route_source_prefix_list, no_match_ip_route_source_prefix_list_cmd, - "no match ip route-source prefix-list [WORD]", + "no match ip route-source prefix-list [PREFIXLIST_NAME]", NO_STR MATCH_STR IP_STR @@ -4765,7 +4862,7 @@ DEFUN_YANG(no_match_alias, no_match_alias_cmd, "no match alias [ALIAS_NAME]", DEFPY_YANG (match_community, match_community_cmd, - "match community <(1-99)|(100-500)|WORD> [exact-match]", + "match community <(1-99)|(100-500)|COMMUNITY_LIST_NAME> [exact-match]", MATCH_STR "Match BGP community list\n" "Community-list number (standard)\n" @@ -4808,7 +4905,7 @@ DEFPY_YANG (match_community, DEFUN_YANG (no_match_community, no_match_community_cmd, - "no match community [<(1-99)|(100-500)|WORD> [exact-match]]", + "no match community [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> [exact-match]]", NO_STR MATCH_STR "Match BGP community list\n" @@ -4826,7 +4923,7 @@ DEFUN_YANG (no_match_community, DEFPY_YANG (match_lcommunity, match_lcommunity_cmd, - "match large-community <(1-99)|(100-500)|WORD> [exact-match]", + "match large-community <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [exact-match]", MATCH_STR "Match BGP large community list\n" "Large Community-list number (standard)\n" @@ -4869,7 +4966,7 @@ DEFPY_YANG (match_lcommunity, DEFUN_YANG (no_match_lcommunity, no_match_lcommunity_cmd, - "no match large-community [<(1-99)|(100-500)|WORD> [exact-match]]", + "no match large-community [<(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [exact-match]]", NO_STR MATCH_STR "Match BGP large community list\n" @@ -4887,7 +4984,7 @@ DEFUN_YANG (no_match_lcommunity, DEFPY_YANG (match_ecommunity, match_ecommunity_cmd, - "match extcommunity <(1-99)|(100-500)|WORD>", + "match extcommunity <(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME>", MATCH_STR "Match BGP/VPN extended community list\n" "Extended community-list number (standard)\n" @@ -4913,7 +5010,7 @@ DEFPY_YANG (match_ecommunity, DEFUN_YANG (no_match_ecommunity, no_match_ecommunity_cmd, - "no match extcommunity [<(1-99)|(100-500)|WORD>]", + "no match extcommunity [<(1-99)|(100-500)|EXTCOMMUNITY_LIST_NAME>]", NO_STR MATCH_STR "Match BGP/VPN extended community list\n" @@ -4931,7 +5028,7 @@ DEFUN_YANG (no_match_ecommunity, DEFUN_YANG (match_aspath, match_aspath_cmd, - "match as-path WORD", + "match as-path AS_PATH_FILTER_NAME", MATCH_STR "Match BGP AS path list\n" "AS path access-list name\n") @@ -4954,7 +5051,7 @@ DEFUN_YANG (match_aspath, DEFUN_YANG (no_match_aspath, no_match_aspath_cmd, - "no match as-path [WORD]", + "no match as-path [AS_PATH_FILTER_NAME]", NO_STR MATCH_STR "Match BGP AS path list\n" @@ -5526,7 +5623,7 @@ ALIAS_YANG (no_set_community, DEFPY_YANG (set_community_delete, set_community_delete_cmd, - "set comm-list <(1-99)|(100-500)|WORD> delete", + "set comm-list <(1-99)|(100-500)|COMMUNITY_LIST_NAME> delete", SET_STR "set BGP community list (for deletion)\n" "Community-list number (standard)\n" @@ -5553,7 +5650,7 @@ DEFPY_YANG (set_community_delete, DEFUN_YANG (no_set_community_delete, no_set_community_delete_cmd, - "no set comm-list [<(1-99)|(100-500)|WORD> delete]", + "no set comm-list [<(1-99)|(100-500)|COMMUNITY_LIST_NAME> delete]", NO_STR SET_STR "set BGP community list (for deletion)\n" @@ -5653,7 +5750,7 @@ ALIAS_YANG (no_set_lcommunity1, DEFPY_YANG (set_lcommunity_delete, set_lcommunity_delete_cmd, - "set large-comm-list <(1-99)|(100-500)|WORD> delete", + "set large-comm-list <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> delete", SET_STR "set BGP large community list (for deletion)\n" "Large Community-list number (standard)\n" @@ -5679,7 +5776,7 @@ DEFPY_YANG (set_lcommunity_delete, DEFUN_YANG (no_set_lcommunity_delete, no_set_lcommunity_delete_cmd, - "no set large-comm-list <(1-99)|(100-500)|WORD> [delete]", + "no set large-comm-list <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME> [delete]", NO_STR SET_STR "set BGP large community list (for deletion)\n" @@ -6051,10 +6148,48 @@ DEFUN_YANG (no_set_aggregator_as, DEFUN_YANG (match_ipv6_next_hop, match_ipv6_next_hop_cmd, - "match ipv6 next-hop X:X::X:X", + "match ipv6 next-hop ACCESSLIST6_NAME", + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 access-list name\n") +{ + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-next-hop-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[argc - 1]->arg); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_match_ipv6_next_hop, + no_match_ipv6_next_hop_cmd, + "no match ipv6 next-hop [ACCESSLIST6_NAME]", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 access-list name\n") +{ + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-next-hop-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (match_ipv6_next_hop_address, + match_ipv6_next_hop_address_cmd, + "match ipv6 next-hop address X:X::X:X", MATCH_STR IPV6_STR "Match IPv6 next-hop address of route\n" + "IPv6 address\n" "IPv6 address of next hop\n") { const char *xpath = @@ -6065,18 +6200,20 @@ DEFUN_YANG (match_ipv6_next_hop, snprintf(xpath_value, sizeof(xpath_value), "%s/rmap-match-condition/frr-bgp-route-map:ipv6-address", xpath); - nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, argv[3]->arg); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[argc - 1]->arg); return nb_cli_apply_changes(vty, NULL); } -DEFUN_YANG (no_match_ipv6_next_hop, - no_match_ipv6_next_hop_cmd, - "no match ipv6 next-hop X:X::X:X", +DEFUN_YANG (no_match_ipv6_next_hop_address, + no_match_ipv6_next_hop_address_cmd, + "no match ipv6 next-hop address X:X::X:X", NO_STR MATCH_STR IPV6_STR "Match IPv6 next-hop address of route\n" + "IPv6 address\n" "IPv6 address of next hop\n") { const char *xpath = @@ -6086,6 +6223,62 @@ DEFUN_YANG (no_match_ipv6_next_hop, return nb_cli_apply_changes(vty, NULL); } +ALIAS_HIDDEN (match_ipv6_next_hop_address, + match_ipv6_next_hop_old_cmd, + "match ipv6 next-hop X:X::X:X", + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") + +ALIAS_HIDDEN (no_match_ipv6_next_hop_address, + no_match_ipv6_next_hop_old_cmd, + "no match ipv6 next-hop X:X::X:X", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "IPv6 address of next hop\n") + +DEFUN_YANG (match_ipv6_next_hop_prefix_list, + match_ipv6_next_hop_prefix_list_cmd, + "match ipv6 next-hop prefix-list PREFIXLIST_NAME", + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "Match entries by prefix-list\n" + "IPv6 prefix-list name\n") +{ + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-list']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/list-name", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[argc - 1]->arg); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFUN_YANG (no_match_ipv6_next_hop_prefix_list, + no_match_ipv6_next_hop_prefix_list_cmd, + "no match ipv6 next-hop prefix-list [PREFIXLIST_NAME]", + NO_STR + MATCH_STR + IPV6_STR + "Match IPv6 next-hop address of route\n" + "Match entries by prefix-list\n" + "IPv6 prefix-list name\n") +{ + const char *xpath = + "./match-condition[condition='frr-route-map:ipv6-next-hop-prefix-list']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + DEFPY_YANG (match_ipv4_next_hop, match_ipv4_next_hop_cmd, "match ip next-hop address A.B.C.D", @@ -6445,6 +6638,9 @@ void bgp_route_map_init(void) route_map_match_ip_next_hop_hook(generic_match_add); route_map_no_match_ip_next_hop_hook(generic_match_delete); + route_map_match_ipv6_next_hop_hook(generic_match_add); + route_map_no_match_ipv6_next_hop_hook(generic_match_delete); + route_map_match_ip_next_hop_prefix_list_hook(generic_match_add); route_map_no_match_ip_next_hop_prefix_list_hook(generic_match_delete); @@ -6460,6 +6656,9 @@ void bgp_route_map_init(void) route_map_match_ipv6_next_hop_type_hook(generic_match_add); route_map_no_match_ipv6_next_hop_type_hook(generic_match_delete); + route_map_match_ipv6_next_hop_prefix_list_hook(generic_match_add); + route_map_no_match_ipv6_next_hop_prefix_list_hook(generic_match_delete); + route_map_match_metric_hook(generic_match_add); route_map_no_match_metric_hook(generic_match_delete); @@ -6642,6 +6841,8 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_ipv6_address_cmd); route_map_install_match(&route_match_ipv6_next_hop_cmd); + route_map_install_match(&route_match_ipv6_next_hop_address_cmd); + route_map_install_match(&route_match_ipv6_next_hop_prefix_list_cmd); route_map_install_match(&route_match_ipv4_next_hop_cmd); route_map_install_match(&route_match_ipv6_address_prefix_list_cmd); route_map_install_match(&route_match_ipv6_next_hop_type_cmd); @@ -6651,7 +6852,13 @@ void bgp_route_map_init(void) route_map_install_set(&route_set_ipv6_nexthop_peer_cmd); install_element(RMAP_NODE, &match_ipv6_next_hop_cmd); + install_element(RMAP_NODE, &match_ipv6_next_hop_address_cmd); + install_element(RMAP_NODE, &match_ipv6_next_hop_prefix_list_cmd); install_element(RMAP_NODE, &no_match_ipv6_next_hop_cmd); + install_element(RMAP_NODE, &no_match_ipv6_next_hop_address_cmd); + install_element(RMAP_NODE, &no_match_ipv6_next_hop_prefix_list_cmd); + install_element(RMAP_NODE, &match_ipv6_next_hop_old_cmd); + install_element(RMAP_NODE, &no_match_ipv6_next_hop_old_cmd); install_element(RMAP_NODE, &match_ipv4_next_hop_cmd); install_element(RMAP_NODE, &no_match_ipv4_next_hop_cmd); install_element(RMAP_NODE, &set_ipv6_nexthop_global_cmd); diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 09a6be4010..773538ee41 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -1234,7 +1234,7 @@ lib_route_map_entry_match_condition_rmap_match_condition_ipv6_address_modify( /* Set destroy information. */ rhc->rhc_mhook = bgp_route_match_delete; - rhc->rhc_rule = "ipv6 next-hop"; + rhc->rhc_rule = "ipv6 next-hop address"; rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; ret = bgp_route_match_add(rhc->rhc_rmi, rhc->rhc_rule, diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 376172a6f9..4ed8c7c59b 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -88,7 +88,7 @@ struct bgp_dest *bgp_dest_lock_node(struct bgp_dest *dest) const char *bgp_dest_get_prefix_str(struct bgp_dest *dest) { const struct prefix *p = NULL; - char str[PREFIX_STRLEN] = {0}; + static char str[PREFIX_STRLEN] = {0}; p = bgp_dest_get_prefix(dest); if (p) diff --git a/bgpd/bgp_trace.h b/bgpd/bgp_trace.h index 91a190722b..14149b5139 100644 --- a/bgpd/bgp_trace.h +++ b/bgpd/bgp_trace.h @@ -334,6 +334,147 @@ TRACEPOINT_EVENT( ) ) TRACEPOINT_LOGLEVEL(frr_bgp, evpn_nh_rmac_zsend, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_local_es_add_zrecv, + TP_ARGS(esi_t *, esi, struct in_addr, vtep, + uint8_t, active, uint8_t, bypass, uint16_t, df_pref), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_integer(uint8_t, active, active) + ctf_integer(uint8_t, bypass, bypass) + ctf_integer(uint16_t, df_pref, df_pref) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_es_add_zrecv, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_local_es_del_zrecv, + TP_ARGS(esi_t *, esi), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_es_del_zrecv, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_local_es_evi_add_zrecv, + TP_ARGS(esi_t *, esi, vni_t, vni), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_es_evi_add_zrecv, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_mh_local_es_evi_del_zrecv, + TP_ARGS(esi_t *, esi, vni_t, vni), + TP_FIELDS( + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer(vni_t, vni, vni) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_mh_local_es_evi_del_zrecv, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_local_vni_add_zrecv, + TP_ARGS(vni_t, vni, struct in_addr, vtep, vrf_id_t, vrf, + struct in_addr, mc_grp), + TP_FIELDS( + ctf_integer(vni_t, vni, vni) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_integer_network_hex(unsigned int, mc_grp, + mc_grp.s_addr) + ctf_integer(int, vrf, vrf) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_local_vni_add_zrecv, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_local_vni_del_zrecv, + TP_ARGS(vni_t, vni), + TP_FIELDS( + ctf_integer(vni_t, vni, vni) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_local_vni_del_zrecv, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_local_macip_add_zrecv, + TP_ARGS(vni_t, vni, struct ethaddr *, mac, + struct ipaddr *, ip, uint32_t, flags, + uint32_t, seqnum, esi_t *, esi), + TP_FIELDS( + ctf_integer(vni_t, vni, vni) + ctf_array(unsigned char, mac, mac, + sizeof(struct ethaddr)) + ctf_array(unsigned char, ip, ip, + sizeof(struct ipaddr)) + ctf_integer(uint32_t, flags, flags) + ctf_integer(uint32_t, seq, seqnum) + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_local_macip_add_zrecv, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_local_macip_del_zrecv, + TP_ARGS(vni_t, vni, struct ethaddr *, mac, struct ipaddr *, ip, + int, state), + TP_FIELDS( + ctf_integer(vni_t, vni, vni) + ctf_array(unsigned char, mac, mac, + sizeof(struct ethaddr)) + ctf_array(unsigned char, ip, ip, + sizeof(struct ipaddr)) + ctf_integer(int, state, state) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_local_macip_del_zrecv, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_local_l3vni_add_zrecv, + TP_ARGS(vni_t, vni, vrf_id_t, vrf, + struct ethaddr *, svi_rmac, + struct ethaddr *, vrr_rmac, int, filter, + struct in_addr, vtep, int, svi_ifindex, + bool, anycast_mac), + TP_FIELDS( + ctf_integer(vni_t, vni, vni) + ctf_integer(int, vrf, vrf) + ctf_array(unsigned char, svi_rmac, svi_rmac, + sizeof(struct ethaddr)) + ctf_array(unsigned char, vrr_rmac, vrr_rmac, + sizeof(struct ethaddr)) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_integer(int, filter, filter) + ctf_integer(int, svi_ifindex, svi_ifindex) + ctf_string(anycast_mac, anycast_mac ? "y" : "n") + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_local_l3vni_add_zrecv, TRACE_INFO) + +TRACEPOINT_EVENT( + frr_bgp, + evpn_local_l3vni_del_zrecv, + TP_ARGS(vni_t, vni, vrf_id_t, vrf), + TP_FIELDS( + ctf_integer(vni_t, vni, vni) + ctf_integer(int, vrf, vrf) + ) +) +TRACEPOINT_LOGLEVEL(frr_bgp, evpn_local_l3vni_del_zrecv, TRACE_INFO) /* clang-format on */ #include <lttng/tracepoint-event.h> diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index 96febcd5df..c6ddb1c1a7 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -553,7 +553,7 @@ void bgp_adj_out_set_subgroup(struct bgp_dest *dest, bgp_adv_fifo_add_tail(&subgrp->sync->update, adv); - subgrp->version = max(subgrp->version, dest->version); + subgrp->version = MAX(subgrp->version, dest->version); } /* The only time 'withdraw' will be false is if we are sending @@ -609,7 +609,7 @@ void bgp_adj_out_unset_subgroup(struct bgp_dest *dest, } } - subgrp->version = max(subgrp->version, dest->version); + subgrp->version = MAX(subgrp->version, dest->version); } void bgp_adj_out_remove_subgroup(struct bgp_dest *dest, struct bgp_adj_out *adj, @@ -686,11 +686,21 @@ void subgroup_announce_table(struct update_subgroup *subgrp, dest_p, &attr, false)) { /* Check if route can be advertised */ - if (advertise) - bgp_adj_out_set_subgroup(dest, - subgrp, - &attr, - ri); + if (advertise) { + if (!bgp_check_withdrawal(bgp, + dest)) + bgp_adj_out_set_subgroup( + dest, subgrp, + &attr, ri); + else + bgp_adj_out_unset_subgroup( + dest, subgrp, 1, + bgp_addpath_id_for_peer( + peer, + afi, + safi, + &ri->tx_addpath)); + } } else { /* If default originate is enabled for * the peer, do not send explicit @@ -721,7 +731,7 @@ void subgroup_announce_table(struct update_subgroup *subgrp, * covers the pathological case where all routes in the table have * now been deleted. */ - subgrp->version = max(subgrp->version, table->version); + subgrp->version = MAX(subgrp->version, table->version); /* * Start a task to merge the subgroup if necessary. diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index 8d2cffbb47..6308936aa8 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -118,15 +118,11 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, if (header) { if (use_json) { - char buf[BUFSIZ] = {0}; - json_object_int_add( json, "bgpTableVersion", 0); - json_object_string_add( + json_object_string_addf( json, "bgpLocalRouterId", - inet_ntop(AF_INET, - &bgp->router_id, buf, - sizeof(buf))); + "%pI4", &bgp->router_id); json_object_int_add( json, "defaultLocPrf", @@ -243,9 +239,7 @@ int show_adj_route_vpn(struct vty *vty, struct peer *peer, json_object_object_add(json, "advertisedRoutes", json_adv); json_object_int_add(json, "totalPrefixCounter", output_count); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else vty_out(vty, "\nTotal number of prefixes %ld\n", output_count); diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index 14f4fb7310..d6fdbfd0d0 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -645,10 +645,7 @@ int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, json_object_string_add( json, "warning", "View/Vrf is unknown"); - vty_out(vty, "%s\n", - json_object_to_json_string_ext(json, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else vty_out(vty, "View/Vrf %s is unknown\n", @@ -666,10 +663,7 @@ int bgp_vty_find_and_parse_afi_safi_bgp(struct vty *vty, json_object_string_add( json, "warning", "Default BGP instance not found"); - vty_out(vty, "%s\n", - json_object_to_json_string_ext(json, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else vty_out(vty, @@ -1354,6 +1348,10 @@ DEFUN_NOSH (router_bgp, else { as = strtoul(argv[idx_asn]->arg, NULL, 10); + if (as == BGP_PRIVATE_AS_MAX || as == BGP_AS4_MAX) + vty_out(vty, "Reserved AS used (%u|%u); AS is %u\n", + BGP_PRIVATE_AS_MAX, BGP_AS4_MAX, as); + inst_type = BGP_INSTANCE_TYPE_DEFAULT; if (argc > 3) { name = argv[idx_vrf]->arg; @@ -2710,7 +2708,7 @@ DEFUN (bgp_graceful_restart_stalepath_time, DEFUN (bgp_graceful_restart_restart_time, bgp_graceful_restart_restart_time_cmd, - "bgp graceful-restart restart-time (1-4095)", + "bgp graceful-restart restart-time (0-4095)", BGP_STR "Graceful restart capability parameters\n" "Set the time to wait to delete stale routes before a BGP open message is received\n" @@ -2764,7 +2762,7 @@ DEFUN (no_bgp_graceful_restart_stalepath_time, DEFUN (no_bgp_graceful_restart_restart_time, no_bgp_graceful_restart_restart_time_cmd, - "no bgp graceful-restart restart-time [(1-4095)]", + "no bgp graceful-restart restart-time [(0-4095)]", NO_STR BGP_STR "Graceful restart capability parameters\n" @@ -3168,6 +3166,37 @@ DEFUN (no_bgp_graceful_restart_rib_stale_time, return CMD_SUCCESS; } +DEFUN(bgp_llgr_stalepath_time, bgp_llgr_stalepath_time_cmd, + "bgp long-lived-graceful-restart stale-time (1-4294967295)", + BGP_STR + "Enable Long-lived Graceful Restart\n" + "Specifies maximum time to wait before purging long-lived stale routes\n" + "Stale time value (seconds)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + uint32_t llgr_stale_time; + + llgr_stale_time = strtoul(argv[3]->arg, NULL, 10); + bgp->llgr_stale_time = llgr_stale_time; + + return CMD_SUCCESS; +} + +DEFUN(no_bgp_llgr_stalepath_time, no_bgp_llgr_stalepath_time_cmd, + "no bgp long-lived-graceful-restart stale-time [(1-4294967295)]", + NO_STR BGP_STR + "Enable Long-lived Graceful Restart\n" + "Specifies maximum time to wait before purging long-lived stale routes\n" + "Stale time value (seconds)\n") +{ + VTY_DECLVAR_CONTEXT(bgp, bgp); + + bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME; + + return CMD_SUCCESS; +} + static inline void bgp_initiate_graceful_shut_unshut(struct vty *vty, struct bgp *bgp) { @@ -4205,6 +4234,12 @@ DEFPY(bgp_shutdown_msg, bgp_shutdown_msg_cmd, "bgp shutdown message MSG...", if (argc > 3) msgstr = argv_concat(argv, argc, 3); + if (msgstr && strlen(msgstr) > BGP_ADMIN_SHUTDOWN_MSG_LEN) { + vty_out(vty, "%% Shutdown message size exceeded %d\n", + BGP_ADMIN_SHUTDOWN_MSG_LEN); + return CMD_WARNING_CONFIG_FAILED; + } + bgp_shutdown_enable(bgp, msgstr); XFREE(MTYPE_TMP, msgstr); @@ -6278,6 +6313,30 @@ DEFUN(no_neighbor_disable_link_bw_encoding_ieee, PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE); } +/* extended-optional-parameters */ +DEFUN(neighbor_extended_optional_parameters, + neighbor_extended_optional_parameters_cmd, + "neighbor <A.B.C.D|X:X::X:X|WORD> extended-optional-parameters", + NEIGHBOR_STR NEIGHBOR_ADDR_STR2 + "Force the extended optional parameters format for OPEN messages\n") +{ + int idx_peer = 1; + + return peer_flag_set_vty(vty, argv[idx_peer]->arg, + PEER_FLAG_EXTENDED_OPT_PARAMS); +} + +DEFUN(no_neighbor_extended_optional_parameters, + no_neighbor_extended_optional_parameters_cmd, + "no neighbor <A.B.C.D|X:X::X:X|WORD> extended-optional-parameters", + NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 + "Force the extended optional parameters format for OPEN messages\n") +{ + int idx_peer = 2; + + return peer_flag_unset_vty(vty, argv[idx_peer]->arg, + PEER_FLAG_EXTENDED_OPT_PARAMS); +} /* enforce-first-as */ DEFUN (neighbor_enforce_first_as, @@ -7018,12 +7077,10 @@ DEFUN (no_neighbor_interface, DEFUN (neighbor_distribute_list, neighbor_distribute_list_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list <(1-199)|(1300-2699)|WORD> <in|out>", + "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n" "Filter incoming updates\n" "Filter outgoing updates\n") @@ -7051,24 +7108,20 @@ DEFUN (neighbor_distribute_list, ALIAS_HIDDEN( neighbor_distribute_list, neighbor_distribute_list_hidden_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list <(1-199)|(1300-2699)|WORD> <in|out>", + "neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n" "Filter incoming updates\n" "Filter outgoing updates\n") DEFUN (no_neighbor_distribute_list, no_neighbor_distribute_list_cmd, - "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list <(1-199)|(1300-2699)|WORD> <in|out>", + "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n" "Filter incoming updates\n" "Filter outgoing updates\n") @@ -7094,11 +7147,9 @@ DEFUN (no_neighbor_distribute_list, ALIAS_HIDDEN( no_neighbor_distribute_list, no_neighbor_distribute_list_hidden_cmd, - "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list <(1-199)|(1300-2699)|WORD> <in|out>", + "no neighbor <A.B.C.D|X:X::X:X|WORD> distribute-list ACCESSLIST_NAME <in|out>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Filter updates to/from this neighbor\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n" "Filter incoming updates\n" "Filter outgoing updates\n") @@ -7250,7 +7301,7 @@ static int peer_aslist_unset_vty(struct vty *vty, const char *ip_str, afi_t afi, DEFUN (neighbor_filter_list, neighbor_filter_list_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> filter-list WORD <in|out>", + "neighbor <A.B.C.D|X:X::X:X|WORD> filter-list AS_PATH_FILTER_NAME <in|out>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Establish BGP filters\n" @@ -7267,7 +7318,7 @@ DEFUN (neighbor_filter_list, } ALIAS_HIDDEN(neighbor_filter_list, neighbor_filter_list_hidden_cmd, - "neighbor <A.B.C.D|X:X::X:X|WORD> filter-list WORD <in|out>", + "neighbor <A.B.C.D|X:X::X:X|WORD> filter-list AS_PATH_FILTER_NAME <in|out>", NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Establish BGP filters\n" "AS path access-list name\n" @@ -7276,7 +7327,7 @@ ALIAS_HIDDEN(neighbor_filter_list, neighbor_filter_list_hidden_cmd, DEFUN (no_neighbor_filter_list, no_neighbor_filter_list_cmd, - "no neighbor <A.B.C.D|X:X::X:X|WORD> filter-list WORD <in|out>", + "no neighbor <A.B.C.D|X:X::X:X|WORD> filter-list AS_PATH_FILTER_NAME <in|out>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 @@ -7293,7 +7344,7 @@ DEFUN (no_neighbor_filter_list, } ALIAS_HIDDEN(no_neighbor_filter_list, no_neighbor_filter_list_hidden_cmd, - "no neighbor <A.B.C.D|X:X::X:X|WORD> filter-list WORD <in|out>", + "no neighbor <A.B.C.D|X:X::X:X|WORD> filter-list AS_PATH_FILTER_NAME <in|out>", NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2 "Establish BGP filters\n" "AS path access-list name\n" @@ -9668,10 +9719,8 @@ DEFUN (show_bgp_vrfs, json_object_string_add(json_vrf, "type", type); json_object_int_add(json_vrf, "vrfId", vrf_id_ui); - json_object_string_add(json_vrf, "routerId", - inet_ntop(AF_INET, - &bgp->router_id, buf, - sizeof(buf))); + json_object_string_addf(json_vrf, "routerId", "%pI4", + &bgp->router_id); json_object_int_add(json_vrf, "numConfiguredPeers", peers_cfg); json_object_int_add(json_vrf, "numEstablishedPeers", @@ -9704,9 +9753,7 @@ DEFUN (show_bgp_vrfs, json_object_int_add(json, "totalVrfs", count); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { if (count) vty_out(vty, @@ -10238,9 +10285,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, json_object_int_add(json, "dynamicPeers", dn_count); json_object_int_add(json, "totalPeers", count); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { vty_out(vty, "%% No failed BGP neighbors found\n"); } @@ -10249,6 +10294,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, count = 0; /* Reset the value as its used again */ filtered_count = 0; + dn_count = 0; for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) continue; @@ -10267,12 +10313,9 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, /* Usage summary and header */ if (use_json) { - char buf[BUFSIZ] = {0}; - - json_object_string_add( - json, "routerId", - inet_ntop(AF_INET, &bgp->router_id, buf, - sizeof(buf))); + json_object_string_addf(json, "routerId", + "%pI4", + &bgp->router_id); json_object_int_add(json, "as", bgp->as); json_object_int_add(json, "vrfId", vrf_id_ui); json_object_string_add( @@ -10811,9 +10854,7 @@ static int bgp_show_summary(struct vty *vty, struct bgp *bgp, int afi, int safi, if (!show_failed) bgp_show_bestpath_json(bgp, json); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { if (count) { if (filtered_count == count) @@ -12345,10 +12386,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, p->group, &prefix); if (range) { - prefix2str(range, buf1, sizeof(buf1)); - json_object_string_add( + json_object_string_addf( json_neigh, - "peerSubnetRangeGroup", buf1); + "peerSubnetRangeGroup", "%pFX", + range); } } } else { @@ -12381,13 +12422,10 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, /* BGP Version. */ json_object_int_add(json_neigh, "bgpVersion", 4); - json_object_string_add( - json_neigh, "remoteRouterId", - inet_ntop(AF_INET, &p->remote_id, buf1, sizeof(buf1))); - json_object_string_add( - json_neigh, "localRouterId", - inet_ntop(AF_INET, &bgp->router_id, buf1, - sizeof(buf1))); + json_object_string_addf(json_neigh, "remoteRouterId", "%pI4", + &p->remote_id); + json_object_string_addf(json_neigh, "localRouterId", "%pI4", + &bgp->router_id); /* Confederation */ if (CHECK_FLAG(bgp->config, BGP_CONFIG_CONFEDERATION) @@ -12494,6 +12532,14 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, "bgpTimerConfiguredKeepAliveIntervalMsecs", bgp->default_keepalive); } + + /* Extended Optional Parameters Length for BGP OPEN Message */ + if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(p)) + json_object_boolean_true_add( + json_neigh, "extendedOptionalParametersLength"); + else + json_object_boolean_false_add( + json_neigh, "extendedOptionalParametersLength"); } else { /* Administrative shutdown. */ if (CHECK_FLAG(p->flags, PEER_FLAG_SHUTDOWN) @@ -12566,6 +12612,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, " Configured tcp-mss is %d", p->tcp_mss); vty_out(vty, ", synced tcp-mss is %d\n", sync_tcp_mss); } + + /* Extended Optional Parameters Length for BGP OPEN Message */ + if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(p)) + vty_out(vty, + " Extended Optional Parameters Length is enabled\n"); } /* Capability. */ if (peer_established(p)) { @@ -12845,6 +12896,61 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, } } + /* Long-lived Graceful Restart */ + if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV) + || CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) { + json_object *json_llgr = NULL; + const char *afi_safi_str; + + if (CHECK_FLAG(p->cap, + PEER_CAP_LLGR_ADV) + && CHECK_FLAG(p->cap, + PEER_CAP_LLGR_RCV)) + json_object_string_add( + json_cap, + "longLivedGracefulRestart", + "advertisedAndReceived"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_LLGR_ADV)) + json_object_string_add( + json_cap, + "longLivedGracefulRestart", + "advertised"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_LLGR_RCV)) + json_object_string_add( + json_cap, + "longLivedGracefulRestart", + "received"); + + if (CHECK_FLAG(p->cap, + PEER_CAP_LLGR_RCV)) { + json_llgr = + json_object_new_object(); + + FOREACH_AFI_SAFI (afi, safi) { + if (CHECK_FLAG( + p->af_cap + [afi] + [safi], + PEER_CAP_ENHE_AF_RCV)) { + afi_safi_str = get_afi_safi_str( + afi, + safi, + true); + json_object_string_add( + json_llgr, + afi_safi_str, + "received"); + } + } + json_object_object_add( + json_cap, + "longLivedGracefulRestartByPeer", + json_llgr); + } + } + /* Route Refresh */ if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) || CHECK_FLAG(p->cap, @@ -13285,6 +13391,43 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, } } + /* Long-lived Graceful Restart */ + if (CHECK_FLAG(p->cap, PEER_CAP_LLGR_RCV) + || CHECK_FLAG(p->cap, PEER_CAP_LLGR_ADV)) { + vty_out(vty, + " Long-lived Graceful Restart:"); + if (CHECK_FLAG(p->cap, + PEER_CAP_LLGR_ADV)) + vty_out(vty, " advertised"); + if (CHECK_FLAG(p->cap, + PEER_CAP_LLGR_RCV)) + vty_out(vty, " %sreceived", + CHECK_FLAG( + p->cap, + PEER_CAP_LLGR_ADV) + ? "and " + : ""); + vty_out(vty, "\n"); + + if (CHECK_FLAG(p->cap, + PEER_CAP_LLGR_RCV)) { + vty_out(vty, + " Address families by peer:\n"); + FOREACH_AFI_SAFI (afi, safi) + if (CHECK_FLAG( + p->af_cap + [afi] + [safi], + PEER_CAP_LLGR_AF_RCV)) + vty_out(vty, + " %s\n", + get_afi_safi_str( + afi, + safi, + false)); + } + } + /* Route Refresh */ if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) || CHECK_FLAG(p->cap, @@ -13884,18 +14027,12 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, /* Nexthop display. */ if (p->su_local) { if (use_json) { - json_object_string_add(json_neigh, "nexthop", - inet_ntop(AF_INET, - &p->nexthop.v4, buf1, - sizeof(buf1))); - json_object_string_add(json_neigh, "nexthopGlobal", - inet_ntop(AF_INET6, - &p->nexthop.v6_global, - buf1, sizeof(buf1))); - json_object_string_add(json_neigh, "nexthopLocal", - inet_ntop(AF_INET6, - &p->nexthop.v6_local, - buf1, sizeof(buf1))); + json_object_string_addf(json_neigh, "nexthop", "%pI4", + &p->nexthop.v4); + json_object_string_addf(json_neigh, "nexthopGlobal", + "%pI6", &p->nexthop.v6_global); + json_object_string_addf(json_neigh, "nexthopLocal", + "%pI6", &p->nexthop.v6_local); if (p->shared_network) json_object_string_add(json_neigh, "bgpConnection", @@ -14077,13 +14214,9 @@ static int bgp_show_neighbor_graceful_restart(struct vty *vty, struct bgp *bgp, vty_out(vty, "%% No such neighbor\n"); } if (use_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - if (json_neighbor) json_object_free(json_neighbor); - json_object_free(json); + vty_json(vty, json); } else { vty_out(vty, "\n"); } @@ -14323,11 +14456,7 @@ static int bgp_show_neighbor_vty(struct vty *vty, const char *name, if (!bgp) { if (use_json) { json = json_object_new_object(); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else vty_out(vty, "%% BGP instance not found\n"); @@ -14636,11 +14765,7 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); if (!bgp) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); return CMD_WARNING; } @@ -14712,10 +14837,7 @@ static int bgp_show_route_leak_vty(struct vty *vty, const char *name, } if (use_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext(json, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } } else { bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); @@ -14827,9 +14949,7 @@ static int bgp_show_all_instance_route_leak_vty(struct vty *vty, afi_t afi, if (use_json) { json_object_object_add(json, "vrfs", json_vrfs); - vty_out(vty, "%s\n", json_object_to_json_string_ext(json, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } return CMD_SUCCESS; @@ -14874,9 +14994,8 @@ DEFUN (show_ip_bgp_route_leak, vrf = NULL; } /* ["BGP_AFI_CMD_STR" ["BGP_SAFI_CMD_STR"]] */ - if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) { + if (argv_find_and_parse_afi(argv, argc, &idx, &afi)) argv_find_and_parse_safi(argv, argc, &idx, &safi); - } if (!((afi == AFI_IP || afi == AFI_IP6) && safi == SAFI_UNICAST)) { vty_out(vty, @@ -15308,14 +15427,10 @@ static int bgp_show_peer_group_vty(struct vty *vty, const char *name, bgp = name ? bgp_lookup_by_name(name) : bgp_get_default(); if (!bgp) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else { + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% BGP instance not found\n"); - } return CMD_WARNING; } @@ -15335,12 +15450,8 @@ static int bgp_show_peer_group_vty(struct vty *vty, const char *name, if (group_name && !found && !uj) vty_out(vty, "%% No such peer-group\n"); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -16573,6 +16684,11 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp, vty_out(vty, " neighbor %s disable-link-bw-encoding-ieee\n", addr); + /* extended-optional-parameters */ + if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_OPT_PARAMS)) + vty_out(vty, " neighbor %s extended-optional-parameters\n", + addr); + /* enforce-first-as */ if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS)) vty_out(vty, " neighbor %s enforce-first-as\n", addr); @@ -17260,6 +17376,12 @@ int bgp_config_write(struct vty *vty) if (CHECK_FLAG(bgp->flags, BGP_FLAG_GRACEFUL_SHUTDOWN)) vty_out(vty, " bgp graceful-shutdown\n"); + /* Long-lived Graceful Restart */ + if (bgp->llgr_stale_time != BGP_DEFAULT_LLGR_STALE_TIME) + vty_out(vty, + " bgp long-lived-graceful-restart stale-time %u\n", + bgp->llgr_stale_time); + /* BGP graceful-restart. */ if (bgp->stalepath_time != BGP_DEFAULT_STALEPATH_TIME) vty_out(vty, @@ -17472,6 +17594,7 @@ static struct cmd_node bgp_ipv4_unicast_node = { .node = BGP_IPV4_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv4_multicast_node = { @@ -17479,6 +17602,7 @@ static struct cmd_node bgp_ipv4_multicast_node = { .node = BGP_IPV4M_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv4_labeled_unicast_node = { @@ -17486,6 +17610,7 @@ static struct cmd_node bgp_ipv4_labeled_unicast_node = { .node = BGP_IPV4L_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv6_unicast_node = { @@ -17493,6 +17618,7 @@ static struct cmd_node bgp_ipv6_unicast_node = { .node = BGP_IPV6_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv6_multicast_node = { @@ -17500,6 +17626,7 @@ static struct cmd_node bgp_ipv6_multicast_node = { .node = BGP_IPV6M_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv6_labeled_unicast_node = { @@ -17507,6 +17634,7 @@ static struct cmd_node bgp_ipv6_labeled_unicast_node = { .node = BGP_IPV6L_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_vpnv4_node = { @@ -17514,6 +17642,7 @@ static struct cmd_node bgp_vpnv4_node = { .node = BGP_VPNV4_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_vpnv6_node = { @@ -17521,6 +17650,7 @@ static struct cmd_node bgp_vpnv6_node = { .node = BGP_VPNV6_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af-vpnv6)# ", + .no_xpath = true, }; static struct cmd_node bgp_evpn_node = { @@ -17528,6 +17658,7 @@ static struct cmd_node bgp_evpn_node = { .node = BGP_EVPN_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-evpn)# ", + .no_xpath = true, }; static struct cmd_node bgp_evpn_vni_node = { @@ -17542,6 +17673,7 @@ static struct cmd_node bgp_flowspecv4_node = { .node = BGP_FLOWSPECV4_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_flowspecv6_node = { @@ -17549,6 +17681,7 @@ static struct cmd_node bgp_flowspecv6_node = { .node = BGP_FLOWSPECV6_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af-vpnv6)# ", + .no_xpath = true, }; static struct cmd_node bgp_srv6_node = { @@ -17837,6 +17970,10 @@ void bgp_vty_init(void) install_element(BGP_NODE, &bgp_graceful_shutdown_cmd); install_element(BGP_NODE, &no_bgp_graceful_shutdown_cmd); + /* "bgp long-lived-graceful-restart" commands */ + install_element(BGP_NODE, &bgp_llgr_stalepath_time_cmd); + install_element(BGP_NODE, &no_bgp_llgr_stalepath_time_cmd); + /* "bgp fast-external-failover" commands */ install_element(BGP_NODE, &bgp_fast_external_failover_cmd); install_element(BGP_NODE, &no_bgp_fast_external_failover_cmd); @@ -18509,6 +18646,11 @@ void bgp_vty_init(void) install_element(BGP_NODE, &no_neighbor_disable_link_bw_encoding_ieee_cmd); + /* "neighbor extended-optional-parameters" commands. */ + install_element(BGP_NODE, &neighbor_extended_optional_parameters_cmd); + install_element(BGP_NODE, + &no_neighbor_extended_optional_parameters_cmd); + /* "neighbor enforce-first-as" commands. */ install_element(BGP_NODE, &neighbor_enforce_first_as_cmd); install_element(BGP_NODE, &no_neighbor_enforce_first_as_cmd); @@ -19069,7 +19211,7 @@ static void community_list_perror(struct vty *vty, int ret) /*community-list standard */ DEFUN (community_list_standard, bgp_community_list_standard_cmd, - "bgp community-list <(1-99)|standard WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", + "bgp community-list <(1-99)|standard COMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...", BGP_STR COMMUNITY_LIST_STR "Community list number (standard)\n" @@ -19093,7 +19235,7 @@ DEFUN (community_list_standard, idx = 0; argv_find(argv, argc, "(1-99)", &idx); - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx); cl_name_or_number = argv[idx]->arg; direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT : COMMUNITY_DENY; @@ -19116,7 +19258,7 @@ DEFUN (community_list_standard, DEFUN (no_community_list_standard_all, no_bgp_community_list_standard_all_cmd, - "no bgp community-list <(1-99)|standard WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", + "no bgp community-list <(1-99)|standard COMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...", NO_STR BGP_STR COMMUNITY_LIST_STR @@ -19156,7 +19298,7 @@ DEFUN (no_community_list_standard_all, idx = 0; argv_find(argv, argc, "(1-99)", &idx); - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx); cl_name_or_number = argv[idx]->arg; int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq, @@ -19173,7 +19315,7 @@ DEFUN (no_community_list_standard_all, } ALIAS(no_community_list_standard_all, no_bgp_community_list_standard_all_list_cmd, - "no bgp community-list <(1-99)|standard WORD>", + "no bgp community-list <(1-99)|standard COMMUNITY_LIST_NAME>", NO_STR BGP_STR COMMUNITY_LIST_STR "Community list number (standard)\n" "Add an standard community-list entry\n" @@ -19182,7 +19324,7 @@ ALIAS(no_community_list_standard_all, no_bgp_community_list_standard_all_list_cm /*community-list expanded */ DEFUN (community_list_expanded_all, bgp_community_list_expanded_all_cmd, - "bgp community-list <(100-500)|expanded WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", + "bgp community-list <(100-500)|expanded COMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...", BGP_STR COMMUNITY_LIST_STR "Community list number (expanded)\n" @@ -19207,7 +19349,7 @@ DEFUN (community_list_expanded_all, idx = 0; argv_find(argv, argc, "(100-500)", &idx); - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx); cl_name_or_number = argv[idx]->arg; direct = argv_find(argv, argc, "permit", &idx) ? COMMUNITY_PERMIT : COMMUNITY_DENY; @@ -19230,7 +19372,7 @@ DEFUN (community_list_expanded_all, DEFUN (no_community_list_expanded_all, no_bgp_community_list_expanded_all_cmd, - "no bgp community-list <(100-500)|expanded WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", + "no bgp community-list <(100-500)|expanded COMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...", NO_STR BGP_STR COMMUNITY_LIST_STR @@ -19270,7 +19412,7 @@ DEFUN (no_community_list_expanded_all, idx = 0; argv_find(argv, argc, "(100-500)", &idx); - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "COMMUNITY_LIST_NAME", &idx); cl_name_or_number = argv[idx]->arg; int ret = community_list_unset(bgp_clist, cl_name_or_number, str, seq, @@ -19288,7 +19430,7 @@ DEFUN (no_community_list_expanded_all, ALIAS(no_community_list_expanded_all, no_bgp_community_list_expanded_all_list_cmd, - "no bgp community-list <(100-500)|expanded WORD>", + "no bgp community-list <(100-500)|expanded COMMUNITY_LIST_NAME>", NO_STR BGP_STR COMMUNITY_LIST_STR "Community list number (expanded)\n" "Add an expanded community-list entry\n" @@ -19366,7 +19508,7 @@ DEFUN (show_community_list, DEFUN (show_community_list_arg, show_bgp_community_list_arg_cmd, - "show bgp community-list <(1-500)|WORD> detail", + "show bgp community-list <(1-500)|COMMUNITY_LIST_NAME> detail", SHOW_STR BGP_STR "List community-list\n" @@ -19412,7 +19554,7 @@ static int lcommunity_list_set_vty(struct vty *vty, int argc, /* All digit name check. */ idx = 0; - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "LCOMMUNITY_LIST_NAME", &idx); argv_find(argv, argc, "(1-99)", &idx); argv_find(argv, argc, "(100-500)", &idx); cl_name = argv[idx]->arg; @@ -19476,7 +19618,7 @@ static int lcommunity_list_unset_vty(struct vty *vty, int argc, idx = 0; argv_find(argv, argc, "(1-99)", &idx); argv_find(argv, argc, "(100-500)", &idx); - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "LCOMMUNITY_LIST_NAME", &idx); /* Unset community list. */ ret = lcommunity_list_unset(bgp_clist, argv[idx]->arg, str, seq, direct, @@ -19532,7 +19674,7 @@ DEFUN (lcommunity_list_expanded, DEFUN (lcommunity_list_name_standard, bgp_lcommunity_list_name_standard_cmd, - "bgp large-community-list standard WORD [seq (0-4294967295)] <deny|permit> AA:BB:CC...", + "bgp large-community-list standard LCOMMUNITY_LIST_NAME [seq (0-4294967295)] <deny|permit> AA:BB:CC...", BGP_STR LCOMMUNITY_LIST_STR "Specify standard large-community-list\n" @@ -19549,7 +19691,7 @@ DEFUN (lcommunity_list_name_standard, DEFUN (lcommunity_list_name_expanded, bgp_lcommunity_list_name_expanded_cmd, - "bgp large-community-list expanded WORD [seq (0-4294967295)] <deny|permit> LINE...", + "bgp large-community-list expanded LCOMMUNITY_LIST_NAME [seq (0-4294967295)] <deny|permit> LINE...", BGP_STR LCOMMUNITY_LIST_STR "Specify expanded large-community-list\n" @@ -19566,7 +19708,7 @@ DEFUN (lcommunity_list_name_expanded, DEFUN (no_lcommunity_list_all, no_bgp_lcommunity_list_all_cmd, - "no bgp large-community-list <(1-99)|(100-500)|WORD>", + "no bgp large-community-list <(1-99)|(100-500)|LCOMMUNITY_LIST_NAME>", NO_STR BGP_STR LCOMMUNITY_LIST_STR @@ -19580,7 +19722,7 @@ DEFUN (no_lcommunity_list_all, DEFUN (no_lcommunity_list_name_standard_all, no_bgp_lcommunity_list_name_standard_all_cmd, - "no bgp large-community-list standard WORD", + "no bgp large-community-list standard LCOMMUNITY_LIST_NAME", NO_STR BGP_STR LCOMMUNITY_LIST_STR @@ -19593,7 +19735,7 @@ DEFUN (no_lcommunity_list_name_standard_all, DEFUN (no_lcommunity_list_name_expanded_all, no_bgp_lcommunity_list_name_expanded_all_cmd, - "no bgp large-community-list expanded WORD", + "no bgp large-community-list expanded LCOMMUNITY_LIST_NAME", NO_STR BGP_STR LCOMMUNITY_LIST_STR @@ -19640,7 +19782,7 @@ DEFUN (no_lcommunity_list_expanded, DEFUN (no_lcommunity_list_name_standard, no_bgp_lcommunity_list_name_standard_cmd, - "no bgp large-community-list standard WORD [seq (0-4294967295)] <deny|permit> AA:AA:NN...", + "no bgp large-community-list standard LCOMMUNITY_LIST_NAME [seq (0-4294967295)] <deny|permit> AA:AA:NN...", NO_STR BGP_STR LCOMMUNITY_LIST_STR @@ -19658,7 +19800,7 @@ DEFUN (no_lcommunity_list_name_standard, DEFUN (no_lcommunity_list_name_expanded, no_bgp_lcommunity_list_name_expanded_cmd, - "no bgp large-community-list expanded WORD [seq (0-4294967295)] <deny|permit> LINE...", + "no bgp large-community-list expanded LCOMMUNITY_LIST_NAME [seq (0-4294967295)] <deny|permit> LINE...", NO_STR BGP_STR LCOMMUNITY_LIST_STR @@ -19732,7 +19874,7 @@ DEFUN (show_lcommunity_list, DEFUN (show_lcommunity_list_arg, show_bgp_lcommunity_list_arg_cmd, - "show bgp large-community-list <(1-500)|WORD> detail", + "show bgp large-community-list <(1-500)|LCOMMUNITY_LIST_NAME> detail", SHOW_STR BGP_STR "List large-community list\n" @@ -19760,7 +19902,7 @@ DEFUN (show_lcommunity_list_arg, DEFUN (extcommunity_list_standard, bgp_extcommunity_list_standard_cmd, - "bgp extcommunity-list <(1-99)|standard WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", + "bgp extcommunity-list <(1-99)|standard EXTCOMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...", BGP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (standard)\n" @@ -19780,7 +19922,7 @@ DEFUN (extcommunity_list_standard, int idx = 0; argv_find(argv, argc, "(1-99)", &idx); - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx); cl_number_or_name = argv[idx]->arg; if (argv_find(argv, argc, "(0-4294967295)", &idx)) @@ -19806,7 +19948,7 @@ DEFUN (extcommunity_list_standard, DEFUN (extcommunity_list_name_expanded, bgp_extcommunity_list_name_expanded_cmd, - "bgp extcommunity-list <(100-500)|expanded WORD> [seq (0-4294967295)] <deny|permit> LINE...", + "bgp extcommunity-list <(100-500)|expanded EXTCOMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> LINE...", BGP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (expanded)\n" @@ -19825,7 +19967,7 @@ DEFUN (extcommunity_list_name_expanded, int idx = 0; argv_find(argv, argc, "(100-500)", &idx); - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx); cl_number_or_name = argv[idx]->arg; if (argv_find(argv, argc, "(0-4294967295)", &idx)) @@ -19851,7 +19993,7 @@ DEFUN (extcommunity_list_name_expanded, DEFUN (no_extcommunity_list_standard_all, no_bgp_extcommunity_list_standard_all_cmd, - "no bgp extcommunity-list <(1-99)|standard WORD> [seq (0-4294967295)] <deny|permit> AA:NN...", + "no bgp extcommunity-list <(1-99)|standard EXTCOMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> AA:NN...", NO_STR BGP_STR EXTCOMMUNITY_LIST_STR @@ -19889,7 +20031,7 @@ DEFUN (no_extcommunity_list_standard_all, idx = 0; argv_find(argv, argc, "(1-99)", &idx); - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx); cl_number_or_name = argv[idx]->arg; int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str, @@ -19907,7 +20049,7 @@ DEFUN (no_extcommunity_list_standard_all, ALIAS(no_extcommunity_list_standard_all, no_bgp_extcommunity_list_standard_all_list_cmd, - "no bgp extcommunity-list <(1-99)|standard WORD>", + "no bgp extcommunity-list <(1-99)|standard EXTCOMMUNITY_LIST_NAME>", NO_STR BGP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (standard)\n" "Specify standard extcommunity-list\n" @@ -19915,7 +20057,7 @@ ALIAS(no_extcommunity_list_standard_all, DEFUN (no_extcommunity_list_expanded_all, no_bgp_extcommunity_list_expanded_all_cmd, - "no bgp extcommunity-list <(100-500)|expanded WORD> [seq (0-4294967295)] <deny|permit> LINE...", + "no bgp extcommunity-list <(100-500)|expanded EXTCOMMUNITY_LIST_NAME> [seq (0-4294967295)] <deny|permit> LINE...", NO_STR BGP_STR EXTCOMMUNITY_LIST_STR @@ -19954,7 +20096,7 @@ DEFUN (no_extcommunity_list_expanded_all, idx = 0; argv_find(argv, argc, "(100-500)", &idx); - argv_find(argv, argc, "WORD", &idx); + argv_find(argv, argc, "EXTCOMMUNITY_LIST_NAME", &idx); cl_number_or_name = argv[idx]->arg; int ret = extcommunity_list_unset(bgp_clist, cl_number_or_name, str, @@ -19972,7 +20114,7 @@ DEFUN (no_extcommunity_list_expanded_all, ALIAS(no_extcommunity_list_expanded_all, no_bgp_extcommunity_list_expanded_all_list_cmd, - "no bgp extcommunity-list <(100-500)|expanded WORD>", + "no bgp extcommunity-list <(100-500)|expanded EXTCOMMUNITY_LIST_NAME>", NO_STR BGP_STR EXTCOMMUNITY_LIST_STR "Extended Community list number (expanded)\n" "Specify expanded extcommunity-list\n" @@ -20033,7 +20175,7 @@ DEFUN (show_extcommunity_list, DEFUN (show_extcommunity_list_arg, show_bgp_extcommunity_list_arg_cmd, - "show bgp extcommunity-list <(1-500)|WORD> detail", + "show bgp extcommunity-list <(1-500)|EXTCOMMUNITY_LIST_NAME> detail", SHOW_STR BGP_STR "List extended-community list\n" diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 09fe399c29..de25aa30d9 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -64,6 +64,7 @@ #include "bgpd/bgp_evpn_private.h" #include "bgpd/bgp_evpn_mh.h" #include "bgpd/bgp_mac.h" +#include "bgpd/bgp_trace.h" /* All information about zebra. */ struct zclient *zclient = NULL; @@ -112,12 +113,6 @@ static int bgp_read_nexthop_update(ZAPI_CALLBACK_ARGS) return 0; } -static int bgp_read_import_check_update(ZAPI_CALLBACK_ARGS) -{ - bgp_parse_nexthop_update(cmd, vrf_id); - return 0; -} - /* Set or clear interface on which unnumbered neighbor is configured. This * would in turn cause BGP to initiate or turn off IPv6 RAs on this * interface. @@ -141,8 +136,7 @@ static void bgp_update_interface_nbrs(struct bgp *bgp, struct interface *ifp, } } -static int bgp_read_fec_update(int command, struct zclient *zclient, - zebra_size_t length) +static int bgp_read_fec_update(ZAPI_CALLBACK_ARGS) { bgp_parse_fec_update(); return 0; @@ -212,10 +206,11 @@ static int bgp_ifp_destroy(struct interface *ifp) { struct bgp *bgp; - bgp = bgp_lookup_by_vrf_id(ifp->vrf_id); + bgp = ifp->vrf->info; if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf del VRF %u IF %s", ifp->vrf_id, ifp->name); + zlog_debug("Rx Intf del VRF %u IF %s", ifp->vrf->vrf_id, + ifp->name); if (bgp) { bgp_update_interface_nbrs(bgp, ifp, NULL); @@ -234,12 +229,13 @@ static int bgp_ifp_up(struct interface *ifp) struct listnode *node, *nnode; struct bgp *bgp; - bgp = bgp_lookup_by_vrf_id(ifp->vrf_id); + bgp = ifp->vrf->info; bgp_mac_add_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf_id, ifp->name); + zlog_debug("Rx Intf up VRF %u IF %s", ifp->vrf->vrf_id, + ifp->name); if (!bgp) return 0; @@ -264,12 +260,13 @@ static int bgp_ifp_down(struct interface *ifp) struct bgp *bgp; struct peer *peer; - bgp = bgp_lookup_by_vrf_id(ifp->vrf_id); + bgp = ifp->vrf->info; bgp_mac_del_mac_entry(ifp); if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("Rx Intf down VRF %u IF %s", ifp->vrf_id, ifp->name); + zlog_debug("Rx Intf down VRF %u IF %s", ifp->vrf->vrf_id, + ifp->name); if (!bgp) return 0; @@ -881,7 +878,7 @@ bool bgp_zebra_nexthop_set(union sockunion *local, union sockunion *remote, * It's fine to not have a v6 LL when using * update-source loopback/vrf */ - if (!v6_ll_avail && if_is_loopback_or_vrf(ifp)) + if (!v6_ll_avail && if_is_loopback(ifp)) v6_ll_avail = true; } else /* Link-local address. */ @@ -1255,6 +1252,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, uint8_t distance; struct peer *peer; struct bgp_path_info *mpinfo; + struct bgp *bgp_orig; uint32_t metric; struct attr local_attr; struct bgp_path_info local_info; @@ -1418,13 +1416,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, } } + BGP_ORIGINAL_UPDATE(bgp_orig, mpinfo, bgp); + if (nh_family == AF_INET) { nh_updated = update_ipv4nh_for_route_install( - nh_othervrf, - nh_othervrf ? - info->extra->bgp_orig : bgp, - &mpinfo_cp->attr->nexthop, - mpinfo_cp->attr, is_evpn, api_nh); + nh_othervrf, bgp_orig, + &mpinfo_cp->attr->nexthop, mpinfo_cp->attr, + is_evpn, api_nh); } else { ifindex_t ifindex = IFINDEX_INTERNAL; struct in6_addr *nexthop; @@ -1434,18 +1432,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, if (!nexthop) nh_updated = update_ipv4nh_for_route_install( - nh_othervrf, - nh_othervrf ? info->extra->bgp_orig - : bgp, + nh_othervrf, bgp_orig, &mpinfo_cp->attr->nexthop, mpinfo_cp->attr, is_evpn, api_nh); else nh_updated = update_ipv6nh_for_route_install( - nh_othervrf, - nh_othervrf ? info->extra->bgp_orig - : bgp, - nexthop, ifindex, mpinfo, info, is_evpn, - api_nh); + nh_othervrf, bgp_orig, nexthop, ifindex, + mpinfo, info, is_evpn, api_nh); } /* Did we get proper nexthop info to update zebra? */ @@ -1495,6 +1488,8 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, if (is_add && 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); strlcpy(bzo.aspath, info->attr->aspath->str, sizeof(bzo.aspath)); @@ -1508,6 +1503,9 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, strlcpy(bzo.lcommunity, info->attr->lcommunity->str, sizeof(bzo.lcommunity)); + strlcpy(bzo.selection_reason, reason, + sizeof(bzo.selection_reason)); + SET_FLAG(api.message, ZAPI_MESSAGE_OPAQUE); api.opaque.length = MIN(sizeof(struct bgp_zebra_opaque), ZAPI_MESSAGE_OPAQUE_LENGTH); @@ -2530,34 +2528,26 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, case ZAPI_ROUTE_INSTALLED: new_select = NULL; /* Clear the flags so that route can be processed */ - if (CHECK_FLAG(dest->flags, - BGP_NODE_FIB_INSTALL_PENDING)) { - UNSET_FLAG(dest->flags, - BGP_NODE_FIB_INSTALL_PENDING); - SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); - if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("route %pRN : INSTALLED", dest); - /* Find the best route */ - for (pi = dest->info; pi; pi = pi->next) { - /* Process aggregate route */ - bgp_aggregate_increment(bgp, &p, pi, - afi, safi); - if (CHECK_FLAG(pi->flags, - BGP_PATH_SELECTED)) - new_select = pi; - } - /* Advertise the route */ - if (new_select) - group_announce_route(bgp, afi, safi, - dest, new_select); - else { - flog_err(EC_BGP_INVALID_ROUTE, - "selected route %pRN not found", - dest); - - bgp_dest_unlock_node(dest); - return -1; - } + UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + SET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); + if (BGP_DEBUG(zebra, ZEBRA)) + zlog_debug("route %pRN : INSTALLED", dest); + /* Find the best route */ + for (pi = dest->info; pi; pi = pi->next) { + /* Process aggregate route */ + bgp_aggregate_increment(bgp, &p, pi, afi, safi); + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) + new_select = pi; + } + /* Advertise the route */ + if (new_select) + group_announce_route(bgp, afi, safi, dest, new_select); + else { + flog_err(EC_BGP_INVALID_ROUTE, + "selected route %pRN not found", dest); + + bgp_dest_unlock_node(dest); + return -1; } break; case ZAPI_ROUTE_REMOVED: @@ -2570,15 +2560,34 @@ static int bgp_zebra_route_notify_owner(int command, struct zclient *zclient, zlog_debug("route %pRN: Removed from Fib", dest); break; case ZAPI_ROUTE_FAIL_INSTALL: + new_select = NULL; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("route: %pRN Failed to Install into Fib", dest); + UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) + new_select = pi; + } + if (new_select) + group_announce_route(bgp, afi, safi, dest, new_select); /* Error will be logged by zebra module */ break; case ZAPI_ROUTE_BETTER_ADMIN_WON: if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("route: %pRN removed due to better admin won", dest); + new_select = NULL; + UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALL_PENDING); + UNSET_FLAG(dest->flags, BGP_NODE_FIB_INSTALLED); + for (pi = bgp_dest_get_bgp_path_info(dest); pi; pi = pi->next) { + bgp_aggregate_decrement(bgp, &p, pi, afi, safi); + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) + new_select = pi; + } + if (new_select) + group_announce_route(bgp, afi, safi, dest, new_select); /* No action required */ break; case ZAPI_ROUTE_REMOVE_FAIL: @@ -2779,6 +2788,9 @@ static int bgp_zebra_process_local_es_add(ZAPI_CALLBACK_ARGS) esi_to_str(&esi, buf, sizeof(buf)), &originator_ip, active, df_pref, bypass ? "bypass" : ""); + frrtrace(5, frr_bgp, evpn_mh_local_es_add_zrecv, &esi, originator_ip, + active, bypass, df_pref); + bgp_evpn_local_es_add(bgp, &esi, originator_ip, active, df_pref, !!bypass); @@ -2804,6 +2816,8 @@ static int bgp_zebra_process_local_es_del(ZAPI_CALLBACK_ARGS) zlog_debug("Rx del ESI %s", esi_to_str(&esi, buf, sizeof(buf))); + frrtrace(1, frr_bgp, evpn_mh_local_es_del_zrecv, &esi); + bgp_evpn_local_es_del(bgp, &esi); return 0; @@ -2830,10 +2844,15 @@ static int bgp_zebra_process_local_es_evi(ZAPI_CALLBACK_ARGS) ZEBRA_VNI_ADD ? "add" : "del", esi_to_str(&esi, buf, sizeof(buf)), vni); - if (cmd == ZEBRA_LOCAL_ES_EVI_ADD) + if (cmd == ZEBRA_LOCAL_ES_EVI_ADD) { + frrtrace(2, frr_bgp, evpn_mh_local_es_evi_add_zrecv, &esi, vni); + bgp_evpn_local_es_evi_add(bgp, &esi, vni); - else + } else { + frrtrace(2, frr_bgp, evpn_mh_local_es_evi_del_zrecv, &esi, vni); + bgp_evpn_local_es_evi_del(bgp, &esi, vni); + } return 0; } @@ -2868,6 +2887,10 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) filter ? "prefix-routes-only" : "none", svi_ifindex); + frrtrace(8, frr_bgp, evpn_local_l3vni_add_zrecv, l3vni, vrf_id, + &svi_rmac, &vrr_rmac, filter, originator_ip, + svi_ifindex, is_anycast_mac); + bgp_evpn_local_l3vni_add(l3vni, vrf_id, &svi_rmac, &vrr_rmac, originator_ip, filter, svi_ifindex, is_anycast_mac); @@ -2876,6 +2899,8 @@ static int bgp_zebra_process_local_l3vni(ZAPI_CALLBACK_ARGS) zlog_debug("Rx L3-VNI DEL VRF %s VNI %u", vrf_id_to_name(vrf_id), l3vni); + frrtrace(2, frr_bgp, evpn_local_l3vni_del_zrecv, l3vni, vrf_id); + bgp_evpn_local_l3vni_del(l3vni, vrf_id); } @@ -2912,13 +2937,19 @@ static int bgp_zebra_process_local_vni(ZAPI_CALLBACK_ARGS) vrf_id_to_name(vrf_id), vni, vrf_id_to_name(tenant_vrf_id), svi_ifindex); - if (cmd == ZEBRA_VNI_ADD) + if (cmd == ZEBRA_VNI_ADD) { + frrtrace(4, frr_bgp, evpn_local_vni_add_zrecv, vni, vtep_ip, + tenant_vrf_id, mcast_grp); + return bgp_evpn_local_vni_add( bgp, vni, vtep_ip.s_addr != INADDR_ANY ? vtep_ip : bgp->router_id, tenant_vrf_id, mcast_grp, svi_ifindex); - else + } else { + frrtrace(1, frr_bgp, evpn_local_vni_del_zrecv, vni); + return bgp_evpn_local_vni_del(bgp, vni); + } } static int bgp_zebra_process_local_macip(ZAPI_CALLBACK_ARGS) @@ -2974,14 +3005,21 @@ static int bgp_zebra_process_local_macip(ZAPI_CALLBACK_ARGS) &mac, &ip, vni, seqnum, state, esi_to_str(&esi, buf2, sizeof(buf2))); - if (cmd == ZEBRA_MACIP_ADD) + if (cmd == ZEBRA_MACIP_ADD) { + frrtrace(6, frr_bgp, evpn_local_macip_add_zrecv, vni, &mac, &ip, + flags, seqnum, &esi); + return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip, flags, seqnum, &esi); - else + } else { + frrtrace(4, frr_bgp, evpn_local_macip_del_zrecv, vni, &mac, &ip, + state); + return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, state); + } } -static void bgp_zebra_process_local_ip_prefix(ZAPI_CALLBACK_ARGS) +static int bgp_zebra_process_local_ip_prefix(ZAPI_CALLBACK_ARGS) { struct stream *s = NULL; struct bgp *bgp_vrf = NULL; @@ -2993,7 +3031,7 @@ static void bgp_zebra_process_local_ip_prefix(ZAPI_CALLBACK_ARGS) bgp_vrf = bgp_lookup_by_vrf_id(vrf_id); if (!bgp_vrf) - return; + return 0; if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Recv prefix %pFX %s on vrf %s", &p, @@ -3017,9 +3055,10 @@ static void bgp_zebra_process_local_ip_prefix(ZAPI_CALLBACK_ARGS) bgp_evpn_withdraw_type5_route(bgp_vrf, &p, AFI_IP6, SAFI_UNICAST); } + return 0; } -static void bgp_zebra_process_label_chunk(ZAPI_CALLBACK_ARGS) +static int bgp_zebra_process_label_chunk(ZAPI_CALLBACK_ARGS) { struct stream *s = NULL; uint8_t response_keep; @@ -3038,12 +3077,12 @@ static void bgp_zebra_process_label_chunk(ZAPI_CALLBACK_ARGS) if (zclient->redist_default != proto) { flog_err(EC_BGP_LM_ERROR, "Got LM msg with wrong proto %u", proto); - return; + return 0; } if (zclient->instance != instance) { flog_err(EC_BGP_LM_ERROR, "Got LM msg with wrong instance %u", proto); - return; + return 0; } if (first > last || @@ -3052,7 +3091,7 @@ static void bgp_zebra_process_label_chunk(ZAPI_CALLBACK_ARGS) flog_err(EC_BGP_LM_ERROR, "%s: Invalid Label chunk: %u - %u", __func__, first, last); - return; + return 0; } if (BGP_DEBUG(zebra, ZEBRA)) { zlog_debug("Label Chunk assign: %u - %u (%u) ", @@ -3061,8 +3100,10 @@ static void bgp_zebra_process_label_chunk(ZAPI_CALLBACK_ARGS) bgp_lp_event_chunk(response_keep, first, last); + return 0; + stream_failure: /* for STREAM_GETX */ - return; + return -1; } extern struct zebra_privs_t bgpd_privs; @@ -3072,9 +3113,10 @@ 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_id, ifp->name); + zlog_debug("Rx Intf add VRF %u IF %s", ifp->vrf->vrf_id, + ifp->name); - bgp = bgp_lookup_by_vrf_id(ifp->vrf_id); + bgp = ifp->vrf->info; if (!bgp) return 0; @@ -3085,7 +3127,7 @@ static int bgp_ifp_create(struct interface *ifp) return 0; } -static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +static int bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) { struct stream *s = NULL; struct bgp *bgp = bgp_get_default(); @@ -3100,18 +3142,19 @@ static void bgp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) if (strcmp(bgp->srv6_locator_name, s6c.locator_name) != 0) { zlog_err("%s: Locator name unmatch %s:%s", __func__, bgp->srv6_locator_name, s6c.locator_name); - return; + return 0; } for (ALL_LIST_ELEMENTS_RO(bgp->srv6_locator_chunks, node, c)) { if (!prefix_cmp(c, &s6c.prefix)) - return; + return 0; } chunk = prefix_ipv6_new(); *chunk = s6c.prefix; listnode_add(bgp->srv6_locator_chunks, chunk); vpn_leak_postchange_all(); + return 0; } static int bgp_zebra_process_srv6_locator_add(ZAPI_CALLBACK_ARGS) @@ -3196,6 +3239,41 @@ static int bgp_zebra_process_srv6_locator_delete(ZAPI_CALLBACK_ARGS) return 0; } +static zclient_handler *const bgp_handlers[] = { + [ZEBRA_ROUTER_ID_UPDATE] = bgp_router_id_update, + [ZEBRA_INTERFACE_ADDRESS_ADD] = bgp_interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = bgp_interface_address_delete, + [ZEBRA_INTERFACE_NBR_ADDRESS_ADD] = bgp_interface_nbr_address_add, + [ZEBRA_INTERFACE_NBR_ADDRESS_DELETE] = bgp_interface_nbr_address_delete, + [ZEBRA_INTERFACE_VRF_UPDATE] = bgp_interface_vrf_update, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = zebra_read_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = zebra_read_route, + [ZEBRA_NEXTHOP_UPDATE] = bgp_read_nexthop_update, + [ZEBRA_FEC_UPDATE] = bgp_read_fec_update, + [ZEBRA_LOCAL_ES_ADD] = bgp_zebra_process_local_es_add, + [ZEBRA_LOCAL_ES_DEL] = bgp_zebra_process_local_es_del, + [ZEBRA_VNI_ADD] = bgp_zebra_process_local_vni, + [ZEBRA_LOCAL_ES_EVI_ADD] = bgp_zebra_process_local_es_evi, + [ZEBRA_LOCAL_ES_EVI_DEL] = bgp_zebra_process_local_es_evi, + [ZEBRA_VNI_DEL] = bgp_zebra_process_local_vni, + [ZEBRA_MACIP_ADD] = bgp_zebra_process_local_macip, + [ZEBRA_MACIP_DEL] = bgp_zebra_process_local_macip, + [ZEBRA_L3VNI_ADD] = bgp_zebra_process_local_l3vni, + [ZEBRA_L3VNI_DEL] = bgp_zebra_process_local_l3vni, + [ZEBRA_IP_PREFIX_ROUTE_ADD] = bgp_zebra_process_local_ip_prefix, + [ZEBRA_IP_PREFIX_ROUTE_DEL] = bgp_zebra_process_local_ip_prefix, + [ZEBRA_GET_LABEL_CHUNK] = bgp_zebra_process_label_chunk, + [ZEBRA_RULE_NOTIFY_OWNER] = rule_notify_owner, + [ZEBRA_IPSET_NOTIFY_OWNER] = ipset_notify_owner, + [ZEBRA_IPSET_ENTRY_NOTIFY_OWNER] = ipset_entry_notify_owner, + [ZEBRA_IPTABLE_NOTIFY_OWNER] = iptable_notify_owner, + [ZEBRA_ROUTE_NOTIFY_OWNER] = bgp_zebra_route_notify_owner, + [ZEBRA_SRV6_LOCATOR_ADD] = bgp_zebra_process_srv6_locator_add, + [ZEBRA_SRV6_LOCATOR_DELETE] = bgp_zebra_process_srv6_locator_delete, + [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = + bgp_zebra_process_srv6_locator_chunk, +}; + void bgp_zebra_init(struct thread_master *master, unsigned short instance) { zclient_num_connects = 0; @@ -3204,44 +3282,11 @@ void bgp_zebra_init(struct thread_master *master, unsigned short instance) bgp_ifp_down, bgp_ifp_destroy); /* Set default values. */ - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, bgp_handlers, + array_size(bgp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_BGP, 0, &bgpd_privs); zclient->zebra_connected = bgp_zebra_connected; - zclient->router_id_update = bgp_router_id_update; - zclient->interface_address_add = bgp_interface_address_add; - zclient->interface_address_delete = bgp_interface_address_delete; - zclient->interface_nbr_address_add = bgp_interface_nbr_address_add; - zclient->interface_nbr_address_delete = - bgp_interface_nbr_address_delete; - zclient->interface_vrf_update = bgp_interface_vrf_update; - zclient->redistribute_route_add = zebra_read_route; - zclient->redistribute_route_del = zebra_read_route; - zclient->nexthop_update = bgp_read_nexthop_update; - zclient->import_check_update = bgp_read_import_check_update; - zclient->fec_update = bgp_read_fec_update; - zclient->local_es_add = bgp_zebra_process_local_es_add; - zclient->local_es_del = bgp_zebra_process_local_es_del; - zclient->local_vni_add = bgp_zebra_process_local_vni; - zclient->local_es_evi_add = bgp_zebra_process_local_es_evi; - zclient->local_es_evi_del = bgp_zebra_process_local_es_evi; - zclient->local_vni_del = bgp_zebra_process_local_vni; - zclient->local_macip_add = bgp_zebra_process_local_macip; - zclient->local_macip_del = bgp_zebra_process_local_macip; - zclient->local_l3vni_add = bgp_zebra_process_local_l3vni; - zclient->local_l3vni_del = bgp_zebra_process_local_l3vni; - zclient->local_ip_prefix_add = bgp_zebra_process_local_ip_prefix; - zclient->local_ip_prefix_del = bgp_zebra_process_local_ip_prefix; - zclient->label_chunk = bgp_zebra_process_label_chunk; - zclient->rule_notify_owner = rule_notify_owner; - zclient->ipset_notify_owner = ipset_notify_owner; - zclient->ipset_entry_notify_owner = ipset_entry_notify_owner; - zclient->iptable_notify_owner = iptable_notify_owner; - zclient->route_notify_owner = bgp_zebra_route_notify_owner; zclient->instance = instance; - zclient->srv6_locator_add = bgp_zebra_process_srv6_locator_add; - zclient->srv6_locator_delete = bgp_zebra_process_srv6_locator_delete; - zclient->process_srv6_locator_chunk = - bgp_zebra_process_srv6_locator_chunk; } void bgp_zebra_destroy(void) @@ -3513,7 +3558,7 @@ void bgp_zebra_announce_default(struct bgp *bgp, struct nexthop *nh, /* create default route with interface <VRF> * with nexthop-vrf <VRF> */ - ifp = if_lookup_by_name_all_vrf(vrf->name); + ifp = if_lookup_by_name_vrf(vrf->name, vrf); if (!ifp) return; api_nh->vrf_id = nh->vrf_id; diff --git a/bgpd/bgp_zebra.h b/bgpd/bgp_zebra.h index 9c0a1d8f1f..eee3d36931 100644 --- a/bgpd/bgp_zebra.h +++ b/bgpd/bgp_zebra.h @@ -23,6 +23,13 @@ #include "vxlan.h" +/* Macro to update bgp_original based on bpg_path_info */ +#define BGP_ORIGINAL_UPDATE(_bgp_orig, _mpinfo, _bgp) \ + ((_mpinfo->extra && _mpinfo->extra->bgp_orig \ + && _mpinfo->sub_type == BGP_ROUTE_IMPORTED) \ + ? (_bgp_orig = _mpinfo->extra->bgp_orig) \ + : (_bgp_orig = _bgp)) + /* Default weight for next hop, if doing weighted ECMP. */ #define BGP_ZEBRA_DEFAULT_NHOP_WEIGHT 1 diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index b191029d2f..6d0fd2fdd6 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -1185,10 +1185,6 @@ struct peer *peer_lock_with_caller(const char *name, struct peer *peer) { assert(peer && (peer->lock >= 0)); -#if 0 - zlog_debug("%s peer_lock %p %d", name, peer, peer->lock); -#endif - peer->lock++; return peer; @@ -1201,10 +1197,6 @@ struct peer *peer_unlock_with_caller(const char *name, struct peer *peer) { assert(peer && (peer->lock > 0)); -#if 0 - zlog_debug("%s peer_unlock %p %d", name, peer, peer->lock); -#endif - peer->lock--; if (peer->lock == 0) { @@ -1664,8 +1656,7 @@ void bgp_peer_conf_if_to_su_update(struct peer *peer) hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); } -static void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, - safi_t safi) +void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, safi_t safi) { struct bgp_dest *dest, *ndest; struct bgp_table *table; @@ -3169,6 +3160,7 @@ static struct bgp *bgp_create(as_t *as, const char *name, bgp_addpath_init_bgp_data(&bgp->tx_addpath); bgp->fast_convergence = false; bgp->as = *as; + bgp->llgr_stale_time = BGP_DEFAULT_LLGR_STALE_TIME; #ifdef ENABLE_BGP_VNC if (inst_type != BGP_INSTANCE_TYPE_VRF) { @@ -4180,6 +4172,7 @@ static const struct peer_flag_action peer_flag_action_list[] = { {PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_none}, {PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none}, {PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE, 0, peer_change_none}, + {PEER_FLAG_EXTENDED_OPT_PARAMS, 0, peer_change_reset}, {0, 0, 0}}; static const struct peer_flag_action peer_af_flag_action_list[] = { @@ -4279,17 +4272,16 @@ static void peer_flag_modify_action(struct peer *peer, uint32_t flag) if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { char *msg = peer->tx_shutdown_message; size_t msglen; + uint8_t msgbuf[BGP_ADMIN_SHUTDOWN_MSG_LEN + 1]; if (!msg && peer_group_active(peer)) msg = peer->group->conf ->tx_shutdown_message; msglen = msg ? strlen(msg) : 0; - if (msglen > 128) - msglen = 128; + if (msglen > BGP_ADMIN_SHUTDOWN_MSG_LEN) + msglen = BGP_ADMIN_SHUTDOWN_MSG_LEN; if (msglen) { - uint8_t msgbuf[129]; - msgbuf[0] = msglen; memcpy(msgbuf + 1, msg, msglen); @@ -4326,6 +4318,12 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) { struct peer *peer; struct listnode *node; + /* length(1) + message(N) */ + uint8_t data[BGP_ADMIN_SHUTDOWN_MSG_LEN + 1]; + size_t datalen = strlen(msg); + + data[0] = datalen; + memcpy(data + 1, msg, datalen); /* do nothing if already shut down */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN)) @@ -4346,8 +4344,8 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) if (msg) bgp_notify_send_with_data( peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, - (uint8_t *)(msg), strlen(msg)); + BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, data, + datalen + 1); else bgp_notify_send( peer, BGP_NOTIFY_CEASE, @@ -4752,6 +4750,10 @@ int peer_ebgp_multihop_set(struct peer *peer, int ttl) BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(peer); + + /* Reconfigure BFD peer with new TTL. */ + if (peer->bfd_config) + bgp_peer_bfd_update_source(peer); } } else { group = peer->group; @@ -4766,6 +4768,10 @@ int peer_ebgp_multihop_set(struct peer *peer, int ttl) BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(peer); + + /* Reconfigure BFD peer with new TTL. */ + if (peer->bfd_config) + bgp_peer_bfd_update_source(peer); } } return 0; @@ -4775,6 +4781,7 @@ int peer_ebgp_multihop_unset(struct peer *peer) { struct peer_group *group; struct listnode *node, *nnode; + int ttl; if (peer->sort == BGP_PEER_IBGP) return 0; @@ -4783,9 +4790,14 @@ int peer_ebgp_multihop_unset(struct peer *peer) return BGP_ERR_NO_EBGP_MULTIHOP_WITH_TTLHACK; if (peer_group_active(peer)) - peer->ttl = peer->group->conf->ttl; + ttl = peer->group->conf->ttl; else - peer->ttl = BGP_DEFAULT_TTL; + ttl = BGP_DEFAULT_TTL; + + if (ttl == peer->ttl) + return 0; + + peer->ttl = ttl; if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) @@ -4793,6 +4805,10 @@ int peer_ebgp_multihop_unset(struct peer *peer) BGP_NOTIFY_CEASE_CONFIG_CHANGE); else bgp_session_reset(peer); + + /* Reconfigure BFD peer with new TTL. */ + if (peer->bfd_config) + bgp_peer_bfd_update_source(peer); } else { group = peer->group; for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) { @@ -4809,6 +4825,10 @@ int peer_ebgp_multihop_unset(struct peer *peer) else bgp_session_reset(peer); } + + /* Reconfigure BFD peer with new TTL. */ + if (peer->bfd_config) + bgp_peer_bfd_update_source(peer); } } return 0; @@ -4854,6 +4874,10 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) } else bgp_session_reset(peer); + /* Apply new source configuration to BFD session. */ + if (peer->bfd_config) + bgp_peer_bfd_update_source(peer); + /* Skip peer-group mechanics for regular peers. */ return 0; } @@ -4887,6 +4911,10 @@ int peer_update_source_if_set(struct peer *peer, const char *ifname) BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(member); + + /* Apply new source configuration to BFD session. */ + if (member->bfd_config) + bgp_peer_bfd_update_source(member); } return 0; @@ -4917,6 +4945,10 @@ int peer_update_source_addr_set(struct peer *peer, const union sockunion *su) } else bgp_session_reset(peer); + /* Apply new source configuration to BFD session. */ + if (peer->bfd_config) + bgp_peer_bfd_update_source(peer); + /* Skip peer-group mechanics for regular peers. */ return 0; } @@ -4949,6 +4981,10 @@ int peer_update_source_addr_set(struct peer *peer, const union sockunion *su) BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(member); + + /* Apply new source configuration to BFD session. */ + if (member->bfd_config) + bgp_peer_bfd_update_source(member); } return 0; @@ -4986,6 +5022,10 @@ int peer_update_source_unset(struct peer *peer) } else bgp_session_reset(peer); + /* Apply new source configuration to BFD session. */ + if (peer->bfd_config) + bgp_peer_bfd_update_source(peer); + /* Skip peer-group mechanics for regular peers. */ return 0; } @@ -5017,6 +5057,10 @@ int peer_update_source_unset(struct peer *peer) BGP_NOTIFY_CEASE_CONFIG_CHANGE); } else bgp_session_reset(member); + + /* Apply new source configuration to BFD session. */ + if (member->bfd_config) + bgp_peer_bfd_update_source(member); } return 0; @@ -7828,8 +7872,7 @@ void bgp_terminate(void) bgp_notify_send(peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_PEER_UNCONFIG); - if (bm->t_rmap_update) - BGP_TIMER_OFF(bm->t_rmap_update); + BGP_TIMER_OFF(bm->t_rmap_update); bgp_mac_finish(); } @@ -7856,11 +7899,7 @@ struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, json_no, "malformedAddressOrName", ip_str); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_no, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json_no); + vty_json(vty, json_no); } else vty_out(vty, "%% Malformed address or name: %s\n", @@ -7879,10 +7918,7 @@ struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp, json_no = json_object_new_object(); json_object_string_add(json_no, "warning", "No such neighbor in this view/vrf"); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_no, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_no); + vty_json(vty, json_no); } else vty_out(vty, "No such neighbor in this view/vrf\n"); return NULL; diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index 5e1eacbb9e..865a50757f 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -81,13 +81,6 @@ typedef uint32_t as_t; typedef uint16_t as16_t; /* we may still encounter 16 Bit asnums */ typedef uint16_t bgp_size_t; -#define max(a, b) \ - ({ \ - __typeof__(a) _a = (a); \ - __typeof__(b) _b = (b); \ - _a > _b ? _a : _b; \ - }) - enum bgp_af_index { BGP_AF_START, BGP_AF_IPV4_UNICAST = BGP_AF_START, @@ -613,6 +606,9 @@ struct bgp { struct graceful_restart_info gr_info[AFI_MAX][SAFI_MAX]; uint32_t rib_stale_time; + /* BGP Long-lived Graceful Restart */ + uint32_t llgr_stale_time; + #define BGP_ROUTE_SELECT_DELAY 1 #define BGP_MAX_BEST_ROUTE_SELECT 10000 /* Maximum-paths configuration */ @@ -1052,6 +1048,11 @@ enum bgp_fsm_status { #define PEER_HOSTNAME(peer) ((peer)->host ? (peer)->host : "(unknown peer)") +struct llgr_info { + uint32_t stale_time; + uint8_t flags; +}; + /* BGP neighbor structure. */ struct peer { /* BGP structure. */ @@ -1182,6 +1183,8 @@ struct peer { #define PEER_CAP_ENHANCED_RR_RCV (1U << 18) /* enhanced rr received */ #define PEER_CAP_EXTENDED_MESSAGE_ADV (1U << 19) #define PEER_CAP_EXTENDED_MESSAGE_RCV (1U << 20) +#define PEER_CAP_LLGR_ADV (1U << 21) +#define PEER_CAP_LLGR_RCV (1U << 22) /* Capability flags (reset in bgp_stop) */ uint32_t af_cap[AFI_MAX][SAFI_MAX]; @@ -1200,6 +1203,8 @@ struct peer { #define PEER_CAP_ENHE_AF_ADV (1U << 12) /* Extended nexthopi afi/safi advertised */ #define PEER_CAP_ENHE_AF_RCV (1U << 13) /* Extended nexthop afi/safi received */ #define PEER_CAP_ENHE_AF_NEGO (1U << 14) /* Extended nexthop afi/safi negotiated */ +#define PEER_CAP_LLGR_AF_ADV (1U << 15) +#define PEER_CAP_LLGR_AF_RCV (1U << 16) /* Global configuration flags. */ /* @@ -1293,6 +1298,8 @@ struct peer { * extended communities. */ #define PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE (1U << 29) +/* force the extended format for Optional Parameters in OPEN message */ +#define PEER_FLAG_EXTENDED_OPT_PARAMS (1U << 30) /* *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART @@ -1379,6 +1386,8 @@ struct peer { #define PEER_STATUS_GROUP (1U << 4) /* peer-group conf */ #define PEER_STATUS_NSF_MODE (1U << 5) /* NSF aware peer */ #define PEER_STATUS_NSF_WAIT (1U << 6) /* wait comeback peer */ +/* received extended format encoding for OPEN message */ +#define PEER_STATUS_EXT_OPT_PARAMS_LENGTH (1U << 7) /* Peer status af flags (reset in bgp_stop) */ uint16_t af_sflags[AFI_MAX][SAFI_MAX]; @@ -1393,6 +1402,8 @@ struct peer { #define PEER_STATUS_BORR_RECEIVED (1U << 8) /* BoRR received from peer */ #define PEER_STATUS_EORR_SEND (1U << 9) /* EoRR send to peer */ #define PEER_STATUS_EORR_RECEIVED (1U << 10) /* EoRR received from peer */ +/* LLGR aware peer */ +#define PEER_STATUS_LLGR_WAIT (1U << 11) /* Configured timer values. */ _Atomic uint32_t holdtime; @@ -1424,6 +1435,7 @@ struct peer { struct thread *t_pmax_restart; struct thread *t_gr_restart; struct thread *t_gr_stale; + struct thread *t_llgr_stale[AFI_MAX][SAFI_MAX]; struct thread *t_generate_updgrp_packets; struct thread *t_process_packet; struct thread *t_process_packet_error; @@ -1657,6 +1669,9 @@ struct peer { /* set TCP max segment size */ uint32_t tcp_mss; + /* Long-lived Graceful Restart */ + struct llgr_info llgr[AFI_MAX][SAFI_MAX]; + QOBJ_FIELDS; }; DECLARE_QOBJ_TYPE(peer); @@ -1716,6 +1731,9 @@ struct bgp_nlri { /* Default BGP port number. */ #define BGP_PORT_DEFAULT 179 +/* Extended BGP Administrative Shutdown Communication */ +#define BGP_ADMIN_SHUTDOWN_MSG_LEN 255 + /* BGP minimum message size. */ #define BGP_MSG_OPEN_MIN_SIZE (BGP_HEADER_SIZE + 10) #define BGP_MSG_UPDATE_MIN_SIZE (BGP_HEADER_SIZE + 4) @@ -1748,9 +1766,6 @@ struct bgp_nlri { #define BGP_ATTR_COMMUNITIES 8 #define BGP_ATTR_ORIGINATOR_ID 9 #define BGP_ATTR_CLUSTER_LIST 10 -#define BGP_ATTR_DPA 11 -#define BGP_ATTR_ADVERTISER 12 -#define BGP_ATTR_RCID_PATH 13 #define BGP_ATTR_MP_REACH_NLRI 14 #define BGP_ATTR_MP_UNREACH_NLRI 15 #define BGP_ATTR_EXT_COMMUNITIES 16 @@ -1869,6 +1884,9 @@ struct bgp_nlri { #define BGP_DEFAULT_RIB_STALE_TIME 500 #define BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME 1 +/* BGP Long-lived Graceful Restart */ +#define BGP_DEFAULT_LLGR_STALE_TIME 0 + /* BGP uptime string length. */ #define BGP_UPTIME_LEN 25 @@ -2458,4 +2476,7 @@ void peer_nsf_stop(struct peer *peer); void peer_tcp_mss_set(struct peer *peer, uint32_t tcp_mss); void peer_tcp_mss_unset(struct peer *peer); + +extern void bgp_recalculate_afi_safi_bestpaths(struct bgp *bgp, afi_t afi, + safi_t safi); #endif /* _QUAGGA_BGPD_H */ diff --git a/bgpd/rfapi/vnc_zebra.c b/bgpd/rfapi/vnc_zebra.c index ba849e4e0b..672a0e9780 100644 --- a/bgpd/rfapi/vnc_zebra.c +++ b/bgpd/rfapi/vnc_zebra.c @@ -895,6 +895,11 @@ int vnc_redistribute_unset(struct bgp *bgp, afi_t afi, int type) extern struct zebra_privs_t bgpd_privs; +static zclient_handler *const vnc_handlers[] = { + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = vnc_zebra_read_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = vnc_zebra_read_route, +}; + /* * Modeled after bgp_zebra.c'bgp_zebra_init() * Charriere asks, "Is it possible to carry two?" @@ -902,11 +907,9 @@ extern struct zebra_privs_t bgpd_privs; void vnc_zebra_init(struct thread_master *master) { /* Set default values. */ - zclient_vnc = zclient_new(master, &zclient_options_default); + zclient_vnc = zclient_new(master, &zclient_options_default, + vnc_handlers, array_size(vnc_handlers)); zclient_init(zclient_vnc, ZEBRA_ROUTE_VNC, 0, &bgpd_privs); - - zclient_vnc->redistribute_route_add = vnc_zebra_read_route; - zclient_vnc->redistribute_route_del = vnc_zebra_read_route; } void vnc_zebra_destroy(void) diff --git a/configure.ac b/configure.ac index 873ed18db8..0d598954cc 100644 --- a/configure.ac +++ b/configure.ac @@ -180,8 +180,6 @@ AM_PROG_CC_C_O dnl remove autoconf default "-g -O2" CFLAGS="$orig_cflags" CXXFLAGS="$orig_cxxflags" -AC_PROG_CC_C99 -dnl NB: see C11 below dnl Some special handling for ICC later on if test "$CC" = "icc"; then @@ -254,12 +252,24 @@ if test "$cc_is_icc" = "yes"; then AC_C_FLAG([-diag-error 10006]) fi -dnl AC_PROG_CC_C99 may change CC to include -std=gnu99 or something -ac_cc="$CC" -CC="${CC% -std=gnu99}" -CC="${CC% -std=c99}" +dnl autoconf 2.69 AC_PROG_CC_C99 is "state of the art" +dnl autoconf 2.70 AC_PROG_CC_C99 is deprecated and AC_PROC_CC tries to do C11 +m4_if(m4_version_compare(m4_defn([AC_AUTOCONF_VERSION]), [2.70]), [-1], [dnl + dnl autoconf < 2.70 + AC_PROG_CC_C99 -AC_C_FLAG([-std=gnu11], [CC="$ac_cc"], [CC="$CC -std=gnu11"]) + dnl AC_PROG_CC_C99 may change CC to include -std=gnu99 or something + ac_cc="$CC" + CC="${CC% -std=gnu99}" + CC="${CC% -std=c99}" + + AC_C_FLAG([-std=gnu11], [CC="$ac_cc"], [CC="$CC -std=gnu11"]) +], [ + dnl autoconf >= 2.70 + if test "$ac_cv_prog_cc_c11" = "no"; then + AC_MSG_ERROR([ISO C11 compiler support (with GNU extensions) is required.]) + fi +]) dnl if the user has specified any CFLAGS, override our settings if test "$enable_gcov" = "yes"; then @@ -507,6 +517,15 @@ AC_SUBST([AC_LDFLAGS]) AC_SUBST([AC_LDFLAGS_EXEC]) AM_CONDITIONAL([STATIC_BIN], [test "$enable_static_bin" = "yes"]) +dnl libtool, the repository of all knowledge related linkers, is too stupid to +dnl correctly tell the linker how to build modules. +if test -z "$module_cmds"; then + module_cmds="`echo \"$archive_cmds\" | sed -e 's%$wl-soname $wl$soname%%'`" +fi +if test -z "$module_expsym_cmds"; then + module_expsym_cmds="`echo \"$archive_expsym_cmds\" | sed -e 's%$wl-soname $wl$soname%%'`" +fi + AC_ARG_ENABLE([rpath], [AS_HELP_STRING([--enable-rpath], [set hardcoded rpaths in the executable @<:@default=yes@:>@])], [], @@ -642,6 +661,8 @@ AC_ARG_ENABLE([ospfclient], (this is the default if --disable-ospfapi is set)])) AC_ARG_ENABLE([multipath], AS_HELP_STRING([--enable-multipath=ARG], [enable multipath function, ARG must be digit])) +AC_ARG_WITH([service_timeout], + AS_HELP_STRING([--with-service-timeout=ARG], [set service timeout value (2 minutes by default), ARG must be digit])) AC_ARG_ENABLE([user], AS_HELP_STRING([--enable-user=USER], [user to run FRR suite as (default frr)])) AC_ARG_ENABLE([group], @@ -674,8 +695,6 @@ AC_ARG_ENABLE([pcreposix], AS_HELP_STRING([--enable-pcreposix], [enable using PCRE Posix libs for regex functions])) AC_ARG_ENABLE([fpm], AS_HELP_STRING([--enable-fpm], [enable Forwarding Plane Manager support])) -AC_ARG_ENABLE([pcep], - AS_HELP_STRING([--enable-pcep], [enable PCEP support for pathd])) AC_ARG_ENABLE([werror], AS_HELP_STRING([--enable-werror], [enable -Werror (recommended for developers only)])) AC_ARG_ENABLE([cumulus], @@ -797,9 +816,12 @@ fi # AS_IF([test "$host" = "$build"], [ + AM_PATH_PYTHON([3]) AC_CHECK_HEADER([gelf.h], [], [ AC_MSG_ERROR([libelf headers are required for building clippy. (Host only when cross-compiling.)]) ]) + + LIBS_save="$LIBS" AC_CHECK_LIB([elf], [elf_memory], [], [ AC_MSG_ERROR([libelf is required for building clippy. (Host only when cross-compiling.)]) ]) @@ -810,6 +832,8 @@ AS_IF([test "$host" = "$build"], [ AC_CHECK_LIB([elf], [gelf_getnote], [ AC_DEFINE([HAVE_GELF_GETNOTE], [1], [Have gelf_getnote()]) ]) + LIBS="$LIBS_save" + unset LIBS_save FRR_PYTHON_DEV ], [ @@ -910,6 +934,20 @@ AC_DEFINE_UNQUOTED([MULTIPATH_NUM], [$MPATH_NUM], [Maximum number of paths for a AC_DEFINE_UNQUOTED([VTYSH_PAGER], ["$VTYSH_PAGER"], [What pager to use]) + +TIMEOUT_MIN=2 +case "${with_service_timeout}" in + [[1-9]|[1-9][0-9]|[1-9][0-9][0-9]]) + TIMEOUT_MIN="${with_service_timeout}" + ;; + 0|"") + ;; + *) + AC_MSG_FAILURE([Please specify digit for timeout ARG]) + ;; +esac +AC_SUBST([TIMEOUT_MIN]) + dnl -------------------- dnl Enable code coverage dnl -------------------- @@ -1566,8 +1604,17 @@ if test "$ac_cv_have_decl_TCP_MD5SIG" = "no"; then AC_CHECK_DECLS([TCP_MD5SIG], [], [], MD5_INCLUDES)]) fi -AC_CHECK_LIB([crypt], [crypt], [], - [AC_CHECK_LIB([crypto], [DES_crypt])]) +LIBS_save="$LIBS" +AC_CHECK_LIB([crypt], [crypt], [], [ + AC_CHECK_LIB([crypto], [DES_crypt]) +]) +LIBCRYPT="$LIBS" +LIBCRYPT="${LIBCRYPT%$LIBS_save}" +LIBCRYPT="${LIBCRYPT#$LIBS_save}" +AC_SUBST([LIBCRYPT]) +LIBS="$LIBS_save" +unset LIBS_save + AC_CHECK_LIB([resolv], [res_init]) dnl --------------------------- @@ -1714,7 +1761,6 @@ fi AS_IF([test "$enable_pathd" != "no"], [ AC_DEFINE([HAVE_PATHD], [1], [pathd]) - AC_DEFINE([HAVE_PATHD_PCEP], [1], [pathd-pcep]) ]) @@ -1776,7 +1822,7 @@ if test "$enable_bgp_vnc" != "no";then fi bgpd_bmp=false -case "${enable_bmp}" in +case "${enable_bgp_bmp}" in no) ;; yes) @@ -1882,6 +1928,7 @@ if test "$enable_confd" != "" -a "$enable_confd" != "no"; then if test "$CONFD" = "/bin/false"; then AC_MSG_ERROR([confd was not found on your system.])] fi + AC_CHECK_PROG([CONFDC], [confdc], [confdc], [/bin/false], "${enable_confd}/bin") CONFD_CFLAGS="-I${enable_confd}/include -L${enable_confd}/lib" AC_SUBST([CONFD_CFLAGS]) CONFD_LIBS="-lconfd" @@ -2021,6 +2068,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include "rtrlib/rtrlib.h"]], dnl --------------- dnl dlopen & dlinfo dnl --------------- +LIBS_save="$LIBS" AC_SEARCH_LIBS([dlopen], [dl dld], [], [ AC_MSG_ERROR([unable to find the dlopen()]) ]) @@ -2067,6 +2115,13 @@ if test "$frr_cv_rtld_di_linkmap" = "yes"; then AC_DEFINE([HAVE_DLINFO_LINKMAP], [1], [Have dlinfo RTLD_DI_LINKMAP]) fi +LIBDL="$LIBS" +LIBDL="${LIBDL%$LIBS_save}" +LIBDL="${LIBDL#$LIBS_save}" +AC_SUBST([LIBDL]) +LIBS="$LIBS_save" +unset LIBS_save + dnl ########################################################################## dnl test "$enable_clippy_only" != "yes" fi @@ -2234,7 +2289,16 @@ dnl -------------------------------------- dnl checking for flex and bison dnl -------------------------------------- -AM_PROG_LEX +dnl autoconf 2.69 AC_PROG_LEX has no parameters +dnl autoconf 2.70 AC_PROG_LEX prints a deprecation warning without params +m4_if(m4_version_compare(m4_defn([AC_AUTOCONF_VERSION]), [2.70]), [-1], [dnl + dnl autoconf < 2.70 + AC_PROG_LEX +], [ + dnl autoconf >= 2.70 + AC_PROG_LEX([noyywrap]) +]) + AC_MSG_CHECKING([version of flex]) frr_ac_flex_version="$(eval $LEX -V | grep flex | head -n 1)" frr_ac_flex_version="${frr_ac_flex_version##* }" diff --git a/debian/changelog b/debian/changelog index 99c75106db..f5b392274a 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,8 +1,20 @@ -frr (8.1~dev-1) UNRELEASED; urgency=medium +frr (8.2~dev-1) UNRELEASED; urgency=medium * New upstream release... - -- OndÅ™ej Surý <ondrej@debian.org> Tue, 04 May 2021 22:52:47 +0200 + -- Jafar Al-Gharaibeh <jafar@atcorp.com> Mon, 08 Nov 2021 10:00:00 +0500 + +frr (8.1-0) unstable; urgency=medium + + * New upstream release FRR 8.1 + + -- Jafar Al-Gharaibeh <jafar@atcorp.com> Tue, 02 Nov 2021 14:00:00 +0500 + +frr (8.0-0) unstable; urgency=medium + + * New upstream release FRR 8.0 + + -- Martin Winter <mwinter@opensourcerouting.org> Wed, 21 Jul 2021 13:42:00 +0200 frr (7.5.1-1) unstable; urgency=medium diff --git a/debian/frr-pythontools.install b/debian/frr-pythontools.install index 5f7eaebed5..820895ce68 100644 --- a/debian/frr-pythontools.install +++ b/debian/frr-pythontools.install @@ -1,2 +1,3 @@ usr/lib/frr/frr-reload.py usr/lib/frr/generate_support_bundle.py +usr/lib/frr/frr_babeltrace.py diff --git a/doc/developer/bgp-typecodes.rst b/doc/developer/bgp-typecodes.rst index beb7ca1f8a..c7921a772f 100644 --- a/doc/developer/bgp-typecodes.rst +++ b/doc/developer/bgp-typecodes.rst @@ -17,9 +17,6 @@ various BGP RFCs. In the code these are defined as BGP_ATTR_<ATTR>. | 8 | COMMUNITIES | [RFC 1997] | | 9 | ORIGINATOR_ID | [RFC 4456] | | 10 | CLUSTER_LIST | [RFC 4456] | -| 11 | DPA | [draft-ietf-idr-bgp-dpa-05.txt(expired)] | -| 12 | ADVERTISER | [RFC 1863] | -| 13 | RCID_PATH | [RFC 1863] | | 14 | MP_REACH_NLRI | [RFC 4760] | | 15 | MP_UNREACH_NLRI | [RFC 4760] | | 16 | EXT_COMMUNITIES | [RFC 4360] | diff --git a/doc/developer/building-frr-for-archlinux.rst b/doc/developer/building-frr-for-archlinux.rst index af1677e89e..406d22d618 100644 --- a/doc/developer/building-frr-for-archlinux.rst +++ b/doc/developer/building-frr-for-archlinux.rst @@ -11,7 +11,9 @@ Installing Dependencies git autoconf automake libtool make cmake pcre readline texinfo \ pkg-config pam json-c bison flex python-pytest \ c-ares python python2-ipaddress python-sphinx \ - net-snmp perl libcap libelf + net-snmp perl libcap libelf libunwind + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-centos7.rst b/doc/developer/building-frr-for-centos7.rst index ce11126f70..c40b5de594 100644 --- a/doc/developer/building-frr-for-centos7.rst +++ b/doc/developer/building-frr-for-centos7.rst @@ -22,7 +22,9 @@ Add packages: readline-devel texinfo net-snmp-devel groff pkgconfig \ json-c-devel pam-devel bison flex pytest c-ares-devel \ python-devel python-sphinx libcap-devel \ - elfutils-libelf-devel + elfutils-libelf-devel libunwind-devel + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-centos8.rst b/doc/developer/building-frr-for-centos8.rst index 109a7866d9..659752f6df 100644 --- a/doc/developer/building-frr-for-centos8.rst +++ b/doc/developer/building-frr-for-centos8.rst @@ -15,7 +15,9 @@ Add packages: automake libtool make readline-devel texinfo net-snmp-devel pkgconfig \ groff pkgconfig json-c-devel pam-devel bison flex python2-pytest \ c-ares-devel python2-devel libcap-devel \ - elfutils-libelf-devel + elfutils-libelf-devel libunwind-devel + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-debian9.rst b/doc/developer/building-frr-for-debian9.rst index f8d8025f62..b2fdef9990 100644 --- a/doc/developer/building-frr-for-debian9.rst +++ b/doc/developer/building-frr-for-debian9.rst @@ -11,7 +11,9 @@ Add packages: sudo apt-get install git autoconf automake libtool make \ libreadline-dev texinfo libjson-c-dev pkg-config bison flex \ libc-ares-dev python3-dev python3-pytest python3-sphinx build-essential \ - libsnmp-dev libcap-dev libelf-dev + libsnmp-dev libcap-dev libelf-dev libunwind-dev + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-fedora.rst b/doc/developer/building-frr-for-fedora.rst index 6ce76ba158..dc869ece10 100644 --- a/doc/developer/building-frr-for-fedora.rst +++ b/doc/developer/building-frr-for-fedora.rst @@ -15,7 +15,9 @@ Installing Dependencies readline-devel texinfo net-snmp-devel groff pkgconfig json-c-devel \ pam-devel python3-pytest bison flex c-ares-devel python3-devel \ python3-sphinx perl-core patch libcap-devel \ - elfutils-libelf-devel + elfutils-libelf-devel libunwind-devel + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-freebsd10.rst b/doc/developer/building-frr-for-freebsd10.rst index e85cb80053..5e70b81d43 100644 --- a/doc/developer/building-frr-for-freebsd10.rst +++ b/doc/developer/building-frr-for-freebsd10.rst @@ -17,7 +17,9 @@ is first package install and asked) :: pkg install git autoconf automake libtool gmake json-c pkgconf \ - bison flex py36-pytest c-ares python3.6 py36-sphinx + bison flex py36-pytest c-ares python3.6 py36-sphinx libunwind + +.. include:: building-libunwind-note.rst Make sure there is no /usr/bin/flex preinstalled (and use the newly installed in /usr/local/bin): (FreeBSD frequently provides a older flex diff --git a/doc/developer/building-frr-for-freebsd11.rst b/doc/developer/building-frr-for-freebsd11.rst index b97538b763..808207b831 100644 --- a/doc/developer/building-frr-for-freebsd11.rst +++ b/doc/developer/building-frr-for-freebsd11.rst @@ -17,7 +17,9 @@ is first package install and asked) .. code-block:: shell pkg install git autoconf automake libtool gmake json-c pkgconf \ - bison flex py36-pytest c-ares python3.6 py36-sphinx texinfo + bison flex py36-pytest c-ares python3.6 py36-sphinx texinfo libunwind + +.. include:: building-libunwind-note.rst Make sure there is no /usr/bin/flex preinstalled (and use the newly installed in /usr/local/bin): (FreeBSD frequently provides a older flex diff --git a/doc/developer/building-frr-for-opensuse.rst b/doc/developer/building-frr-for-opensuse.rst index ee6a36a14b..d9800a1638 100644 --- a/doc/developer/building-frr-for-opensuse.rst +++ b/doc/developer/building-frr-for-opensuse.rst @@ -14,7 +14,9 @@ Installing Dependencies readline-devel texinfo net-snmp-devel groff pkgconfig libjson-c-devel\ pam-devel python3-pytest bison flex c-ares-devel python3-devel\ python3-Sphinx perl patch libcap-devel libyang-devel \ - libelf-devel + libelf-devel libunwind-devel + +.. include:: building-libunwind-note.rst Building & Installing FRR ------------------------- diff --git a/doc/developer/building-frr-for-ubuntu1804.rst b/doc/developer/building-frr-for-ubuntu1804.rst index 3e8c6c0d0b..fcfd94ec2c 100644 --- a/doc/developer/building-frr-for-ubuntu1804.rst +++ b/doc/developer/building-frr-for-ubuntu1804.rst @@ -15,7 +15,9 @@ Installing Dependencies pkg-config libpam0g-dev libjson-c-dev bison flex \ libc-ares-dev python3-dev python3-sphinx \ install-info build-essential libsnmp-dev perl libcap-dev \ - libelf-dev + libelf-dev libunwind-dev + +.. include:: building-libunwind-note.rst .. include:: building-libyang.rst diff --git a/doc/developer/building-frr-for-ubuntu2004.rst b/doc/developer/building-frr-for-ubuntu2004.rst index 28e7ca6518..fdfc25da9d 100644 --- a/doc/developer/building-frr-for-ubuntu2004.rst +++ b/doc/developer/building-frr-for-ubuntu2004.rst @@ -15,7 +15,9 @@ Installing Dependencies pkg-config libpam0g-dev libjson-c-dev bison flex \ libc-ares-dev python3-dev python3-sphinx \ install-info build-essential libsnmp-dev perl \ - libcap-dev python2 libelf-dev + libcap-dev python2 libelf-dev libunwind-dev + +.. include:: building-libunwind-note.rst Note that Ubuntu 20 no longer installs python 2.x, so it must be installed explicitly. Ensure that your system has a symlink named diff --git a/doc/developer/building-libunwind-note.rst b/doc/developer/building-libunwind-note.rst new file mode 100644 index 0000000000..0beb1f8d37 --- /dev/null +++ b/doc/developer/building-libunwind-note.rst @@ -0,0 +1,6 @@ +.. note:: + + The ``libunwind`` library is optional but highly recommended, as it improves + backtraces printed for crashes and debugging. However, if it is not + available for some reason, it can simply be left out without any loss of + functionality. diff --git a/doc/developer/conf.py b/doc/developer/conf.py index 8f282c0790..79f8233978 100644 --- a/doc/developer/conf.py +++ b/doc/developer/conf.py @@ -136,8 +136,10 @@ language = None # directories to ignore when looking for source files. exclude_patterns = [ "_build", + "building-libunwind-note.rst", "building-libyang.rst", "topotests-snippets.rst", + "topotests-markers.rst", "include-compile.rst", ] diff --git a/doc/developer/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst index 08e3057ae6..6a7f9c4ca9 100644 --- a/doc/developer/frr-release-procedure.rst +++ b/doc/developer/frr-release-procedure.rst @@ -6,27 +6,33 @@ FRR Release Procedure ``<version>`` - version to be released, e.g. 7.3 ``origin`` - FRR upstream repository -1. Checkout ``dev/<version>``. +Stage 1 - Preparation +--------------------- + +#. Prepare changelog for the new release + + Note: use ``tools/release_notes.py`` to help draft release notes changelog + +#. Checkout the existing ``dev/<version>`` branch. .. code-block:: console git checkout dev/<version> -2. Create and push a new branch called ``stable/<version>`` based on the +#. Create and push a new branch called ``stable/<version>`` based on the ``dev/<version>`` branch. .. code-block:: console git checkout -b stable/<version> - git push origin stable/<version>:refs/heads/stable/<version> -3. Remove the development branch called ``dev/<version>`` +#. Remove the development branch called ``dev/<version>`` .. code-block:: console git push origin --delete dev/<version> -4. Update Changelog for Red Hat Packages: +#. Update Changelog for Red Hat Packages: Edit :file:`redhat/frr.spec.in` and look for the ``%changelog`` section: @@ -47,7 +53,7 @@ FRR Release Procedure - Add the changelog text below this entry. -5. Update Changelog for Debian Packages: +#. Update Changelog for Debian Packages: Update :file:`debian/changelog`: @@ -80,104 +86,148 @@ FRR Release Procedure . * Your Changes Here -6. Change main version number: +#. Commit the changes, adding the changelog to the commit message. Follow all + existing commit guidelines. The commit message should be akin to:: + + debian, redhat: updating changelog for new release + +#. Change main version number: + + - Edit :file:`configure.ac` and change version in the ``AC_INIT`` command + to ``<version>`` + + Add and commit this change. This commit should be separate from the commit + containing the changelog. The commit message should be:: + + FRR Release <version> + + The version field should be complete; i.e. for ``8.0.0``, the version should + be ``8.0.0`` and not ``8.0`` or ``8``. + + +Stage 2 - Staging +----------------- + +#. Push the stable branch to a new remote branch prefixed with ``rc``:: + + git push origin stable/<version>:rc/version - - Edit :file:`configure.ac` and change version in the ``AC_INIT`` command - to ``<version>`` + This will trigger the NetDEF CI, which serve as a sanity check on the + release branch. Verify that all tests pass and that all package builds are + successful. To do this, go to the NetDEF CI located here: -7. Commit the changes, adding the changelog to the commit message. Follow all - existing commit guidelines. + https://ci1.netdef.org/browse/FRR-FRR -8. Create and submit a GitHub pull request, with the ``HEAD`` set to - ``stable/<version>`` and the base set to the upstream ``master`` branch. - Allow NetDef CI to complete its run and verify that all package builds were - successful. + In the top left, look for ``rc-<version>`` in the "Plan branch" dropdown. + Select this version. Note that it may take a few minutes for the CI to kick + in on this new branch and appear in the list. -9. Create a git tag for the version: +#. Push the stable branch: .. code-block:: console - git tag -a frr-<version> -m "FRRouting Release <version>" + git push origin stable/<version>:refs/heads/stable/<version> -10. Push the commit and new tag. +#. Create and push a git tag for the version: .. code-block:: console - git push origin stable/<version>:refs/head/stable/<version> + git tag -a frr-<version> -m "FRRouting Release <version>" git push origin frr-<version> -11. Kick off the Release build plan on the CI system for the correct release. - Contact Martin Winter for this step. Ensure all release packages build - successfully. +#. Create a new branch based on ``master``, cherry-pick the commit made earlier + that added the changelogs, and use it to create a PR against ``master``. + This way ``master`` has the latest changelog for the next cycle. + +#. Kick off the "Release" build plan on the CI system for the correct release. + Contact Martin Winter for this step. Ensure all release packages build + successfully. + +#. Kick off the Snapcraft build plan for the release. + + +Stage 3 - Publish +----------------- -12. Kick off the Snapcraft build plan for the release. +#. Upload both the Debian and RPM packages to their respective repositories. -13. Acquire the release RPM binary packages from Martin Winter. +#. Coordinate with the maintainer of FRR's RPM repository to publish the RPM + packages on that repository. Update the repository webpage. Verify that the + instructions on the webpage work and that FRR is installable from the + repository on a Red Hat system. -14. On GitHub, go to the <https://github.com/FRRouting/frr/releases>_ and click - "Draft a new release". Write a release announcement. The release - announcement should follow the template in - ``release-announcement-template.md``, located next to this document. Check - for spelling errors, and optionally (but preferably) have other maintainers - proofread the announcement text. + Current maintainer: *Martin Winter* - Attach **only** the binary RPM packages to the GitHub release using - GitHub's attachment functionality. Do not attach Debian packages. Do not - attach source tarballs - these will be generated and attached by GitHub - automatically. Do not publish the release yet. +#. Coordinate with the maintainer of FRR Debian package to publish the Debian + packages on that repository. Update the repository webpage. Verify that the + instructions on the webpage work and that FRR is installable from the + repository on a Debian system. -15. Contact the current Debian maintainer for FRR to get new Debian packages - built and published on our APT repository at https://deb.frrouting.net/. - Ensure the webpage text is updated. Verify that new packages install - successfully on a vanilla Debian installation using the instructions on the - webpage. + Current maintainer: *Jafar Al-Gharaibeh* -16. Deploy Snapcraft release (after CI system finishes the tests for snapcraft - testplan). +#. Log in to the Read The Docs instance. in the "FRRouting" project, navigate + to the "Overview" tab. Ensure there is a ``stable-<version>`` version listed + and that it is enabled. Go to "Admin" and then "Advanced Settings". Change + "Default version" to the new version. This ensures that the documentation + shown to visitors is that of the latest release by default. -17. Update the Read The Docs instance to being publishing documentation built - off the ``stable/<version>`` branch. Contact Quentin Young for this step. + This step must be performed by someone with administrative access to the + Read the Docs instance. -18. Publish the GitHub release. +#. On GitHub, go to the <https://github.com/FRRouting/frr/releases>_ and click + "Draft a new release". Write a release announcement. The release + announcement should follow the template in + ``release-announcement-template.md``, located next to this document. Check + for spelling errors, and optionally (but preferably) have other maintainers + proofread the announcement text. -19. Clone the ``frr-www`` repository: + Do not attach any packages or source tarballs to the GitHub release. - .. code-block:: console + Publish the release once it is reviewed. - git clone https://github.com/FRRouting/frr-www.git +#. Deploy Snapcraft release. Remember that this will automatically upgrade Snap + users. -20. Add a new release announcement, using a previous announcement as template: + Current maintainer: *Martin Winter* - .. code-block:: console +#. Build and publish the Docker containers. - cp <old-version>-launch.md <version>-launch.md + Current maintainer: *Quentin Young* - Paste the GitHub release announcement text into this document, and **remove - line breaks**. In other words, this:: +#. Clone the ``frr-www`` repository: + + .. code-block:: console + + git clone https://github.com/FRRouting/frr-www.git + +#. Add a new release announcement, using a previous announcement as template: + + .. code-block:: console - This is one continuous - sentence that should be - rendered on one line + cp <old-version>.md <version>.md - Needs to be changed to this:: + Paste the GitHub release announcement text into this document, and **remove + line breaks**. In other words, this:: - This is one continuous sentence that should be rendered on one line + This is one continuous + sentence that should be + rendered on one line - This is very important otherwise the announcement will be unreadable on the - website. + Needs to be changed to this:: - Make sure to add a link to the GitHub releases page at the top. + This is one continuous sentence that should be rendered on one line - Once finished, manually add a new entry into ``index.html`` to link to this - new announcement. Look at past commits to see how to do this. + This is very important otherwise the announcement will be unreadable on the + website. -21. Deploy the updated ``frr-www`` on the frrouting.org web server and verify - that the announcement text is visible. + Make sure to add a link to the GitHub releases page at the top. -22. Send an email to ``announce@lists.frrouting.org``. The text of this email - should include the text from the GitHub release. + Once finished, manually add a new entry into ``index.html`` to link to this + new announcement. Look at past commits to see how to do this. -23. Update masters version of the changelog-auto.in +#. Deploy the updated ``frr-www`` on the frrouting.org web server and verify + that the announcement text is visible. - Take the change data and cut-n-paste the changes into the master version below - the @VERSION@-0 lines. So we have the history of the previous release. +#. Send an email to ``announce@lists.frrouting.org``. The text of this email + should include text as appropriate from the GitHub release and a link to the + GitHub release, Debian repository, and RPM repository. diff --git a/doc/developer/link-state.rst b/doc/developer/link-state.rst index 1cbaf27ffe..2072595e36 100644 --- a/doc/developer/link-state.rst +++ b/doc/developer/link-state.rst @@ -53,15 +53,15 @@ Data structures 3 types of Link State structure have been defined: -.. c:type:: struct ls_node +.. c:struct:: ls_node that groups all information related to a node -.. c:type:: struct ls_attributes +.. c:struct:: ls_attributes that groups all information related to a link -.. c:type:: struct ls_prefix +.. c:struct:: ls_prefix that groups all information related to a prefix @@ -73,7 +73,7 @@ identifier which advertises the Link State and a bit mask as flags to indicates which parameters are valid i.e. for which the value is valid and corresponds to a Link State information conveyed by the routing protocol. -.. c:type:: struct ls_node_id +.. c:struct:: ls_node_id defines the Node identifier as router ID IPv4 address plus the area ID for OSPF or the ISO System ID plus the IS-IS level for IS-IS. @@ -159,10 +159,11 @@ A unique Key is used to identify both Vertices and Edges within the Graph. 4 data structures have been defined to implement the Graph model: -.. c:type:: struct ls_vertex -.. c:type:: struct ls_edge -.. c:type:: struct ls_prefix -.. c:type:: struct ls_ted +.. c:struct:: ls_vertex +.. c:struct:: ls_edge +.. c:struct:: ls_ted + + - :c:struct:`ls_prefix` TED stores Vertex, Edge and Subnet elements with a RB Tree structure. The Vertex key corresponds to the Router ID for OSPF and ISO System ID for @@ -412,7 +413,7 @@ Data Structures The Link State Message is defined to convey Link State parameters from the routing protocol (OSPF or IS-IS) to other daemons e.g. BGP. -.. c:type:: struct ls_message +.. c:struct:: ls_message The structure is composed of: diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst index 553bd1f596..dc8f236927 100644 --- a/doc/developer/lists.rst +++ b/doc/developer/lists.rst @@ -106,19 +106,25 @@ Functions provided: | _init, _fini | yes | yes | yes | yes | yes | +------------------------------------+------+------+------+---------+------------+ | _first, _next, _next_safe, | yes | yes | yes | yes | yes | +| | | | | | | | _const_first, _const_next | | | | | | +------------------------------------+------+------+------+---------+------------+ | _swap_all | yes | yes | yes | yes | yes | +------------------------------------+------+------+------+---------+------------+ +| _anywhere | yes | -- | -- | -- | -- | ++------------------------------------+------+------+------+---------+------------+ | _add_head, _add_tail, _add_after | yes | -- | -- | -- | -- | +------------------------------------+------+------+------+---------+------------+ | _add | -- | yes | yes | yes | yes | +------------------------------------+------+------+------+---------+------------+ +| _member | yes | yes | yes | yes | yes | ++------------------------------------+------+------+------+---------+------------+ | _del, _pop | yes | yes | yes | yes | yes | +------------------------------------+------+------+------+---------+------------+ | _find, _const_find | -- | -- | yes | yes | -- | +------------------------------------+------+------+------+---------+------------+ | _find_lt, _find_gteq, | -- | -- | -- | yes | yes | +| | | | | | | | _const_find_lt, _const_find_gteq | | | | | | +------------------------------------+------+------+------+---------+------------+ | use with frr_each() macros | yes | yes | yes | yes | yes | @@ -182,7 +188,7 @@ Common iteration macros The following iteration macros work across all data structures: -.. c:function:: frr_each(Z, &head, item) +.. c:macro:: frr_each(Z, head, item) Equivalent to: @@ -193,7 +199,7 @@ The following iteration macros work across all data structures: Note that this will fail if the list is modified while being iterated over. -.. c:function:: frr_each_safe(Z, &head, item) +.. c:macro:: frr_each_safe(Z, head, item) Same as the previous, but the next element is pre-loaded into a "hidden" variable (named ``Z_safe``.) Equivalent to: @@ -212,7 +218,7 @@ The following iteration macros work across all data structures: tables is resized while iterating. This will cause items to be skipped or iterated over twice. -.. c:function:: frr_each_from(Z, &head, item, from) +.. c:macro:: frr_each_from(Z, head, item, from) Iterates over the list, starting at item ``from``. This variant is "safe" as in the previous macro. Equivalent to: @@ -268,6 +274,16 @@ The following documentation assumes that a list has been defined using outdated by the time this function returns and can therefore only be used as an estimate. +.. c:function:: bool Z_member(const struct Z_head *, const itemtype *) + + Determines whether some item is a member of the given container. The + item must either be valid on some container, or set to all zeroes. + + On some containers, if no faster way to determine membership is possible, + this is simply ``item == Z_find(head, item)``. + + Not currently available for atomic containers. + .. c:function:: const itemtype *Z_const_first(const struct Z_head *) .. c:function:: itemtype *Z_first(struct Z_head *) @@ -297,7 +313,7 @@ The following documentation assumes that a list has been defined using affected by the "modification while iterating" problem. To remove all items from a hash table, use the loop demonstrated above. -.. c:function:: const itemtype *Z_next(const struct Z_head *, const itemtype *prev) +.. c:function:: const itemtype *Z_const_next(const struct Z_head *, const itemtype *prev) .. c:function:: itemtype *Z_next(struct Z_head *, itemtype *prev) Return the item that follows after ``prev``, or ``NULL`` if ``prev`` is @@ -346,7 +362,7 @@ are several functions exposed to insert data: ``item`` must not be ``NULL`` for any of the following functions. -.. c:function:: DECLARE_XXX(Z, type, field) +.. c:macro:: DECLARE_XXX(Z, type, field) :param listtype XXX: ``LIST``, ``DLIST`` or ``ATOMLIST`` to select a data structure implementation. @@ -396,6 +412,17 @@ are several functions exposed to insert data: maybe flip the order of ``item`` & ``after``? ``Z_add_after(head, item, after)`` +.. c:function:: bool Z_anywhere(const itemtype *) + + Returns whether an item is a member of *any* container of this type. + The item must either be valid on some container, or set to all zeroes. + + Guaranteed to be fast (pointer compare or similar.) + + Not currently available for sorted and atomic containers. Might be added + for sorted containers at some point (when needed.) + + API for sorted structures ------------------------- @@ -403,7 +430,7 @@ Sorted data structures do not need to have an insertion position specified, therefore the insertion calls are different from unsorted lists. Also, sorted lists can be searched for a value. -.. c:function:: DECLARE_XXX_UNIQ(Z, type, field, compare_func) +.. c:macro:: DECLARE_XXX_UNIQ(Z, type, field, compare_func) :param listtype XXX: One of the following: ``SORTLIST`` (single-linked sorted list), ``SKIPLIST`` (skiplist), @@ -423,7 +450,7 @@ sorted lists can be searched for a value. ``int function(const itemtype *, const itemtype*)``. This function may be static if the list is only used in one file. -.. c:function:: DECLARE_XXX_NONUNIQ(Z, type, field, compare_func) +.. c:macro:: DECLARE_XXX_NONUNIQ(Z, type, field, compare_func) Same as above, but allow adding multiple items to the list that compare as equal in ``compare_func``. Ordering between these items is undefined @@ -439,7 +466,7 @@ sorted lists can be searched for a value. For ``_NONUNIQ`` lists, this function always returns NULL since ``item`` can always be successfully added to the list. -.. c:function:: const itemtype *Z_find(const struct Z_head *, const itemtype *ref) +.. c:function:: const itemtype *Z_const_find(const struct Z_head *, const itemtype *ref) .. c:function:: itemtype *Z_find(struct Z_head *, const itemtype *ref) Search the list for an item that compares equal to ``ref``. If no equal @@ -461,13 +488,13 @@ sorted lists can be searched for a value. containing non-unique items, more than one item may compare as equal to the item that is searched for. -.. c:function:: const itemtype *Z_find_gteq(const struct Z_head *, const itemtype *ref) +.. c:function:: const itemtype *Z_const_find_gteq(const struct Z_head *, const itemtype *ref) .. c:function:: itemtype *Z_find_gteq(struct Z_head *, const itemtype *ref) Search the list for an item that compares greater or equal to ``ref``. See :c:func:`Z_find()` above. -.. c:function:: const itemtype *Z_find_lt(const struct Z_head *, const itemtype *ref) +.. c:function:: const itemtype *Z_const_find_lt(const struct Z_head *, const itemtype *ref) .. c:function:: itemtype *Z_find_lt(struct Z_head *, const itemtype *ref) Search the list for an item that compares less than @@ -477,9 +504,9 @@ sorted lists can be searched for a value. API for hash tables ------------------- -.. c:function:: DECLARE_XXX(Z, type, field, compare_func, hash_func) +.. c:macro:: DECLARE_HASH(Z, type, field, compare_func, hash_func) - :param listtype XXX: Only ``HASH`` is currently available. + :param listtype HASH: Only ``HASH`` is currently available. :param token Z: Gives the name prefix that is used for the functions created for this instantiation. ``DECLARE_XXX(foo, ...)`` gives ``struct foo_item``, ``foo_add()``, ``foo_count()``, etc. Note diff --git a/doc/developer/locking.rst b/doc/developer/locking.rst index d698789f9f..c8366480d2 100644 --- a/doc/developer/locking.rst +++ b/doc/developer/locking.rst @@ -7,7 +7,9 @@ FRR ships two small wrappers around ``pthread_mutex_lock()`` / ``pthread_mutex_unlock``. Use ``#include "frr_pthread.h"`` to get these macros. -.. c:function:: frr_with_mutex(pthread_mutex_t *mutex) +.. c:macro:: frr_with_mutex(mutex) + + (With ``pthread_mutex_t *mutex``.) Begin a C statement block that is executed with the mutex locked. Any exit from the block (``break``, ``return``, ``goto``, end of block) will @@ -43,7 +45,9 @@ macros. statement works correctly, FRR coding style requires that this macro always be used with a ``{ ... }`` block. -.. c:function:: frr_mutex_lock_autounlock(pthread_mutex_t *mutex) +.. c:macro:: frr_mutex_lock_autounlock(mutex) + + (With ``pthread_mutex_t *mutex``.) Lock mutex and unlock at the end of the current C statement block:: diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst index 681fc1173c..eaf8625efa 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -489,7 +489,7 @@ calls to :c:func:`zlog_tls_buffer_flush()` in appropriate places: buffer. This function is safe to call regardless of the per-thread log buffer being set up / in use or not. -When working with threads that do not use the :c:type:`struct thread_master` +When working with threads that do not use the :c:struct:`thread_master` event loop, per-thread buffers can be managed with: .. c:function:: void zlog_tls_buffer_init(void) @@ -531,7 +531,7 @@ that they use. Basic internals ^^^^^^^^^^^^^^^ -.. c:type:: struct zlog_target +.. c:struct:: zlog_target This struct needs to be filled in by any log target and then passed to :c:func:`zlog_target_replace()`. After it has been registered, @@ -570,7 +570,7 @@ Basic internals Allocates a logging target struct. Note that the ``oldzt`` argument may be ``NULL`` to allocate a "from scratch". If ``oldzt`` is not ``NULL``, the - generic bits in :c:type:`struct zlog_target` are copied. **Target specific + generic bits in :c:struct:`zlog_target` are copied. **Target specific bits are not copied.** .. c:function:: struct zlog_target *zlog_target_replace(struct zlog_target *oldzt, struct zlog_target *newzt) diff --git a/doc/developer/memtypes.rst b/doc/developer/memtypes.rst index 08dad7fb68..2e181c4f2b 100644 --- a/doc/developer/memtypes.rst +++ b/doc/developer/memtypes.rst @@ -42,7 +42,7 @@ Example: Definition ---------- -.. c:type:: struct memtype +.. c:struct:: memtype This is the (internal) type used for MTYPE definitions. The macros below should be used to create these, but in some cases it is useful to pass a diff --git a/doc/developer/process-architecture.rst b/doc/developer/process-architecture.rst index 6a028d0000..37bd620f24 100644 --- a/doc/developer/process-architecture.rst +++ b/doc/developer/process-architecture.rst @@ -3,34 +3,38 @@ Process Architecture ==================== -FRR inherited its overall design architecture from Quagga. The chosen model for -Quagga is that of a suite of independent daemons that do IPC via Unix domain -sockets. Within each daemon, the architecture follows the event-driven model. -FRR has inherited this model as well. As FRR is deployed at larger scales and -gains ever more features, each adding to the overall processing workload, we -are approaching the saturation point for a single thread per daemon. In light -of this, there are ongoing efforts to introduce multithreading to various -components of FRR. This document aims to describe the current design choices -and overall model for integrating the event-driven and multithreaded -architectures into a cohesive whole. +FRR is a suite of daemons that serve different functions. This document +describes internal architecture of daemons, focusing their general design +patterns, and especially how threads are used in the daemons that use them. + +Overview +-------- +The fundamental pattern used in FRR daemons is an `event loop +<https://en.wikipedia.org/wiki/Event_loop>`_. Some daemons use `kernel threads +<https://en.wikipedia.org/wiki/Thread_(computing)#Kernel_threads>`_. In these +daemons, each kernel thread runs its own event loop. The event loop +implementation is constructed to be thread safe and to allow threads other than +its owning thread to schedule events on it. The rest of this document describes +these two designs in detail. Terminology ----------- -Because this document describes the architecture for true kernel threads as -well as the event system, a digression on terminology is in order here. +Because this document describes the architecture for kernel threads as well as +the event system, a digression on terminology is in order here. -Historically Quagga's event system was viewed as an implementation of userspace +Historically Quagga's loop system was viewed as an implementation of userspace threading. Because of this design choice, the names for various datastructures within the event system are variations on the term "thread". The primary -context datastructure in this system is called a "threadmaster". What would -today be called an 'event' or 'task' in systems such as libevent are called -"threads" and the datastructure for them is ``struct thread``. To add to the -confusion, these "threads" have various types, one of which is "event". To -hopefully avoid some of this confusion, this document refers to these "threads" -as a 'task' except where the datastructures are explicitly named. When they are -explicitly named, they will be formatted ``like this`` to differentiate from -the conceptual names. When speaking of kernel threads, the term used will be -"pthread" since FRR's kernel threading implementation is POSIX threads. +datastructure that holds the state of an event loop in this system is called a +"threadmaster". Events scheduled on the event loop - what would today be called +an 'event' or 'task' in systems such as libevent - are called "threads" and the +datastructure for them is ``struct thread``. To add to the confusion, these +"threads" have various types, one of which is "event". To hopefully avoid some +of this confusion, this document refers to these "threads" as a 'task' except +where the datastructures are explicitly named. When they are explicitly named, +they will be formatted ``like this`` to differentiate from the conceptual +names. When speaking of kernel threads, the term used will be "pthread" since +FRR's kernel threading implementation uses the POSIX threads API. .. This should be broken into its document under :ref:`libfrr` .. _event-architecture: diff --git a/doc/developer/rcu.rst b/doc/developer/rcu.rst index c2ddf93f53..c8248194b7 100644 --- a/doc/developer/rcu.rst +++ b/doc/developer/rcu.rst @@ -133,9 +133,9 @@ atomic ops & datastructures with other types of locking, e.g. rwlocks. become invalid, as another thread may have called :c:func:`rcu_free` on them. -.. c:type:: struct rcu_head -.. c:type:: struct rcu_head_close -.. c:type:: struct rcu_action +.. c:struct:: rcu_head +.. c:struct:: rcu_head_close +.. c:struct:: rcu_action The ``rcu_head`` structures are small (16-byte) bits that contain the queueing machinery for the RCU sweeper/cleanup mechanisms. @@ -209,7 +209,7 @@ atomic ops & datastructures with other types of locking, e.g. rwlocks. Internals ^^^^^^^^^ -.. c:type:: struct rcu_thread +.. c:struct:: rcu_thread Per-thread state maintained by the RCU code, set up by the following functions. A pointer to a thread's own ``rcu_thread`` is saved in diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index d16420c7e7..c8654d6725 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -23,6 +23,7 @@ dev_RSTFILES = \ doc/developer/building-frr-for-ubuntu1604.rst \ doc/developer/building-frr-for-ubuntu1804.rst \ doc/developer/building-frr-for-ubuntu2004.rst \ + doc/developer/building-libunwind-note.rst \ doc/developer/building-libyang.rst \ doc/developer/building.rst \ doc/developer/cli.rst \ diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index b4f6ec521c..fa1fd20067 100644 --- a/doc/developer/topotests.rst +++ b/doc/developer/topotests.rst @@ -8,19 +8,21 @@ Topotests is a suite of topology tests for FRR built on top of micronet. Installation and Setup ---------------------- -Topotests run under python3. Additionally, for ExaBGP (which is used in some of -the BGP tests) an older python2 version must be installed. +Topotests run under python3. Additionally, for ExaBGP (which is used +in some of the BGP tests) an older python2 version (and the python2 +version of ``pip``) must be installed. -Tested with Ubuntu 20.04 and Ubuntu 18.04 and Debian 11. +Tested with Ubuntu 20.04,Ubuntu 18.04, and Debian 11. -Instructions are the same for all setups (i.e. ExaBGP is only used for BGP -tests). +Instructions are the same for all setups (i.e. ExaBGP is only used for +BGP tests). Installing Topotest Requirements ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code:: shell + apt-get install gdb apt-get install iproute2 apt-get install net-tools apt-get install python3-pip @@ -41,7 +43,6 @@ Optional, will give better output. .. code:: shell - apt-get install gdb disable apport (which move core files) Set ``enabled=0`` in ``/etc/default/apport``. @@ -137,14 +138,14 @@ Topotests must be run as root. Normally this will be accomplished through the use of the ``sudo`` command. In order for topotests to be able to open new windows (either XTerm or byobu/screen/tmux windows) certain environment variables must be passed through the sudo command. One way to do this is to -specify the :option:`-E` flag to ``sudo``. This will carry over most if not all +specify the ``-E`` flag to ``sudo``. This will carry over most if not all your environment variables include ``PATH``. For example: .. code:: shell sudo -E python3 -m pytest -s -v -If you do not wish to use :option:`-E` (e.g., to avoid ``sudo`` inheriting +If you do not wish to use ``-E`` (e.g., to avoid ``sudo`` inheriting ``PATH``) you can modify your `/etc/sudoers` config file to specifically pass the environment variables required by topotests. Add the following commands to your ``/etc/sudoers`` config file. @@ -197,7 +198,7 @@ the run. Here we see that 4 tests have failed. We an dig deeper by displaying the captured logs and errors. First let's redisplay the results enumerated by adding -the :option:`-E` flag +the ``-E`` flag .. code:: shell @@ -385,7 +386,7 @@ to launch the given programs. NOTE: you must run the topotest (pytest) such that your DISPLAY, STY or TMUX environment variables are carried over. You can do this by passing the -:option:`-E` flag to ``sudo`` or you can modify your ``/etc/sudoers`` config to +``-E`` flag to ``sudo`` or you can modify your ``/etc/sudoers`` config to automatically pass that environment variable through to the ``sudo`` environment. @@ -903,6 +904,7 @@ Interface), from here you can call your router ``vtysh`` or even bash. Here's the help text: .. code:: shell + unet> help Commands: @@ -912,8 +914,6 @@ Here's the help text: vtysh [hosts] :: open vtysh terminals for hosts [hosts] <vtysh-command> :: execute vtysh-command on hosts -.. code:: shell - Here are some commands example: .. code:: shell diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index 2ce5f5d1c8..e52ec056ad 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -98,6 +98,16 @@ March/July/November. Walking backwards from this date: ``dev/MAJOR.MINOR`` at this point) and a ``rc1`` release candidate is tagged. Master is unfrozen and new features may again proceed. + Part of unfreezing master is editing the ``AC_INIT`` statement in + :file:`configure.ac` to reflect the new development version that master + now refers to. This is accompanied by a ``frr-X.Y-dev`` tag on master, + which should always be on the first commit on master *after* the stable + branch was forked (even if that is not the edit to ``AC_INIT``; it's more + important to have it on the very first commit on master after the fork.) + + (The :file:`configure.ac` edit and tag push are considered git housekeeping + and are pushed directly to ``master``, not through a PR.) + - 2 weeks earlier, a ``rc2`` release candidate is tagged. - on release date, the branch is renamed to ``stable/MAJOR.MINOR``. @@ -1151,6 +1161,37 @@ 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. +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, + + 1. install GCC plugin development files, e.g.:: + + apt-get install gcc-10-plugin-dev + + 2. **before** running ``configure``, compile the plugin with:: + + make -C tools/gcc-plugins CXX=g++-10 + + (Edit the GCC version to what you're using, it should work for GCC 9 or + newer.) + + After this, the plugin should be automatically picked up by ``configure``. + The plugin does not change very frequently, so you can keep it around across + work on different FRR branches. After a ``git clean -x``, the ``make`` line + will need to be run again. You can also add ``--with-frr-format`` to the + ``configure`` line to make sure the plugin is used, otherwise if something + is not set up correctly it might be silently ignored. + + .. warning:: + + Do **not** enable this plugin for package/release builds. It is intended + for developer/debug builds only. Since it modifies the compiler, it may + cause silent corruption of the executable files. + + Using the plugin also changes the string for ``PRI[udx]64`` from the + system value to ``%L[udx]`` (normally ``%ll[udx]`` or ``%l[udx]``.) + Additionally, the FRR codebase is regularly scanned with Coverity. Unfortunately Coverity does not have the ability to handle scanning pull requests, but after code is merged it will send an email notifying project @@ -1264,6 +1305,24 @@ may not be obvious in how to fix. Here are some notes on specific warnings: (and varargs calling convention.) This is a notable difference to C++, where the ``void`` is optional and an empty parameter list means no parameters. +* ``"strict match required"`` from the frr-format plugin: check if you are + using a cast in a printf parameter list. The frr-format plugin cannot + access correct full type information for casts like + ``printfrr(..., (uint64_t)something, ...)`` and will print incorrect + warnings particularly if ``uint64_t``, ``size_t`` or ``ptrdiff_t`` are + involved. The problem is *not* triggered with a variable or function return + value of the exact same type (without a cast). + + Since these cases are very rare, community consensus is to just work around + the warning even though the code might be correct. If you are running into + this, your options are: + + 1. try to avoid the cast altogether, maybe using a different printf format + specifier (e.g. ``%lu`` instead of ``%zu`` or ``PRIu64``). + 2. fix the type(s) of the function/variable/struct member being printed + 3. create a temporary variable with the value and print that without a cast + (this is the last resort and was not necessary anywhere so far.) + .. _documentation: diff --git a/doc/user/babeld.rst b/doc/user/babeld.rst index c8015bb7e5..bda0045a60 100644 --- a/doc/user/babeld.rst +++ b/doc/user/babeld.rst @@ -132,7 +132,7 @@ Babel configuration This specifies the minimum RTT, in milliseconds, starting from which we increase the cost to a neighbour. The additional cost is linear in - (rtt - rtt-min). The default is 100 ms. + (rtt - rtt-min). The default is 10 ms. .. clicmd:: babel rtt-max (1-65535) @@ -144,8 +144,8 @@ Babel configuration .. clicmd:: babel max-rtt-penalty (0-65535) This specifies the maximum cost added to a neighbour because of RTT, i.e. - when the RTT is higher or equal than rtt-max. The default is 0, which - effectively disables the use of a RTT-based cost. + when the RTT is higher or equal than rtt-max. The default is 150. Setting it + to 0 effectively disables the use of a RTT-based cost. .. clicmd:: babel enable-timestamps @@ -268,6 +268,6 @@ Babel sample configuration file ! babel hello-interval 12000 ! babel update-interval 36000 - ! log file /var/log/quagga/babeld.log + ! log file /var/log/frr/babeld.log log stdout diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 16708adb50..69f276d551 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -244,6 +244,42 @@ Basic Config Commands Use unbuffered output for log and debug messages; normally there is some internal buffering. +.. clicmd:: log unique-id + + Include ``[XXXXX-XXXXX]`` log message unique identifier in the textual part + of log messages. This is enabled by default, but can be disabled with + ``no log unique-id``. Please make sure the IDs are enabled when including + logs for FRR bug reports. + + The unique identifiers are automatically generated based on source code + file name, format string (before filling out) and severity. They do not + change "randomly", but some cleanup work may cause large chunks of ID + changes between releases. The IDs always start with a letter, consist of + letters and numbers (and a dash for readability), are case insensitive, and + ``I``, ``L``, ``O`` & ``U`` are excluded. + + This option will not affect future logging targets which allow putting the + unique identifier in auxiliary metadata outside the log message text + content. (No such logging target exists currently, but RFC5424 syslog and + systemd's journald both support it.) + +.. clicmd:: debug unique-id XXXXX-XXXXX backtrace + + Print backtraces (call stack) for specific log messages, identified by + their unique ID (see above.) Includes source code location and current + event handler being executed. On some systems you may need to install a + `debug symbols` package to get proper function names rather than raw code + pointers. + + This command can be issued inside and outside configuration mode, and is + saved to configuration only if it was given in configuration mode. + + .. warning:: + + Printing backtraces can significantly slow down logging calls and cause + log files to quickly balloon in size. Remember to disable backtraces + when they're no longer needed. + .. clicmd:: service password-encryption Encrypt password. diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index 5fcddafaaa..ada14b4fa1 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -515,7 +515,7 @@ Disable checking if nexthop is connected on EBGP sessions Route Flap Dampening -------------------- -.. clicmd:: bgp dampening (1-45) (1-20000) (1-20000) (1-255) +.. clicmd:: bgp dampening (1-45) (1-20000) (1-50000) (1-255) This command enables BGP route-flap dampening and specifies dampening parameters. @@ -924,6 +924,17 @@ However, it MUST defer route selection for an address family until it either. 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 @@ -989,6 +1000,20 @@ BGP GR Peer Mode Commands at the peer level. +Long-lived Graceful Restart +--------------------------- + +Currently, only restarter mode is supported. This capability is advertised only +if graceful restart capability is negotiated. + +.. clicmd:: bgp long-lived-graceful-restart stale-time (1-4294967295) + + Specifies the maximum time to wait before purging long-lived stale routes for + helper routers. + + Default is 0, which means the feature is off by default. Only graceful + restart takes into account. + .. _bgp-shutdown: Administrative Shutdown @@ -1411,6 +1436,15 @@ Configuring Peers value is carried encoded as uint32. To enable backward compatibility we need to disable IEEE floating-point encoding option per-peer. +.. clicmd:: neighbor PEER extended-optional-parameters + + Force Extended Optional Parameters Length format to be used for OPEN messages. + + By default, it's disabled. If the standard optional parameters length is + higher than one-octet (255), then extended format is enabled automatically. + + For testing purposes, extended format can be enabled with this command. + .. clicmd:: neighbor PEER ebgp-multihop Specifying ``ebgp-multihop`` allows sessions with eBGP neighbors to @@ -1425,15 +1459,6 @@ Configuring Peers Set description of the peer. -.. clicmd:: neighbor PEER version VERSION - - Set up the neighbor's BGP version. `version` can be `4`, `4+` or `4-`. BGP - version `4` is the default value used for BGP peering. BGP version `4+` - means that the neighbor supports Multiprotocol Extensions for BGP-4. BGP - version `4-` is similar but the neighbor speaks the old Internet-Draft - revision 00's Multiprotocol Extensions for BGP-4. Some routing software is - still using this version. - .. clicmd:: neighbor PEER interface IFNAME When you connect to a BGP peer over an IPv6 link-local address, you have to @@ -1441,9 +1466,6 @@ Configuring Peers IPv4 session addresses, see the ``neighbor PEER update-source`` command below. - This command is deprecated and may be removed in a future release. Its use - should be avoided. - .. clicmd:: neighbor PEER interface remote-as <internal|external|ASN> Configure an unnumbered BGP peer. ``PEER`` should be an interface name. The @@ -1479,12 +1501,30 @@ Configuring Peers neighbor bar update-source lo0 -.. clicmd:: neighbor PEER default-originate +.. clicmd:: neighbor PEER default-originate [route-map WORD] *bgpd*'s default is to not announce the default route (0.0.0.0/0) even if it is in routing table. When you want to announce default routes to the peer, use this command. + If ``route-map`` keyword is specified, then the default route will be + originated only if route-map conditions are met. For example, announce + the default route only if ``10.10.10.10/32`` route exists and set an + arbitrary community for a default route. + + .. code-block:: frr + + router bgp 64555 + address-family ipv4 unicast + neighbor 192.168.255.1 default-originate route-map default + ! + ip prefix-list p1 seq 5 permit 10.10.10.10/32 + ! + route-map default permit 10 + match ip address prefix-list p1 + set community 123:123 + ! + .. clicmd:: neighbor PEER port PORT .. clicmd:: neighbor PEER password PASSWORD @@ -3006,8 +3046,8 @@ following zebra command - .. clicmd:: evpn mh startup-delay (0-3600) -+Support with VRF network namespace backend -+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +Support with VRF network namespace backend +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ It is possible to separate overlay networks contained in VXLAN interfaces from underlay networks by using VRFs. VRF-lite and VRF-netns backends can be used for that. In the latter case, it is necessary to set both bridge and vxlan interface @@ -3553,6 +3593,13 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. Display flap statistics of routes of the selected afi and safi selected. +.. clicmd:: show bgp [afi] [safi] [all] dampening parameters [json] + + Display details of configured dampening parameters of the selected afi and + safi. + + If the ``json`` option is specified, output is displayed in JSON format. + .. clicmd:: show bgp [afi] [safi] [all] version (1-4294967295) [wide|json] Display prefixes with matching version numbers. The version number and @@ -3585,6 +3632,42 @@ structure is extended with :clicmd:`show bgp [afi] [safi]`. Display routes with non-natural netmasks. +.. clicmd:: show [ip] bgp [afi] [safi] [all] prefix-list WORD [wide|json] + + Display routes that match the specified prefix-list. + + If ``wide`` option is specified, then the prefix table's width is increased + to fully display the prefix and the nexthop. + + If the ``json`` option is specified, output is displayed in JSON format. + +.. clicmd:: show [ip] bgp [afi] [safi] [all] filter-list WORD [wide|json] + + Display routes that match the specified AS-Path filter-list. + + If ``wide`` option is specified, then the prefix table's width is increased + to fully display the prefix and the nexthop. + + If the ``json`` option is specified, output is displayed in JSON format. + +.. clicmd:: show [ip] bgp [afi] [safi] [all] route-map WORD [wide|json] + + Display routes that match the specified route-map. + + If ``wide`` option is specified, then the prefix table's width is increased + to fully display the prefix and the nexthop. + + If the ``json`` option is specified, output is displayed in JSON format. + +.. clicmd:: show [ip] bgp [afi] [safi] [all] <A.B.C.D/M|X:X::X:X/M> longer-prefixes [wide|json] + + Displays the specified route and all more specific routes. + + If ``wide`` option is specified, then the prefix table's width is increased + to fully display the prefix and the nexthop. + + If the ``json`` option is specified, output is displayed in JSON format. + .. clicmd:: show [ip] bgp [afi] [safi] [all] neighbors A.B.C.D [advertised-routes|received-routes|filtered-routes] [json|wide] Display the routes advertised to a BGP neighbor or received routes @@ -3623,9 +3706,9 @@ attribute. community are displayed. When `exact-match` is specified, it display only routes that have an exact match. -.. clicmd:: show [ip] bgp <ipv4|ipv6> community-list WORD +.. clicmd:: show [ip] bgp <ipv4|ipv6> community-list WORD [json] -.. clicmd:: show [ip] bgp <ipv4|ipv6> community-list WORD exact-match +.. clicmd:: show [ip] bgp <ipv4|ipv6> community-list WORD exact-match [json] These commands display BGP routes for the address family specified that match the specified community list. When `exact-match` is specified, it diff --git a/doc/user/images/pathd_config.png b/doc/user/images/pathd_config.png Binary files differnew file mode 100644 index 0000000000..b7be1a6929 --- /dev/null +++ b/doc/user/images/pathd_config.png diff --git a/doc/user/images/pathd_general.png b/doc/user/images/pathd_general.png Binary files differnew file mode 100644 index 0000000000..1da6d46c0a --- /dev/null +++ b/doc/user/images/pathd_general.png diff --git a/doc/user/images/pathd_initiated_multi.png b/doc/user/images/pathd_initiated_multi.png Binary files differnew file mode 100644 index 0000000000..5c818e6112 --- /dev/null +++ b/doc/user/images/pathd_initiated_multi.png diff --git a/doc/user/installation.rst b/doc/user/installation.rst index fdf5bab9c9..b24a9fb471 100644 --- a/doc/user/installation.rst +++ b/doc/user/installation.rst @@ -273,6 +273,13 @@ options from the list below. Build with FPM module support. +.. option:: --with-service-timeout=X + + Set timeout value for FRR service. The time of restarting or reloading FRR + service should not exceed this value. This number can be from 0-999. + Additionally if this parameter is not passed or setting X = 0, FRR will take + default value: 2 minutes. + .. option:: --enable-numeric-version Alpine Linux does not allow non-numeric characters in the version string. @@ -285,6 +292,7 @@ options from the list below. arguments when reporting the version string in `show version` command. .. option:: --with-pkg-extra-version=VER + Add extra version field, for packagers/distributions .. option:: --with-pkg-git-version diff --git a/doc/user/ldpd.rst b/doc/user/ldpd.rst index a6b3d9d97f..149e851891 100644 --- a/doc/user/ldpd.rst +++ b/doc/user/ldpd.rst @@ -24,7 +24,7 @@ Running Ldpd The *ldpd* daemon can be invoked with any of the common options (:ref:`common-invocation-options`). -..option:: --ctl_socket +.. option:: --ctl_socket This option allows you to override the path to the ldpd.sock file used to control this daemon. If specified this option overrides diff --git a/doc/user/ospf6d.rst b/doc/user/ospf6d.rst index 093c5382cf..624510323c 100644 --- a/doc/user/ospf6d.rst +++ b/doc/user/ospf6d.rst @@ -85,6 +85,11 @@ OSPF6 router change to take effect, user can use this cli instead of restarting the ospf6d daemon. +.. clicmd:: clear ipv6 ospf6 [vrf NAME] interface [IFNAME] + + This command restarts the interface state machine for all interfaces in the + VRF or only for the specific interface if ``IFNAME`` is specified. + ASBR Summarisation Support in OSPFv3 ==================================== @@ -176,7 +181,7 @@ OSPF6 area The `not-advertise` option, when present, prevents the summary route from being advertised, effectively filtering the summarized routes. -.. clicmd:: area A.B.C.D nssa [no-summary] +.. clicmd:: area A.B.C.D nssa [no-summary] [default-information-originate [metric-type (1-2)] [metric (0-16777214)]] .. clicmd:: area (0-4294967295) nssa [no-summary] [default-information-originate [metric-type (1-2)] [metric (0-16777214)]] @@ -204,6 +209,21 @@ OSPF6 area existence of a default route in the RIB that wasn't learned via the OSPF protocol. +.. clicmd:: area A.B.C.D nssa range X:X::X:X/M [<not-advertise|cost (0-16777215)>] + +.. clicmd:: area (0-4294967295) nssa range X:X::X:X/M [<not-advertise|cost (0-16777215)>] + + Summarize a group of external subnets into a single Type-7 LSA, which is + then translated to a Type-5 LSA and avertised to the backbone. + This command can only be used at the area boundary (NSSA ABR router). + + By default, the metric of the summary route is calculated as the highest + metric among the summarized routes. The `cost` option, however, can be used + to set an explicit metric. + + The `not-advertise` option, when present, prevents the summary route from + being advertised, effectively filtering the summarized routes. + .. clicmd:: area A.B.C.D export-list NAME .. clicmd:: area (0-4294967295) export-list NAME diff --git a/doc/user/overview.rst b/doc/user/overview.rst index efe64b72f0..a24e3eb7f2 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -349,6 +349,12 @@ BGP :t:`The Resource Public Key Infrastructure (RPKI) to Router Protocol. R. Bush, R. Austein. January 2013.` - :rfc:`6811` :t:`BGP Prefix Origin Validation. P. Mohapatra, J. Scudder, D. Ward, R. Bush, R. Austein. January 2013.` +- :rfc:`6938` + :t:`Deprecation of BGP Path Attributes: DPA, ADVERTISER, and RCID_PATH / CLUSTER_ID. J. Scudder. May 2013.` +- :rfc:`7196` + :t:`Making Route Flap Damping Usable. C. Pelsser, R. Bush, K. Patel, P. Mohapatra, O. Maennel. May 2014.` +- :rfc:`7300` + :t:`Reservation of Last Autonomous System (AS) Numbers. J. Haas, J. Mitchell. July 2014.` - :rfc:`7313` :t:`Enhanced Route Refresh Capability for BGP-4. K. Patel, E. Chen, B. Venkatachalapathy. July 2014.` - :rfc:`7606` @@ -371,7 +377,10 @@ BGP :t:`Using BGP to Bind MPLS Labels to Address Prefixes. E. Rosen. October 2017` - :rfc:`8654` :t:`Extended Message Support for BGP. R. Bush, K. Patel, D. Ward. October 2019` - +- :rfc:`9003` + :t:`Extended BGP Administrative Shutdown Communication. J. Snijders, J. Heitz, J. Scudder, A. Azimov. January 2021` +- :rfc:`9072` + :t:`Extended Optional Parameters Length for BGP OPEN Message. E. Chen, J. Scudder. July 2021` OSPF ---- diff --git a/doc/user/pathd.rst b/doc/user/pathd.rst index bdbf895299..f0b76f10b7 100644 --- a/doc/user/pathd.rst +++ b/doc/user/pathd.rst @@ -6,11 +6,175 @@ PATH :abbr:`PATH` is a daemon that handles the installation and deletion of Segment Routing (SR) Policies. +Based on MPLS (This means that your OS of choice must support MPLS), +SR add a stack of MPLS labels to ingress packets so these +packets are egress through the desired path. + +.. image:: images/pathd_general.png + +The SR policies and Segment Lists can be configured either locally by means +of vtysh or centralized based on a SDN controller (ODL, Cisco, ...) +communicating using the PCEP protocol (:rfc:`5440`). .. _starting-path: -Starting PATH +Configuration +============= + +Explicit Segment Lists +---------------------- + +This is the simplest way of configuration, no remote PCE is necessary. +In order to create a config that match the graphics used in this documentation, +we will create a segment list (SL) called SL1 with an element for each hop and +that element will be assigned a MPLS label. +Then the SL1 will be used in the policy ``example1``, please note also the +preference as in the case of multiple segment list it will be used with the +criteria of bigger number more preference. +Let see now the final configuration that match the graphics shown above. + + +.. code-block:: frr + + segment-routing + traffic-eng + segment-list SL1 + index 10 mpls label 16001 + index 20 mpls label 16002 + ! + policy color 1 endpoint 192.0.2.4 + name example1 + binding-sid 1111 + candidate-path preference 100 name CP1 explicit segment-list SL1 + + +Explicit Segment Lists and Traffic Engineering Database (TED) +------------------------------------------------------------- + +Sometimes is difficult to know the values of MPLS labels +(adjacency changes,...). +Based on the support of IS-IS or OSPF we can activate TED support what will +allow pathd to resolve MPLS based in different types of segments +(:rfc: `draft-ietf-spring-segment-routing-policy-07`). The supported types are +Type C (prefix and local interface), Type E (prefix and algorithm), +Type F (a pair of IP's). +So the configuration would change to this + +.. code-block:: frr + + segment-routing + traffic-eng + mpls-te on + mpls-te import ospfv2 + segment-list SL1 + index 10 nai prefix 10.1.2.1/32 iface 1 + index 20 nai adjacency 10.1.20.1 10.1.20.2 + ! + policy color 1 endpoint 192.0.2.4 + name example1 + binding-sid 1111 + candidate-path preference 100 name CP1 explicit segment-list SL1 + + +In this case no MPLS are provided but the pathd TED support will resolve the +configuration provided to corresponding MPLS labels. + +.. note:: + Please note the ``mpls-te`` configuration added that activate the TED + support and points to ``ospfv2`` so + the ospfv2 (:ref:`ospf-traffic-engineering`) daemon must be also + running and configure to export TED information. + +.. note:: + It would be the same for isis (:ref:`isis-traffic-engineering`) but in the + moment of writting it's not fully tested. + +Dynamic Segment Lists +--------------------- + +One of the useful options to configure is the creation of policies with +the dynamic option. In this case based on a given endpoint the SL will be +,first calculated, and then sended by means of PCEP protocol by the configured +PCE. + +.. code-block:: frr + + traffic-eng + ! + pcep + ! + pce PCE1 + address ip 192.0.2.10 + ! + pcc + peer PCE1 precedence 10 + ! + policy color 1 endpoint 192.0.2.4 + name example + binding-sid 1111 + candidate-path preference 100 name CP2 dynamic + +.. note:: + Please note the configuration for the remote pce which allows pathd to + connect to the given PCE and act as a PCC (PCEP Client) + +.. note:: + If the TED support feature is active, the data obtained from PCE will + be validated, so in a SL from PCEP/PCE the IP and MPLS will be checked + against local TED obtained and built from the igp configured in that + case. + +.. image:: images/pathd_config.png + +Pce Initiated +------------- + +We can step forward in the use of our controller not only by asking to +calculate paths to an endpoint but also to create the whole policies in the +controller and obtain those by means of the PCEP protocol. + + +.. code-block:: frr + + traffic-eng + ! + pcep + ! + pce PCE1 + address ip 192.0.2.10 + pce-initiated + ! + pce PCE2 + address ip 192.0.2.9 + pce-initiated + ! + pcc + peer PCE1 precedence 10 + peer PCE2 precedence 20 + ! + +.. note:: + Now there is no locally created policies in the config as they will + be obtain from the configured pce. + Please check command :clicmd:`show sr-te policy` in ``vtysh`` to see + the obtained policies. + +.. note:: + Another interesting command is :clicmd:`show mpls table` + to check the installed mpls configuration based in those obtained + policies. + +.. note:: + SR Policies could be a mix of local, remote obtained from PCE and + delegated to a PCE (but while testing Pce Initiated with Cisco PCE, + happens that controller sends PCE initiated delete commands to delete + the locally created configuration related to that PCE). + + +.. image:: images/pathd_initiated_multi.png + +Starting ============= Default configuration file for *pathd* is :file:`pathd.conf`. The typical @@ -24,7 +188,6 @@ present and the :file:`frr.conf` is read instead. :abbr:`PATH` supports all the common FRR daemon start options which are documented elsewhere. - PCEP Support ============ @@ -34,6 +197,11 @@ A pceplib is included in the frr source tree and build by default. To start pathd with pcep support the extra parameter `-M pathd_pcep` should be passed to the pathd daemon. +An example of command line with pcep module could be this + +.. code-block:: frr + + pathd -u root -g root -f pathd.conf -z /tmp/zebra-demo1.sock --vty_socket=/var/run/demo1.vty -i /tmp/pathd-demo1.pid -M frr/modules/pathd_pcep.so --log file:/tmp/kk.txt Pathd Configuration =================== @@ -42,53 +210,53 @@ Example: .. code-block:: frr - debug pathd pcep basic - segment-routing - traffic-eng - mpls-te on - mpls-te import ospfv2 - segment-list SL1 - index 10 mpls label 16010 - index 20 mpls label 16030 - ! - segment-list SL2 - index 10 nai prefix 10.1.2.1/32 iface 1 - index 20 nai adjacency 10.1.20.1 10.1.20.2 - index 30 nai prefix 10.10.10.5/32 algorithm 0 - index 40 mpls label 18001 - ! - policy color 1 endpoint 1.1.1.1 - name default - binding-sid 4000 - candidate-path preference 100 name CP1 explicit segment-list SL1 - candidate-path preference 200 name CP2 dynamic - affinity include-any 0x000000FF - bandwidth 100000 - metric bound msd 16 required - metric te 10 - objective-function mcp required - ! - pcep - pce-config GROUP1 - source-address ip 1.1.1.1 - tcp-md5-auth secret - timer keep-alive 30 + debug pathd pcep basic + segment-routing + traffic-eng + mpls-te on + mpls-te import ospfv2 + segment-list SL1 + index 10 mpls label 16010 + index 20 mpls label 16030 ! - pce PCE1 - config GROUP1 - address ip 10.10.10.10 + segment-list SL2 + index 10 nai prefix 10.1.2.1/32 iface 1 + index 20 nai adjacency 10.1.20.1 10.1.20.2 + index 30 nai prefix 10.10.10.5/32 algorithm 0 + index 40 mpls label 18001 ! - pce PCE2 - config GROUP1 - address ip 9.9.9.9 + policy color 1 endpoint 192.0.2.1 + name default + binding-sid 4000 + candidate-path preference 100 name CP1 explicit segment-list SL1 + candidate-path preference 200 name CP2 dynamic + affinity include-any 0x000000FF + bandwidth 100000 + metric bound msd 16 required + metric te 10 + objective-function mcp required ! - pcc - peer PCE1 precedence 10 - peer PCE2 precedence 20 + pcep + pce-config GROUP1 + source-address 192.0.2.1 + tcp-md5-auth secret + timer keep-alive 30 + ! + pce PCE1 + config GROUP1 + address ip 192.0.2.10 + ! + pce PCE2 + config GROUP1 + address ip 192.0.2.9 + ! + pcc + peer PCE1 precedence 10 + peer PCE2 precedence 20 + ! ! ! ! - ! .. _path-commands: @@ -326,14 +494,14 @@ Introspection Commands Endpoint Color Name BSID Status ------------------------------------------ - 1.1.1.1 1 default 4000 Active + 192.0.2.1 1 default 4000 Active .. code-block:: frr router# show sr-te policy detail - Endpoint: 1.1.1.1 Color: 1 Name: LOW_DELAY BSID: 4000 Status: Active + Endpoint: 192.0.2.1 Color: 1 Name: LOW_DELAY BSID: 4000 Status: Active Preference: 100 Name: cand1 Type: explicit Segment-List: sl1 Protocol-Origin: Local * Preference: 200 Name: cand1 Type: dynamic Segment-List: 32453452 Protocol-Origin: PCEP @@ -384,19 +552,19 @@ learned through BGP using route-maps: set sr-te color 1 ! router bgp 1 - bgp router-id 2.2.2.2 - neighbor 1.1.1.1 remote-as 1 - neighbor 1.1.1.1 update-source lo + bgp router-id 192.0.2.2 + neighbor 192.0.2.1 remote-as 1 + neighbor 192.0.2.1 update-source lo ! address-family ipv4 unicast - neighbor 1.1.1.1 next-hop-self - neighbor 1.1.1.1 route-map SET_SR_POLICY in + neighbor 192.0.2.1 next-hop-self + neighbor 192.0.2.1 route-map SET_SR_POLICY in redistribute static exit-address-family ! ! -In this case, the SR Policy with color `1` and endpoint `1.1.1.1` is selected. +In this case, the SR Policy with color `1` and endpoint `192.0.2.1` is selected. Sample configuration @@ -419,13 +587,13 @@ Sample configuration index 10 mpls label 321 index 20 mpls label 654 ! - policy color 1 endpoint 1.1.1.1 + policy color 1 endpoint 192.0.2.1 name one binding-sid 100 candidate-path preference 100 name test1 explicit segment-list test1 candidate-path preference 200 name test2 explicit segment-list test2 ! - policy color 2 endpoint 2.2.2.2 + policy color 2 endpoint 192.0.2.2 name two binding-sid 101 candidate-path preference 100 name def explicit segment-list test2 diff --git a/doc/user/pbr.rst b/doc/user/pbr.rst index e59ed10896..29567bb709 100644 --- a/doc/user/pbr.rst +++ b/doc/user/pbr.rst @@ -154,6 +154,31 @@ end destination. (ECN) field in the IP header; if this value matches then forward the packet according to the nexthop(s) specified. + +.. clicmd:: set queue-id (1-65535) + + Set the egress port queue identifier for matched packets. The Linux Kernel + provider does not currently support packet mangling, so this field will be + ignored unless another provider is used. + +.. clicmd:: set pcp (0-7) + + Set the 802.1Q priority code point (PCP) for matched packets. A PCP of zero + is the defaul (nominally, "best effort"). The Linux Kernel provider does not + currently support packet mangling, so this field will be ignored unless + another provider is used. + +.. clicmd:: set vlan (1-4094) + + Set the VLAN tag for matched packets. Identifiers 0 and 4095 are reserved. + The Linux Kernel provider does not currently support packet mangling, so + this field will be ignored unless another provider is used. + +.. clicmd:: strip vlan + + Strip inner vlan tags from matched packets. The Linux Kernel provider does not currently support packet mangling, so this field will be ignored unless another provider is used. It is invalid to specify both a `strip` and `set + vlan` action. + .. clicmd:: set nexthop-group NAME Use the nexthop-group NAME as the place to forward packets when the match diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index e1fe4bbbdb..a7f22cd40c 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -144,14 +144,30 @@ Route Map Match Command Matches the specified `prefix-len`. This is a Zebra specific command. +.. clicmd:: match ip next-hop ACCESS_LIST + + Match the next-hop according to the given access-list. + .. clicmd:: match ip next-hop address IPV4_ADDR This is a BGP specific match command. Matches the specified `ipv4_addr`. -.. clicmd:: match ipv6 next-hop IPV6_ADDR +.. clicmd:: match ip next-hop prefix-list PREFIX_LIST + + Match the next-hop according to the given prefix-list. + +.. clicmd:: match ipv6 next-hop ACCESS_LIST + + Match the next-hop according to the given access-list. + +.. clicmd:: match ipv6 next-hop address IPV6_ADDR This is a BGP specific match command. Matches the specified `ipv6_addr`. +.. clicmd:: match ipv6 next-hop prefix-list PREFIX_LIST + + Match the next-hop according to the given prefix-list. + .. clicmd:: match as-path AS_PATH Matches the specified `as_path`. diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index 235df56528..c1308913a4 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -54,6 +54,9 @@ In a nutshell, the current implementation provides the following features Enabling RPKI ------------- +You must install ``frr-rpki-rtrlib`` additional package for RPKI support, +otherwise ``bgpd`` daemon won't startup. + .. clicmd:: rpki This command enables the RPKI configuration mode. Most commands that start @@ -66,8 +69,6 @@ Enabling RPKI to configure at least one reachable cache server. See section :ref:`configuring-rpki-rtr-cache-servers` for configuring a cache server. - -When first installing FRR with RPKI support from the pre-packaged binaries. Remember to add ``-M rpki`` to the variable ``bgpd_options`` in :file:`/etc/frr/daemons` , like so:: diff --git a/doc/user/scripting.rst b/doc/user/scripting.rst index b0295e5706..badc82c500 100644 --- a/doc/user/scripting.rst +++ b/doc/user/scripting.rst @@ -1,22 +1,31 @@ -.. _scripting: +.. _scripting-user: ********* Scripting ********* The behavior of FRR may be extended or customized using its built-in scripting -capabilities. +capabilities. The scripting language is Lua 5.3. This guide assumes Lua +knowledge. For more information on Lua, consult the Lua 5.3 reference manual, or +*Programming in Lua* (note that the free version covers only Lua 5.0). -Some configuration commands accept the name of a Lua script to call to perform -some task or make some decision. These scripts have their environments -populated with some set of inputs, and are expected to populate some set of -output variables, which are read by FRR after the script completes. The names -and expected contents of these scripts are documented alongside the commands -that support them. +https://www.lua.org/manual/5.3/ -These scripts live in :file:`/etc/frr/scripts/` by default. This is -configurable at compile time via ``--with-scriptdir``. It may be -overriden at runtime with the ``--scriptdir`` daemon option. +http://www.lua.org/pil/contents.html + +Scripting +========= + +.. seealso:: Developer docs for scripting + +How to use +---------- + +1. Identify the Lua function name. See :ref:`lua-hook-calls`. + +2. Write the Lua script + +3. Configure FRR to use the Lua script In order to use scripting, FRR must be built with ``--enable-scripting``. @@ -26,3 +35,51 @@ In order to use scripting, FRR must be built with ``--enable-scripting``. contents of a script that is in use without restarting FRR. Not all scripting locations may behave this way; refer to the documentation for the particular location. + + +Example: on_rib_process_dplane_results +-------------------------------------- + +This example shows how to write a Lua script that logs changes when a route is +added. + +First, identify the Lua hook call to attach a Lua function to: this will be the +name of the Lua function. In this case, since the hook call is +`on_rib_process_dplane_results`: + +.. code-block:: lua + + function on_rib_process_dplane_results(ctx) + log.info(ctx.rinfo.zd_dest.network) + return {} + + +The documentation for :ref:`on-rib-process-dplane-results` tells us its +arguments. Here, the destination prefix for a route is being logged out. + +Scripts live in :file:`/etc/frr/scripts/` by default. This is configurable at +compile time via ``--with-scriptdir``. It may be overriden at runtime with the +``--scriptdir`` daemon option. + +The documentation for :ref:`on-rib-process-dplane-results` indicates that the +``script`` command should be used to set the script. Assuming that the above +function was created in :file:`/etc/frr/scripts/my_dplane_script.lua`, the +following vtysh command sets the script for the hook call: + +.. code-block:: console + + script on_rib_process_dplane_results my_dplane_script + + +After the script is set, when the hook call is hit, FRR will look for a +*on_rib_process_dplane_results* function in +:file:`/etc/frr/scripts/my_dplane_script.lua` and run it with the ``ctx`` object +as its argument. + + +.. _lua-hook-calls: + +Available Lua hook calls +======================== + +:ref:`on-rib-process-dplane-results` diff --git a/doc/user/snmptrap.rst b/doc/user/snmptrap.rst index 4bc6d40122..7e306b743d 100644 --- a/doc/user/snmptrap.rst +++ b/doc/user/snmptrap.rst @@ -155,13 +155,13 @@ a siren, have your display flash, etc., be creative ;). error="Cease" case "$suberrorcode" in 01) suberror="Maximum Number of Prefixes Reached" ;; - 02) suberror="Administratively Shutdown" ;; - 03) suberror="Peer Unconfigured" ;; - 04) suberror="Administratively Reset" ;; + 02) suberror="Administrative Shutdown" ;; + 03) suberror="Peer De-configured" ;; + 04) suberror="Administrative Reset" ;; 05) suberror="Connection Rejected" ;; 06) suberror="Other Configuration Change" ;; - 07) suberror="Connection collision resolution" ;; - 08) suberror="Out of Resource" ;; + 07) suberror="Connection Collision Resolution" ;; + 08) suberror="Out of Resources" ;; 09) suberror="MAX" ;; *) suberror="Unknown" ;; esac diff --git a/doc/user/static.rst b/doc/user/static.rst index 200d187370..05847ba394 100644 --- a/doc/user/static.rst +++ b/doc/user/static.rst @@ -33,25 +33,51 @@ Static Route Commands ===================== Static routing is a very fundamental feature of routing technology. It defines -a static prefix and gateway. +a static prefix and gateway, with several possible forms. -.. clicmd:: ip route NETWORK GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME +.. clicmd:: ip route NETWORK GATEWAY [DISTANCE] [table TABLENO] [nexthop-vrf VRFNAME] [vrf VRFNAME] -.. clicmd:: ipv6 route NETWORK from SRCPREFIX GATEWAY table TABLENO nexthop-vrf VRFNAME DISTANCE vrf VRFNAME +.. clicmd:: ip route NETWORK IFNAME [DISTANCE] [table TABLENO] [nexthop-vrf VRFNAME] [vrf VRFNAME] + +.. clicmd:: ip route NETWORK GATEWAY IFNAME [DISTANCE] [onlink] [table TABLENO] [nexthop-vrf VRFNAME] [vrf VRFNAME] + +.. clicmd:: ip route NETWORK (Null0|blackhole|reject) [DISTANCE] [table TABLENO] [nexthop-vrf VRFNAME] [vrf VRFNAME] + +.. clicmd:: ipv6 route NETWORK [from SRCPREFIX] GATEWAY [DISTANCE] [table TABLENO] [nexthop-vrf VRFNAME] [vrf VRFNAME] + +.. clicmd:: ipv6 route NETWORK [from SRCPREFIX] IFNAME [DISTANCE] [table TABLENO] [nexthop-vrf VRFNAME] [vrf VRFNAME] + +.. clicmd:: ipv6 route NETWORK [from SRCPREFIX] GATEWAY IFNAME [DISTANCE] [onlink] [table TABLENO] [nexthop-vrf VRFNAME] [vrf VRFNAME] + +.. clicmd:: ipv6 route NETWORK [from SRCPREFIX] (Null0|blackhole|reject) [DISTANCE] [table TABLENO] [nexthop-vrf VRFNAME] [vrf VRFNAME] NETWORK is destination prefix with a valid v4 or v6 network based upon - initial form of the command. GATEWAY is gateway for the prefix it currently - must match the v4 or v6 route type specified at the start of the command. - GATEWAY can also be treated as an interface name. If the interface name - is ``null0`` then zebra installs a blackhole route. TABLENO - is an optional parameter for namespaces that allows you to create the - route in a specified table associated with the vrf namespace. table will - be rejected if you are not using namespace based vrfs. ``nexthop-vrf`` - allows you to create a leaked route with a nexthop in the specified VRFNAME - vrf VRFNAME allows you to create the route in a specified vrf. - ``nexthop-vrf`` cannot be currently used with namespace based vrfs - currently as well. - The v6 variant allows the installation of a static source-specific route + initial form of the command. + + GATEWAY is the IP address to use as next-hop for the prefix. Currently, it must match + the v4 or v6 route type specified at the start of the command. + + IFNAME is the name of the interface to use as next-hop. If only IFNAME is specified + (without GATEWAY), a connected route will be created. + + When both IFNAME and GATEWAY are specified together, it binds the route to the specified + interface. In this case, it is also possible to specify ``onlink`` to force the kernel + to consider the next-hop as "on link" on the given interface. + + Alternatively, the gateway can be specified as ``Null0`` or ``blackhole`` to create a blackhole + route that drops all traffic. It can also be specified as ``reject`` to create an unreachable + route that rejects traffic with ICMP "Destination Unreachable" messages. + + TABLENO is an optional parameter for namespaces that allows you to create the + route in a specified table associated with the vrf namespace. ``table`` will + be rejected if you are not using namespace based vrfs. + + ``vrf`` VRFNAME allows you to create the route in a specified vrf. + + ``nexthop-vrf`` VRFNAME allows you to create a leaked route with a nexthop in the + specified VRFNAME. ``nexthop-vrf`` cannot be currently used with namespace based vrfs. + + The IPv6 variant allows the installation of a static source-specific route with the SRCPREFIX sub command. These routes are currently supported on Linux operating systems only, and perform AND matching on packet's destination and source addresses in the kernel's forwarding path. Note diff --git a/doc/user/zebra.rst b/doc/user/zebra.rst index 5eb97ff06d..c5440ef88d 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -143,8 +143,8 @@ Standard Commands Configure an IPv4 Point-to-Point address on the interface. (The concept of PtP addressing does not exist for IPv6.) - `local-addr` has no subnet mask since the local side in PtP addressing is - always a single (/32) address. `peer-addr/prefix` can be an arbitrary subnet + ``local-addr`` has no subnet mask since the local side in PtP addressing is + always a single (/32) address. ``peer-addr/prefix`` can be an arbitrary subnet behind the other end of the link (or even on the link in Point-to-Multipoint setups), though generally /32s are used. @@ -157,7 +157,7 @@ Standard Commands .. clicmd:: multicast - Enable or disables multicast flag for the interface. + Enable or disable multicast flag for the interface. .. clicmd:: bandwidth (1-10000000) @@ -171,7 +171,7 @@ Standard Commands .. clicmd:: link-detect - Enable/disable link-detect on platforms which support this. Currently only + Enable or disable link-detect on platforms which support this. Currently only Linux, and only where network interface drivers support reporting link-state via the ``IFF_RUNNING`` flag. @@ -430,7 +430,7 @@ commands in relationship to VRF. Here is an extract of some of those commands: .. clicmd:: show ip route vrf VRF tables - This command will dump the routing tables within the vrf scope. If `vrf all` + This command will dump the routing tables within the vrf scope. If ``vrf all`` is executed, all routing tables will be dumped. .. clicmd:: show <ip|ipv6> route summary [vrf VRF] [table TABLENO] [prefix] @@ -444,7 +444,7 @@ By using the :option:`-n` option, the *Linux network namespace* will be mapped over the *Zebra* VRF. One nice feature that is possible by handling *Linux network namespace* is the ability to name default VRF. At startup, *Zebra* discovers the available *Linux network namespace* by parsing folder -`/var/run/netns`. Each file stands for a *Linux network namespace*, but not all +``/var/run/netns``. Each file stands for a *Linux network namespace*, but not all *Linux network namespaces* are available under that folder. This is the case for default VRF. It is possible to name the default VRF, by creating a file, by executing following commands. @@ -455,19 +455,19 @@ executing following commands. mount --bind /proc/self/ns/net /var/run/netns/vrf0 Above command illustrates what happens when the default VRF is visible under -`var/run/netns/`. Here, the default VRF file is `vrf0`. +``/var/run/netns``. Here, the default VRF file is ``vrf0``. At startup, FRR detects the presence of that file. It detects that the file statistics information matches the same file statistics information as -`/proc/self/ns/net` ( through stat() function). As statistics information -matches, then `vrf0` stands for the new default namespace name. -Consequently, the VRF naming `Default` will be overridden by the new discovered -namespace name `vrf0`. +``/proc/self/ns/net`` ( through stat() function). As statistics information +matches, then ``vrf0`` stands for the new default namespace name. +Consequently, the VRF naming ``Default`` will be overridden by the new discovered +namespace name ``vrf0``. For those who don't use VRF backend with *Linux network namespace*, it is possible to statically configure and recompile FRR. It is possible to choose an alternate name for default VRF. Then, the default VRF naming will automatically be updated with the new name. To illustrate, if you want to recompile with -`global` value, use the following command: +``global`` value, use the following command: .. code-block:: shell @@ -499,7 +499,7 @@ options on compilation if the end operator desires to do so. Individual protocols each have their own way of dictating ECMP policy and their respective documentation should be read. -ECMP can be inspected in zebra by doing a `show ip route X` command. +ECMP can be inspected in zebra by doing a ``show ip route X`` command. .. code-block:: shell @@ -528,11 +528,11 @@ ECMP can be inspected in zebra by doing a `show ip route X` command. * via 192.168.161.15, enp39s0, weight 1, 00:00:02 * via 192.168.161.16, enp39s0, weight 1, 00:00:02 -In this example we have 16 way ecmp for the 4.4.4.4/32 route. The `*` character +In this example we have 16 way ecmp for the 4.4.4.4/32 route. The ``*`` character tells us that the route is installed in the Data Plane, or FIB. If you are using the Linux kernel as a Data Plane, this can be inspected -via a `ip route show X` command: +via a ``ip route show X`` command: .. code-block:: shell @@ -557,7 +557,7 @@ via a `ip route show X` command: Once installed into the FIB, FRR currently has little control over what nexthops are choosen to forward packets on. Currently the Linux kernel -has a `fib_multipath_hash_policy` sysctl which dictates how the hashing +has a ``fib_multipath_hash_policy`` sysctl which dictates how the hashing algorithm is used to forward packets. .. _zebra-mpls: @@ -811,7 +811,7 @@ unicast topology! with the longer prefix length is used; if they're equal, the Multicast RIB takes precedence. - The `mrib-then-urib` setting is the default behavior if nothing is + The ``mrib-then-urib`` setting is the default behavior if nothing is configured. If this is the desired behavior, it should be explicitly configured to make the configuration immune against possible changes in what the default behavior is. @@ -904,8 +904,8 @@ that sets the preferred source address, and applies the route-map to all ip prefix-list ANY permit 0.0.0.0/0 le 32 route-map RM1 permit 10 - match ip address prefix-list ANY - set src 10.0.0.1 + match ip address prefix-list ANY + set src 10.0.0.1 ip protocol rip route-map RM1 @@ -915,8 +915,8 @@ IPv6 example for OSPFv3. ipv6 prefix-list ANY seq 10 permit any route-map RM6 permit 10 - match ipv6 address prefix-list ANY - set src 2001:db8:425:1000::3 + match ipv6 address prefix-list ANY + set src 2001:db8:425:1000::3 ipv6 protocol ospf6 route-map RM6 @@ -951,7 +951,7 @@ latter information makes up the Forwarding Information Base (FIB). Zebra feeds the FIB to the kernel, which allows the IP stack in the kernel to forward packets according to the routes computed by FRR. The kernel FIB is updated in an OS-specific way. For example, -the `Netlink` interface is used on Linux, and route sockets are +the ``Netlink`` interface is used on Linux, and route sockets are used on FreeBSD. The FIB push interface aims to provide a cross-platform mechanism to @@ -1353,6 +1353,15 @@ Optional sysctl settings When ndisc_notify is set to 0, no U-NA is sent. When ndisc_notify is set to 1, a U-NA is sent when the interface comes UP. +Useful sysctl settings +---------------------- + +.. option:: net.ipv6.conf.all.use_oif_addrs_only = 1 + + When enabled, the candidate source addresses for destinations routed via this interface are + restricted to the set of addresses configured on this interface (RFC 6724 section 4). If + an operator has hundreds of IP addresses per interface this solves the latency problem. + Debugging ========= @@ -1416,3 +1425,199 @@ Debugging Nexthop and nexthop-group events. +Scripting +========= + +.. clicmd:: zebra on-rib-process script SCRIPT + + Set a Lua script for :ref:`on-rib-process-dplane-results` hook call. + SCRIPT is the basename of the script, without ``.lua``. + +Data structures +--------------- + +.. _const-struct-zebra-dplane-ctx: + +const struct zebra_dplane_ctx +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. code-block:: console + + * integer zd_op + * integer zd_status + * integer zd_provider + * integer zd_vrf_id + * integer zd_table_id + * integer zd_ifname + * integer zd_ifindex + * table rinfo (if zd_op is DPLANE_OP_ROUTE*, DPLANE_NH_*) + + * prefix zd_dest + * prefix zd_src + * integer zd_afi + * integer zd_safi + * integer zd_type + * integer zd_old_type + * integer zd_tag + * integer zd_old_tag + * integer zd_metric + * integer zd_old_metric + * integer zd_instance + * integer zd_old_instance + * integer zd_distance + * integer zd_old_distance + * integer zd_mtu + * integer zd_nexthop_mtu + * table nhe + + * integer id + * integer old_id + * integer afi + * integer vrf_id + * integer type + * nexthop_group ng + * nh_grp + * integer nh_grp_count + + * integer zd_nhg_id + * nexthop_group zd_ng + * nexthop_group backup_ng + * nexthop_group zd_old_ng + * nexthop_group old_backup_ng + + * integer label (if zd_op is DPLANE_OP_LSP_*) + * table pw (if zd_op is DPLANE_OP_PW_*) + + * integer type + * integer af + * integer status + * integer flags + * integer local_label + * integer remote_label + + * table macinfo (if zd_op is DPLANE_OP_MAC_*) + + * integer vid + * integer br_ifindex + * ethaddr mac + * integer vtep_ip + * integer is_sticky + * integer nhg_id + * integer update_flags + + * table rule (if zd_op is DPLANE_OP_RULE_*) + + * integer sock + * integer unique + * integer seq + * string ifname + * integer priority + * integer old_priority + * integer table + * integer old_table + * integer filter_bm + * integer old_filter_bm + * integer fwmark + * integer old_fwmark + * integer dsfield + * integer old_dsfield + * integer ip_proto + * integer old_ip_proto + * prefix src_ip + * prefix old_src_ip + * prefix dst_ip + * prefix old_dst_ip + + * table iptable (if zd_op is DPLANE_OP_IPTABLE_*) + + * integer sock + * integer vrf_id + * integer unique + * integer type + * integer filter_bm + * integer fwmark + * integer action + * integer pkt_len_min + * integer pkt_len_max + * integer tcp_flags + * integer dscp_value + * integer fragment + * integer protocol + * integer nb_interface + * integer flow_label + * integer family + * string ipset_name + + * table ipset (if zd_op is DPLANE_OP_IPSET_*) + * integer sock + * integer vrf_id + * integer unique + * integer type + * integer family + * string ipset_name + + * table neigh (if zd_op is DPLANE_OP_NEIGH_*) + + * ipaddr ip_addr + * table link + + * ethaddr mac + * ipaddr ip_addr + + * integer flags + * integer state + * integer update_flags + + * table br_port (if zd_op is DPLANE_OP_BR_PORT_UPDATE) + + * integer sph_filter_cnt + * integer flags + * integer backup_nhg_id + + * table neightable (if zd_op is DPLANE_OP_NEIGH_TABLE_UPDATE) + + * integer family + * integer app_probes + * integer ucast_probes + * integer mcast_probes + + * table gre (if zd_op is DPLANE_OP_GRE_SET)** + + * integer link_ifindex + * integer mtu + + +.. _const-struct-nh-grp: + +const struct nh_grp +^^^^^^^^^^^^^^^^^^^ + +.. code-block:: console + + * integer id + * integer weight + + +.. _zebra-hook-calls: + +Zebra Hook calls +---------------- + +.. _on-rib-process-dplane-results: + +on_rib_process_dplane_results +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Called when RIB processes dataplane events. +Set script location with the ``zebra on-rib-process script SCRIPT`` command. + +**Arguments** + +* :ref:`const struct zebra_dplane_ctx<const-struct-zebra-dplane-ctx>` ctx + + +.. code-block:: lua + + function on_rib_process_dplane_results(ctx) + log.info(ctx.rinfo.zd_dest.network) + return {} diff --git a/docker/alpine/build.sh b/docker/alpine/build.sh index 22a36877c0..3132feb9f1 100755 --- a/docker/alpine/build.sh +++ b/docker/alpine/build.sh @@ -6,7 +6,15 @@ set -x ## # Package version needs to be decimal ## -GITREV="$(git rev-parse --short=10 HEAD)" + +## +# Set GITREV=0 or similar in ENV if you want the tag to just be updated to -0 +# everytime for automation usage/scripts/etc locally. +# +# Ex) GITREV=0 ./build.sh +## + +GITREV="${GITREV:=$(git rev-parse --short=10 HEAD)}" PKGVER="$(printf '%u\n' 0x$GITREV)" docker build \ diff --git a/docker/alpine/docker-start b/docker/alpine/docker-start index 698f4f93c9..995cea4119 100755 --- a/docker/alpine/docker-start +++ b/docker/alpine/docker-start @@ -1,4 +1,4 @@ -#!/bin/ash +#!/bin/bash if [ -r "/lib/lsb/init-functions" ]; then . /lib/lsb/init-functions diff --git a/eigrpd/eigrp_cli.c b/eigrpd/eigrp_cli.c index 533d7de2c2..744f5f9c7a 100644 --- a/eigrpd/eigrp_cli.c +++ b/eigrpd/eigrp_cli.c @@ -82,7 +82,7 @@ DEFPY_YANG( return nb_cli_apply_changes_clear_pending(vty, NULL); } -void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_header(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *asn = yang_dnode_get_string(dnode, "./asn"); @@ -94,7 +94,7 @@ void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode) +void eigrp_cli_show_end_header(struct vty *vty, const struct lyd_node *dnode) { vty_out(vty, "exit\n"); vty_out(vty, "!\n"); @@ -128,7 +128,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_router_id(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *router_id = yang_dnode_get_string(dnode, NULL); @@ -157,7 +157,8 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_passive_interface(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_passive_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { const char *ifname = yang_dnode_get_string(dnode, NULL); @@ -200,7 +201,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_active_time(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *timer = yang_dnode_get_string(dnode, NULL); @@ -234,7 +235,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_variance(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *variance = yang_dnode_get_string(dnode, NULL); @@ -269,7 +270,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_maximum_paths(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_maximum_paths(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *maximum_paths = yang_dnode_get_string(dnode, NULL); @@ -333,7 +334,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_metrics(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *k1, *k2, *k3, *k4, *k5, *k6; @@ -379,7 +380,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_network(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *prefix = yang_dnode_get_string(dnode, NULL); @@ -408,8 +409,8 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) +void eigrp_cli_show_neighbor(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) { const char *prefix = yang_dnode_get_string(dnode, NULL); @@ -468,7 +469,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_redistribute(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_redistribute(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *proto = yang_dnode_get_string(dnode, "./protocol"); @@ -520,7 +521,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_delay(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *delay = yang_dnode_get_string(dnode, NULL); @@ -558,7 +559,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_bandwidth(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *bandwidth = yang_dnode_get_string(dnode, NULL); @@ -599,7 +600,8 @@ DEFPY_YANG( } -void eigrp_cli_show_hello_interval(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_hello_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { const char *hello = yang_dnode_get_string(dnode, NULL); @@ -639,7 +641,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_hold_time(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *holdtime = yang_dnode_get_string(dnode, NULL); @@ -701,10 +703,12 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_summarize_address(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_summarize_address(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { - const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance"); + const struct lyd_node *instance = + yang_dnode_get_parent(dnode, "instance"); uint16_t asn = yang_dnode_get_uint16(instance, "./asn"); const char *summarize_address = yang_dnode_get_string(dnode, NULL); @@ -765,10 +769,12 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_authentication(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_authentication(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { - const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance"); + const struct lyd_node *instance = + yang_dnode_get_parent(dnode, "instance"); uint16_t asn = yang_dnode_get_uint16(instance, "./asn"); const char *crypt = yang_dnode_get_string(dnode, NULL); @@ -824,10 +830,11 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode, +void eigrp_cli_show_keychain(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { - const struct lyd_node *instance = yang_dnode_get_parent(dnode, "instance"); + const struct lyd_node *instance = + yang_dnode_get_parent(dnode, "instance"); uint16_t asn = yang_dnode_get_uint16(instance, "./asn"); const char *keychain = yang_dnode_get_string(dnode, NULL); @@ -850,7 +857,7 @@ static struct cmd_node eigrp_node = { static int eigrp_config_write(struct vty *vty) { - struct lyd_node *dnode; + const struct lyd_node *dnode; int written = 0; dnode = yang_dnode_get(running_config->dnode, "/frr-eigrpd:eigrpd"); @@ -862,30 +869,6 @@ static int eigrp_config_write(struct vty *vty) return written; } -static int eigrp_write_interface(struct vty *vty) -{ - struct lyd_node *dnode; - struct interface *ifp; - struct vrf *vrf; - int written = 0; - - RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { - FOR_ALL_INTERFACES(vrf, ifp) { - dnode = yang_dnode_getf( - running_config->dnode, - "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifp->name, vrf->name); - if (dnode == NULL) - continue; - - written = 1; - nb_cli_show_dnode_cmds(vty, dnode, false); - } - } - - return written; -} - void eigrp_cli_init(void) { @@ -912,7 +895,7 @@ eigrp_cli_init(void) vrf_cmd_init(NULL); - if_cmd_init(eigrp_write_interface); + if_cmd_init_default(); install_element(INTERFACE_NODE, &eigrp_if_delay_cmd); install_element(INTERFACE_NODE, &no_eigrp_if_delay_cmd); diff --git a/eigrpd/eigrp_cli.h b/eigrpd/eigrp_cli.h index c5f2fd8009..8b16dea39a 100644 --- a/eigrpd/eigrp_cli.h +++ b/eigrpd/eigrp_cli.h @@ -25,45 +25,56 @@ #define _EIGRP_CLI_H_ /*Prototypes*/ -extern void eigrp_cli_show_header(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_header(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_end_header(struct vty *vty, struct lyd_node *dnode); -extern void eigrp_cli_show_router_id(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_end_header(struct vty *vty, + const struct lyd_node *dnode); +extern void eigrp_cli_show_router_id(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); extern void eigrp_cli_show_passive_interface(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_active_time(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_active_time(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_variance(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_variance(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); extern void eigrp_cli_show_maximum_paths(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_metrics(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_metrics(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_network(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_network(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_neighbor(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_neighbor(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_redistribute(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_redistribute(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_delay(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_delay(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_bandwidth(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_bandwidth(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); extern void eigrp_cli_show_hello_interval(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_hold_time(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_hold_time(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); extern void eigrp_cli_show_summarize_address(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); extern void eigrp_cli_show_authentication(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); -extern void eigrp_cli_show_keychain(struct vty *vty, struct lyd_node *dnode, +extern void eigrp_cli_show_keychain(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); extern void eigrp_cli_init(void); diff --git a/eigrpd/eigrp_filter.c b/eigrpd/eigrp_filter.c index bb0cf51bd8..69c0d22aea 100644 --- a/eigrpd/eigrp_filter.c +++ b/eigrpd/eigrp_filter.c @@ -215,7 +215,7 @@ void eigrp_distribute_update_interface(struct interface *ifp) struct distribute *dist; struct eigrp *eigrp; - eigrp = eigrp_lookup(ifp->vrf_id); + eigrp = eigrp_lookup(ifp->vrf->vrf_id); if (!eigrp) return; dist = distribute_lookup(eigrp->distribute_ctx, ifp->name); diff --git a/eigrpd/eigrp_main.c b/eigrpd/eigrp_main.c index 9acb517d8c..9dd795f0b0 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -120,7 +120,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t eigrp_signals[] = { +struct frr_signal_t eigrp_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/eigrpd/eigrp_network.c b/eigrpd/eigrp_network.c index 9a5fbc52b4..6b3a0afc12 100644 --- a/eigrpd/eigrp_network.c +++ b/eigrpd/eigrp_network.c @@ -288,7 +288,7 @@ void eigrp_if_update(struct interface *ifp) * we need to check eac one and add the interface as approperate */ for (ALL_LIST_ELEMENTS(eigrp_om->eigrp, node, nnode, eigrp)) { - if (ifp->vrf_id != eigrp->vrf_id) + if (ifp->vrf->vrf_id != eigrp->vrf_id) continue; /* EIGRP must be on and Router-ID must be configured. */ diff --git a/eigrpd/eigrp_northbound.c b/eigrpd/eigrp_northbound.c index 3ad711164b..a0f8452c94 100644 --- a/eigrpd/eigrp_northbound.c +++ b/eigrpd/eigrp_northbound.c @@ -1135,7 +1135,7 @@ static int lib_interface_eigrp_instance_create(struct nb_cb_create_args *args) } eigrp = eigrp_get(yang_dnode_get_uint16(args->dnode, "./asn"), - ifp->vrf_id); + ifp->vrf->vrf_id); eif = eigrp_interface_lookup(eigrp, ifp->name); if (eif == NULL) return NB_ERR_INCONSISTENCY; @@ -1147,7 +1147,7 @@ static int lib_interface_eigrp_instance_create(struct nb_cb_create_args *args) case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); eigrp = eigrp_get(yang_dnode_get_uint16(args->dnode, "./asn"), - ifp->vrf_id); + ifp->vrf->vrf_id); eif = eigrp_interface_lookup(eigrp, ifp->name); if (eif == NULL) return NB_ERR_INCONSISTENCY; diff --git a/eigrpd/eigrp_routemap.c b/eigrpd/eigrp_routemap.c index 90913a5b28..d9b500a8fd 100644 --- a/eigrpd/eigrp_routemap.c +++ b/eigrpd/eigrp_routemap.c @@ -858,12 +858,10 @@ ALIAS(no_match_interface, no_match_interface_val_cmd, "no match interface WORD", DEFUN (match_ip_next_hop, match_ip_next_hop_cmd, - "match ip next-hop ((1-199)|(1300-2699)|WORD)", + "match ip next-hop ACCESSLIST4_NAME", MATCH_STR IP_STR "Match next-hop address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n") { return eigrp_route_match_add(vty, vty->index, "ip next-hop", argv[0]); @@ -886,15 +884,13 @@ DEFUN (no_match_ip_next_hop, } ALIAS(no_match_ip_next_hop, no_match_ip_next_hop_val_cmd, - "no match ip next-hop ((1-199)|(1300-2699)|WORD)", NO_STR MATCH_STR IP_STR + "no match ip next-hop ACCESSLIST4_NAME", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFUN (match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, - "match ip next-hop prefix-list WORD", + "match ip next-hop prefix-list PREFIXLIST_NAME", MATCH_STR IP_STR "Match next-hop address of route\n" @@ -924,19 +920,17 @@ DEFUN (no_match_ip_next_hop_prefix_list, ALIAS(no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_val_cmd, - "no match ip next-hop prefix-list WORD", NO_STR MATCH_STR IP_STR + "no match ip next-hop prefix-list PREFIXLIST_NAME", NO_STR MATCH_STR IP_STR "Match next-hop address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") DEFUN (match_ip_address, match_ip_address_cmd, - "match ip address ((1-199)|(1300-2699)|WORD)", + "match ip address ACCESSLIST4_NAME", MATCH_STR IP_STR "Match address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n") { return eigrp_route_match_add(vty, vty->index, "ip address", argv[0]); @@ -958,15 +952,13 @@ DEFUN (no_match_ip_address, } ALIAS(no_match_ip_address, no_match_ip_address_val_cmd, - "no match ip address ((1-199)|(1300-2699)|WORD)", NO_STR MATCH_STR IP_STR + "no match ip address ACCESSLIST4_NAME", NO_STR MATCH_STR IP_STR "Match address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n") DEFUN (match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, - "match ip address prefix-list WORD", + "match ip address prefix-list PREFIXLIST_NAME", MATCH_STR IP_STR "Match address of route\n" @@ -995,7 +987,7 @@ DEFUN (no_match_ip_address_prefix_list, } ALIAS(no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_val_cmd, - "no match ip address prefix-list WORD", NO_STR MATCH_STR IP_STR + "no match ip address prefix-list PREFIXLIST_NAME", NO_STR MATCH_STR IP_STR "Match address of route\n" "Match entries of prefix-lists\n" "IP prefix-list name\n") @@ -1132,7 +1124,7 @@ ALIAS(no_set_tag, no_set_tag_val_cmd, "no set tag (0-65535)", NO_STR SET_STR DEFUN (eigrp_distribute_list, eigrp_distribute_list_cmd, - "distribute-list [prefix] WORD <in|out> [WORD]", + "distribute-list [prefix] ACCESSLIST_NAME <in|out> [WORD]", "Filter networks in routing updates\n" "Specify a prefix\n" "Access-list name\n" @@ -1152,7 +1144,7 @@ DEFUN (eigrp_distribute_list, DEFUN (eigrp_no_distribute_list, eigrp_no_distribute_list_cmd, - "no distribute-list [prefix] WORD <in|out> [WORD]", + "no distribute-list [prefix] ACCESSLIST_NAME <in|out> [WORD]", NO_STR "Filter networks in routing updates\n" "Specify a prefix\n" diff --git a/eigrpd/eigrp_zebra.c b/eigrpd/eigrp_zebra.c index 7c765248c6..89dd5be272 100644 --- a/eigrpd/eigrp_zebra.c +++ b/eigrpd/eigrp_zebra.c @@ -102,20 +102,24 @@ static void eigrp_zebra_connected(struct zclient *zclient) zclient_send_reg_requests(zclient, VRF_DEFAULT); } +static zclient_handler *const eigrp_handlers[] = { + [ZEBRA_ROUTER_ID_UPDATE] = eigrp_router_id_update_zebra, + [ZEBRA_INTERFACE_ADDRESS_ADD] = eigrp_interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = eigrp_interface_address_delete, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = eigrp_zebra_read_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = eigrp_zebra_read_route, + [ZEBRA_ROUTE_NOTIFY_OWNER] = eigrp_zebra_route_notify_owner, +}; + void eigrp_zebra_init(void) { struct zclient_options opt = {.receive_notify = false}; - zclient = zclient_new(master, &opt); + zclient = zclient_new(master, &opt, eigrp_handlers, + array_size(eigrp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_EIGRP, 0, &eigrpd_privs); zclient->zebra_connected = eigrp_zebra_connected; - zclient->router_id_update = eigrp_router_id_update_zebra; - zclient->interface_address_add = eigrp_interface_address_add; - zclient->interface_address_delete = eigrp_interface_address_delete; - zclient->redistribute_route_add = eigrp_zebra_read_route; - zclient->redistribute_route_del = eigrp_zebra_read_route; - zclient->route_notify_owner = eigrp_zebra_route_notify_owner; } diff --git a/eigrpd/subdir.am b/eigrpd/subdir.am index 82873a4960..3b647e060b 100644 --- a/eigrpd/subdir.am +++ b/eigrpd/subdir.am @@ -3,7 +3,6 @@ # if EIGRPD -noinst_LIBRARIES += eigrpd/libeigrp.a sbin_PROGRAMS += eigrpd/eigrpd vtysh_scan += \ eigrpd/eigrp_cli.c \ @@ -15,7 +14,7 @@ vtysh_daemons += eigrpd man8 += $(MANBUILD)/frr-eigrpd.8 endif -eigrpd_libeigrp_a_SOURCES = \ +eigrpd_eigrpd_SOURCES = \ eigrpd/eigrp_cli.c \ eigrpd/eigrp_dump.c \ eigrpd/eigrp_errors.c \ @@ -23,6 +22,7 @@ eigrpd_libeigrp_a_SOURCES = \ eigrpd/eigrp_fsm.c \ eigrpd/eigrp_hello.c \ eigrpd/eigrp_interface.c \ + eigrpd/eigrp_main.c \ eigrpd/eigrp_metric.c \ eigrpd/eigrp_neighbor.c \ eigrpd/eigrp_network.c \ @@ -78,5 +78,4 @@ nodist_eigrpd_eigrpd_SOURCES = \ yang/frr-eigrpd.yang.c \ # end -eigrpd_eigrpd_SOURCES = eigrpd/eigrp_main.c -eigrpd_eigrpd_LDADD = eigrpd/libeigrp.a lib/libfrr.la $(LIBCAP) +eigrpd_eigrpd_LDADD = lib/libfrr.la $(LIBCAP) diff --git a/gdb/lib.txt b/gdb/lib.txt index 60a004e1e1..913b455ed1 100644 --- a/gdb/lib.txt +++ b/gdb/lib.txt @@ -1,6 +1,6 @@ # GDB macros for use with Quagga. # -# Macros in this file are not daemon specific. E.g., OS or Quagga library +# Macros in this file are not daemon specific. E.g., OS or FRR library # APIs. # # The macro file can be loaded with 'source <filename>'. They can then be @@ -9,7 +9,7 @@ # # E.g.: # -# (gdb) source ~paul/code/quagga/gdb/lib.txt +# (gdb) source ~paul/code/frr/gdb/lib.txt # (gdb) break bgp_packet.c:613 # Breakpoint 3 at 0x7fa883033a32: file bgp_packet.c, line 613. # (gdb) cont diff --git a/include/linux/nexthop.h b/include/linux/nexthop.h index ee2a15b9c7..d8ffa8c9ca 100644 --- a/include/linux/nexthop.h +++ b/include/linux/nexthop.h @@ -1,12 +1,9 @@ /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ -#ifndef _LINUX_NEXTHOP_H -#define _LINUX_NEXTHOP_H +#ifndef _UAPI_LINUX_NEXTHOP_H +#define _UAPI_LINUX_NEXTHOP_H #include <linux/types.h> -#define RTM_NHA(h) ((struct rtattr *)(((char *)(h)) + \ - NLMSG_ALIGN(sizeof(struct nhmsg)))) - struct nhmsg { unsigned char nh_family; unsigned char nh_scope; /* return only */ @@ -15,6 +12,7 @@ struct nhmsg { unsigned int nh_flags; /* RTNH_F flags */ }; +/* entry in a nexthop group */ struct nexthop_grp { __u32 id; /* nexthop id - must exist */ __u8 weight; /* weight of this nexthop */ @@ -23,7 +21,10 @@ struct nexthop_grp { }; enum { - NEXTHOP_GRP_TYPE_MPATH, /* default type if not specified */ + NEXTHOP_GRP_TYPE_MPATH, /* hash-threshold nexthop group + * default type if not specified + */ + NEXTHOP_GRP_TYPE_RES, /* resilient nexthop group */ __NEXTHOP_GRP_TYPE_MAX, }; @@ -50,10 +51,54 @@ enum { */ NHA_GROUPS, /* flag; only return nexthop groups in dump */ NHA_MASTER, /* u32; only return nexthops with given master dev */ - NHA_FDB, /* nexthop belongs to a bridge fdb */ + + NHA_FDB, /* flag; nexthop belongs to a bridge fdb */ + /* if NHA_FDB is added, OIF, BLACKHOLE, ENCAP cannot be set */ + + /* nested; resilient nexthop group attributes */ + NHA_RES_GROUP, + /* nested; nexthop bucket attributes */ + NHA_RES_BUCKET, __NHA_MAX, }; #define NHA_MAX (__NHA_MAX - 1) + +enum { + NHA_RES_GROUP_UNSPEC, + /* Pad attribute for 64-bit alignment. */ + NHA_RES_GROUP_PAD = NHA_RES_GROUP_UNSPEC, + + /* u16; number of nexthop buckets in a resilient nexthop group */ + NHA_RES_GROUP_BUCKETS, + /* clock_t as u32; nexthop bucket idle timer (per-group) */ + NHA_RES_GROUP_IDLE_TIMER, + /* clock_t as u32; nexthop unbalanced timer */ + NHA_RES_GROUP_UNBALANCED_TIMER, + /* clock_t as u64; nexthop unbalanced time */ + NHA_RES_GROUP_UNBALANCED_TIME, + + __NHA_RES_GROUP_MAX, +}; + +#define NHA_RES_GROUP_MAX (__NHA_RES_GROUP_MAX - 1) + +enum { + NHA_RES_BUCKET_UNSPEC, + /* Pad attribute for 64-bit alignment. */ + NHA_RES_BUCKET_PAD = NHA_RES_BUCKET_UNSPEC, + + /* u16; nexthop bucket index */ + NHA_RES_BUCKET_INDEX, + /* clock_t as u64; nexthop bucket idle time */ + NHA_RES_BUCKET_IDLE_TIME, + /* u32; nexthop id assigned to the nexthop bucket */ + NHA_RES_BUCKET_NH_ID, + + __NHA_RES_BUCKET_MAX, +}; + +#define NHA_RES_BUCKET_MAX (__NHA_RES_BUCKET_MAX - 1) + #endif diff --git a/isisd/fabricd.c b/isisd/fabricd.c index 0f10a1516a..2937df992c 100644 --- a/isisd/fabricd.c +++ b/isisd/fabricd.c @@ -258,7 +258,6 @@ static int fabricd_initial_sync_timeout(struct thread *thread) f->initial_sync_circuit->interface->name); f->initial_sync_state = FABRICD_SYNC_PENDING; f->initial_sync_circuit = NULL; - f->initial_sync_timeout = NULL; return 0; } @@ -403,7 +402,6 @@ static uint8_t fabricd_calculate_fabric_tier(struct isis_area *area) static int fabricd_tier_set_timer(struct thread *thread) { struct fabricd *f = THREAD_ARG(thread); - f->tier_set_timer = NULL; fabricd_set_tier(f, f->tier_pending); return 0; diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index ffda0f8643..9529adb09a 100644 --- a/isisd/isis_adjacency.c +++ b/isisd/isis_adjacency.c @@ -327,15 +327,18 @@ void isis_adj_state_change(struct isis_adjacency **padj, adj->flaps++; } else if (old_state == ISIS_ADJ_UP) { circuit->adj_state_changes++; - listnode_delete(circuit->u.bc.adjdb[level - 1], - adj); circuit->upadjcount[level - 1]--; if (circuit->upadjcount[level - 1] == 0) isis_tx_queue_clean(circuit->tx_queue); - if (new_state == ISIS_ADJ_DOWN) + if (new_state == ISIS_ADJ_DOWN) { + listnode_delete( + circuit->u.bc.adjdb[level - 1], + adj); + del = true; + } } if (circuit->u.bc.lan_neighs[level - 1]) { @@ -374,14 +377,17 @@ void isis_adj_state_change(struct isis_adjacency **padj, &circuit->t_send_csnp[1]); } } else if (old_state == ISIS_ADJ_UP) { - if (adj->circuit->u.p2p.neighbor == adj) - adj->circuit->u.p2p.neighbor = NULL; circuit->upadjcount[level - 1]--; if (circuit->upadjcount[level - 1] == 0) isis_tx_queue_clean(circuit->tx_queue); - if (new_state == ISIS_ADJ_DOWN) + if (new_state == ISIS_ADJ_DOWN) { + if (adj->circuit->u.p2p.neighbor == adj) + adj->circuit->u.p2p.neighbor = + NULL; + del = true; + } } } } @@ -480,8 +486,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, vty_out(vty, "%-13s", adj_state2string(adj->adj_state)); now = time(NULL); if (adj->last_upd) { - if (adj->last_upd + adj->hold_time - < (unsigned long long)now) + if (adj->last_upd + adj->hold_time < now) vty_out(vty, " Expiring"); else vty_out(vty, " %-9llu", @@ -508,8 +513,7 @@ void isis_adj_print_vty(struct isis_adjacency *adj, struct vty *vty, vty_out(vty, ", State: %s", adj_state2string(adj->adj_state)); now = time(NULL); if (adj->last_upd) { - if (adj->last_upd + adj->hold_time - < (unsigned long long)now) + if (adj->last_upd + adj->hold_time < now) vty_out(vty, " Expiring"); else vty_out(vty, ", Expires in %s", diff --git a/isisd/isis_adjacency.h b/isisd/isis_adjacency.h index b7fab7ae1e..4aa553e303 100644 --- a/isisd/isis_adjacency.h +++ b/isisd/isis_adjacency.h @@ -96,8 +96,8 @@ struct isis_adjacency { int level; /* level (1 or 2) */ enum isis_system_type sys_type; /* neighbourSystemType */ uint16_t hold_time; /* entryRemainingTime */ - uint32_t last_upd; - uint32_t last_flap; /* last time the adj flapped */ + time_t last_upd; + time_t last_flap; /* last time the adj flapped */ enum isis_threeway_state threeway_state; uint32_t ext_circuit_id; int flaps; /* number of adjacency flaps */ diff --git a/isisd/isis_bfd.c b/isisd/isis_bfd.c index 7510e310f7..a7548e2f13 100644 --- a/isisd/isis_bfd.c +++ b/isisd/isis_bfd.c @@ -132,7 +132,8 @@ static void bfd_handle_adj_up(struct isis_adjacency *adj) bfd_sess_set_ipv6_addrs(adj->bfd_session, &src_ip.ipv6, &dst_ip.ipv6); bfd_sess_set_interface(adj->bfd_session, adj->circuit->interface->name); - bfd_sess_set_vrf(adj->bfd_session, adj->circuit->interface->vrf_id); + bfd_sess_set_vrf(adj->bfd_session, + adj->circuit->interface->vrf->vrf_id); bfd_sess_set_profile(adj->bfd_session, circuit->bfd_config.profile); bfd_sess_install(adj->bfd_session); return; diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 6f4a91be67..a91bbd0b95 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -82,7 +82,7 @@ static void isis_circuit_enable(struct isis_circuit *circuit) struct interface *ifp = circuit->interface; if (!area) { - area = isis_area_lookup(circuit->tag, ifp->vrf_id); + area = isis_area_lookup(circuit->tag, ifp->vrf->vrf_id); if (area) isis_area_add_circuit(area, circuit); } @@ -116,7 +116,7 @@ struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag) * Default values */ #ifndef FABRICD - circuit->is_type = yang_get_default_enum( + circuit->is_type_config = yang_get_default_enum( "/frr-interface:lib/interface/frr-isisd:isis/circuit-type"); circuit->flags = 0; @@ -156,7 +156,7 @@ struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag) circuit->level_arg[i].circuit = circuit; } #else - circuit->is_type = IS_LEVEL_1_AND_2; + circuit->is_type_config = IS_LEVEL_1_AND_2; circuit->flags = 0; circuit->pad_hellos = 1; for (i = 0; i < 2; i++) { @@ -172,6 +172,8 @@ struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag) } #endif /* ifndef FABRICD */ + circuit->is_type = circuit->is_type_config; + circuit_mt_init(circuit); isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL1); isis_lfa_excluded_ifaces_init(circuit, ISIS_LEVEL2); @@ -253,6 +255,10 @@ void isis_circuit_deconfigure(struct isis_circuit *circuit, /* Free the index of SRM and SSN flags */ flags_free_index(&area->flags, circuit->idx); circuit->idx = 0; + + /* Reset IS type to configured */ + circuit->is_type = circuit->is_type_config; + /* Remove circuit from area */ assert(circuit->area == area); listnode_delete(area->circuit_list, circuit); @@ -262,24 +268,6 @@ void isis_circuit_deconfigure(struct isis_circuit *circuit, return; } -struct isis_circuit *circuit_lookup_by_ifp(struct interface *ifp, - struct list *list) -{ - struct isis_circuit *circuit = NULL; - struct listnode *node; - - if (!list) - return NULL; - - for (ALL_LIST_ELEMENTS_RO(list, node, circuit)) - if (circuit->interface == ifp) { - assert(ifp->info == circuit); - return circuit; - } - - return NULL; -} - struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp) { return (struct isis_circuit *)ifp->info; @@ -499,7 +487,7 @@ void isis_circuit_if_add(struct isis_circuit *circuit, struct interface *ifp) circuit->circ_type = CIRCUIT_T_BROADCAST; } else if (if_is_pointopoint(ifp)) { circuit->circ_type = CIRCUIT_T_P2P; - } else if (if_is_loopback_or_vrf(ifp)) { + } else if (if_is_loopback(ifp)) { circuit->circ_type = CIRCUIT_T_LOOPBACK; circuit->is_passive = 1; } else { @@ -1067,17 +1055,9 @@ static int isis_interface_config_write(struct vty *vty) { struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); int write = 0; - struct listnode *node; struct interface *ifp; - struct isis_area *area; struct isis_circuit *circuit; int i; - struct isis *isis = NULL; - - isis = isis_lookup_by_vrfid(vrf->vrf_id); - - if (isis == NULL) - return 0; FOR_ALL_INTERFACES (vrf, ifp) { /* IF name */ @@ -1089,14 +1069,13 @@ static int isis_interface_config_write(struct vty *vty) write++; } /* ISIS Circuit */ - for (ALL_LIST_ELEMENTS_RO(isis->area_list, node, area)) { - circuit = - circuit_lookup_by_ifp(ifp, area->circuit_list); + do { + circuit = circuit_scan_by_ifp(ifp); if (circuit == NULL) - continue; + break; if (circuit->ip_router) { vty_out(vty, " ip router " PROTO_NAME " %s\n", - area->area_tag); + circuit->tag); write++; } if (circuit->is_passive) { @@ -1109,7 +1088,7 @@ static int isis_interface_config_write(struct vty *vty) } if (circuit->ipv6_router) { vty_out(vty, " ipv6 router " PROTO_NAME " %s\n", - area->area_tag); + circuit->tag); write++; } @@ -1289,36 +1268,12 @@ static int isis_interface_config_write(struct vty *vty) } write += hook_call(isis_circuit_config_write, circuit, vty); - } + } while (0); vty_endframe(vty, "exit\n!\n"); } return write; } -#else -static int isis_interface_config_write(struct vty *vty) -{ - struct vrf *vrf = NULL; - int write = 0; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct interface *ifp; - - FOR_ALL_INTERFACES (vrf, ifp) { - struct lyd_node *dnode; - dnode = yang_dnode_getf( - running_config->dnode, - "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifp->name, vrf->name); - if (dnode == NULL) - continue; - - write++; - nb_cli_show_dnode_cmds(vty, dnode, false); - } - } - return write; -} #endif /* ifdef FABRICD */ void isis_circuit_af_set(struct isis_circuit *circuit, bool ip_router, @@ -1350,7 +1305,7 @@ ferr_r isis_circuit_passive_set(struct isis_circuit *circuit, bool passive) if (circuit->is_passive == passive) return ferr_ok(); - if (if_is_loopback_or_vrf(circuit->interface) && !passive) + if (if_is_loopback(circuit->interface) && !passive) return ferr_cfg_invalid("loopback is always passive"); if (circuit->state != C_STATE_UP) { @@ -1529,7 +1484,11 @@ void isis_circuit_init(void) hook_register_prio(if_del, 0, isis_if_delete_hook); /* Install interface node */ +#ifdef FABRICD if_cmd_init(isis_interface_config_write); +#else + if_cmd_init_default(); +#endif if_zapi_callbacks(isis_ifp_create, isis_ifp_up, isis_ifp_down, isis_ifp_destroy); } diff --git a/isisd/isis_circuit.h b/isisd/isis_circuit.h index e7b7a2434d..7465780848 100644 --- a/isisd/isis_circuit.h +++ b/isisd/isis_circuit.h @@ -122,6 +122,7 @@ struct isis_circuit { */ char *tag; /* area tag */ struct isis_passwd passwd; /* Circuit rx/tx password */ + int is_type_config; /* configured circuit is type */ int is_type; /* circuit is type == level of circuit * differentiated from circuit type (media) */ uint32_t hello_interval[ISIS_LEVELS]; /* hello-interval in seconds */ @@ -185,8 +186,6 @@ DECLARE_QOBJ_TYPE(isis_circuit); void isis_circuit_init(void); struct isis_circuit *isis_circuit_new(struct interface *ifp, const char *tag); void isis_circuit_del(struct isis_circuit *circuit); -struct isis_circuit *circuit_lookup_by_ifp(struct interface *ifp, - struct list *list); struct isis_circuit *circuit_scan_by_ifp(struct interface *ifp); void isis_circuit_configure(struct isis_circuit *circuit, struct isis_area *area); diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index f48b142b1a..21162045ad 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -70,43 +70,12 @@ DEFPY_YANG_NOSH(router_isis, router_isis_cmd, return ret; } -struct if_iter { - struct vty *vty; - const char *tag; -}; - -static int if_iter_cb(const struct lyd_node *dnode, void *arg) -{ - struct if_iter *iter = arg; - const char *tag; - - if (!yang_dnode_exists(dnode, "frr-isisd:isis/area-tag")) - return YANG_ITER_CONTINUE; - - tag = yang_dnode_get_string(dnode, "frr-isisd:isis/area-tag"); - if (strmatch(tag, iter->tag)) { - char xpath[XPATH_MAXLEN]; - const char *name = yang_dnode_get_string(dnode, "name"); - const char *vrf = yang_dnode_get_string(dnode, "vrf"); - - snprintf( - xpath, XPATH_MAXLEN, - "/frr-interface:lib/interface[name='%s'][vrf='%s']/frr-isisd:isis", - name, vrf); - nb_cli_enqueue_change(iter->vty, xpath, NB_OP_DESTROY, NULL); - } - - return YANG_ITER_CONTINUE; -} - DEFPY_YANG(no_router_isis, no_router_isis_cmd, "no router isis WORD$tag [vrf NAME$vrf_name]", NO_STR ROUTER_STR "ISO IS-IS\n" "ISO Routing area tag\n" VRF_CMD_HELP_STR) { - struct if_iter iter; - if (!vrf_name) vrf_name = VRF_DEFAULT_NAME; @@ -118,12 +87,6 @@ DEFPY_YANG(no_router_isis, no_router_isis_cmd, return CMD_ERR_NOTHING_TODO; } - iter.vty = vty; - iter.tag = tag; - - yang_dnode_iterate(if_iter_cb, &iter, vty->candidate_config->dnode, - "/frr-interface:lib/interface[vrf='%s']", vrf_name); - nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes_clear_pending( @@ -131,7 +94,7 @@ DEFPY_YANG(no_router_isis, no_router_isis_cmd, vrf_name); } -void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode, +void cli_show_router_isis(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrf = NULL; @@ -146,7 +109,7 @@ void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void cli_show_router_isis_end(struct vty *vty, struct lyd_node *dnode) +void cli_show_router_isis_end(struct vty *vty, const struct lyd_node *dnode) { vty_out(vty, "exit\n"); } @@ -164,45 +127,11 @@ DEFPY_YANG(ip_router_isis, ip_router_isis_cmd, "IS-IS routing protocol\n" "Routing process tag\n") { - char inst_xpath[XPATH_MAXLEN]; - struct lyd_node *if_dnode, *inst_dnode; - const char *circ_type = NULL; - const char *vrf_name; - struct interface *ifp; - - if_dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!if_dnode) { - vty_out(vty, "%% Failed to get iface dnode in candidate DB\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - vrf_name = yang_dnode_get_string(if_dnode, "vrf"); - - snprintf(inst_xpath, XPATH_MAXLEN, - "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag, - vrf_name); - - /* if instance exists then inherit its type, create it otherwise */ - inst_dnode = yang_dnode_get(vty->candidate_config->dnode, inst_xpath); - if (inst_dnode) - circ_type = yang_dnode_get_string(inst_dnode, "is-type"); - else - nb_cli_enqueue_change(vty, inst_xpath, NB_OP_CREATE, NULL); - nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", NB_OP_MODIFY, tag); nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv4-routing", NB_OP_MODIFY, "true"); - if (circ_type) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", - NB_OP_MODIFY, circ_type); - - /* check if the interface is a loopback and if so set it as passive */ - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (ifp && if_is_loopback_or_vrf(ifp)) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", - NB_OP_MODIFY, "true"); return nb_cli_apply_changes(vty, NULL); } @@ -221,45 +150,11 @@ DEFPY_YANG(ip6_router_isis, ip6_router_isis_cmd, "IS-IS routing protocol\n" "Routing process tag\n") { - char inst_xpath[XPATH_MAXLEN]; - struct lyd_node *if_dnode, *inst_dnode; - const char *circ_type = NULL; - const char *vrf_name; - struct interface *ifp; - - if_dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!if_dnode) { - vty_out(vty, "%% Failed to get iface dnode in candidate DB\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - vrf_name = yang_dnode_get_string(if_dnode, "vrf"); - - snprintf(inst_xpath, XPATH_MAXLEN, - "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag, - vrf_name); - - /* if instance exists then inherit its type, create it otherwise */ - inst_dnode = yang_dnode_get(vty->candidate_config->dnode, inst_xpath); - if (inst_dnode) - circ_type = yang_dnode_get_string(inst_dnode, "is-type"); - else - nb_cli_enqueue_change(vty, inst_xpath, NB_OP_CREATE, NULL); - nb_cli_enqueue_change(vty, "./frr-isisd:isis", NB_OP_CREATE, NULL); nb_cli_enqueue_change(vty, "./frr-isisd:isis/area-tag", NB_OP_MODIFY, tag); nb_cli_enqueue_change(vty, "./frr-isisd:isis/ipv6-routing", NB_OP_MODIFY, "true"); - if (circ_type) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", - NB_OP_MODIFY, circ_type); - - /* check if the interface is a loopback and if so set it as passive */ - ifp = nb_running_get_entry(NULL, VTY_CURR_XPATH, false); - if (ifp && if_is_loopback_or_vrf(ifp)) - nb_cli_enqueue_change(vty, "./frr-isisd:isis/passive", - NB_OP_MODIFY, "true"); return nb_cli_apply_changes(vty, NULL); } @@ -321,7 +216,7 @@ ALIAS_HIDDEN(no_ip_router_isis, no_ip_router_isis_vrf_cmd, "Routing process tag\n" VRF_CMD_HELP_STR) -void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_ipv4(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -330,7 +225,7 @@ void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode, yang_dnode_get_string(dnode, "../area-tag")); } -void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_ipv6(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -395,7 +290,8 @@ DEFPY_YANG(isis_bfd_profile, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_bfd_monitoring(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_bfd_monitoring(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, "./enabled")) { @@ -424,7 +320,7 @@ DEFPY_YANG(net, net_cmd, "[no] net WORD", return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_area_address(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_area_address(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " net %s\n", yang_dnode_get_string(dnode, NULL)); @@ -459,7 +355,7 @@ DEFPY_YANG(no_is_type, no_is_type_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_is_type(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_is_type(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { int is_type = yang_dnode_get_enum(dnode, NULL); @@ -491,7 +387,8 @@ DEFPY_YANG(dynamic_hostname, dynamic_hostname_cmd, "[no] hostname dynamic", return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_dynamic_hostname(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_dynamic_hostname(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -513,7 +410,7 @@ DEFPY_YANG(set_overload_bit, set_overload_bit_cmd, "[no] set-overload-bit", return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_overload(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -552,7 +449,7 @@ DEFPY_YANG(attached_bit_send, attached_bit_send_cmd, "[no] attached-bit send", return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_attached_send(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_attached_send(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -577,7 +474,8 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_attached_receive(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_attached_receive(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -613,7 +511,7 @@ DEFPY_YANG(no_metric_style, no_metric_style_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_metric_style(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_metric_style(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { int metric = yang_dnode_get_enum(dnode, NULL); @@ -656,7 +554,7 @@ DEFPY_YANG(area_passwd, area_passwd_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_area_pwd(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_area_pwd(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *snp; @@ -706,7 +604,7 @@ DEFPY_YANG(no_area_passwd, no_area_passwd_cmd, return nb_cli_apply_changes(vty, "./%s", cmd); } -void cli_show_isis_domain_pwd(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_domain_pwd(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *snp; @@ -931,7 +829,7 @@ DEFPY_YANG(no_lsp_timers, no_lsp_timers_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_lsp_timers(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_lsp_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *l1_refresh = @@ -983,7 +881,7 @@ DEFPY_YANG(no_area_lsp_mtu, no_area_lsp_mtu_cmd, "no lsp-mtu [(128-4352)]", return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_lsp_mtu(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_lsp_mtu(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " lsp-mtu %s\n", yang_dnode_get_string(dnode, NULL)); @@ -1027,7 +925,8 @@ DEFPY_YANG(no_spf_interval, no_spf_interval_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_spf_min_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_spf_min_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { const char *l1 = yang_dnode_get_string(dnode, "./level-1"); @@ -1095,7 +994,8 @@ DEFPY_YANG(no_spf_delay_ietf, no_spf_delay_ietf_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_spf_ietf_backoff(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_spf_ietf_backoff(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, @@ -1111,7 +1011,7 @@ void cli_show_isis_spf_ietf_backoff(struct vty *vty, struct lyd_node *dnode, * XPath: /frr-isisd:isis/instance/spf/prefix-priorities/medium/access-list-name */ DEFPY_YANG(spf_prefix_priority, spf_prefix_priority_cmd, - "spf prefix-priority <critical|high|medium>$priority WORD$acl_name", + "spf prefix-priority <critical|high|medium>$priority ACCESSLIST_NAME$acl_name", "SPF configuration\n" "Configure a prefix priority list\n" "Specify critical priority prefixes\n" @@ -1129,7 +1029,7 @@ DEFPY_YANG(spf_prefix_priority, spf_prefix_priority_cmd, } DEFPY_YANG(no_spf_prefix_priority, no_spf_prefix_priority_cmd, - "no spf prefix-priority <critical|high|medium>$priority [WORD]", + "no spf prefix-priority <critical|high|medium>$priority [ACCESSLIST_NAME]", NO_STR "SPF configuration\n" "Configure a prefix priority list\n" @@ -1147,7 +1047,8 @@ DEFPY_YANG(no_spf_prefix_priority, no_spf_prefix_priority_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_spf_prefix_priority(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_spf_prefix_priority(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " spf prefix-priority %s %s\n", @@ -1167,7 +1068,7 @@ DEFPY_YANG(area_purge_originator, area_purge_originator_cmd, "[no] purge-origina return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_purge_origin(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_purge_origin(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -1198,7 +1099,7 @@ DEFPY_YANG(no_isis_mpls_te_on, no_isis_mpls_te_on_cmd, "no mpls-te [on]", return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_mpls_te(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mpls_te(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " mpls-te on\n"); @@ -1231,7 +1132,8 @@ DEFPY_YANG(no_isis_mpls_te_router_addr, no_isis_mpls_te_router_addr_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_mpls_te_router_addr(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mpls_te_router_addr(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " mpls-te router-address %s\n", @@ -1292,7 +1194,7 @@ DEFPY_YANG(isis_default_originate, isis_default_originate_cmd, level); } -static void vty_print_def_origin(struct vty *vty, struct lyd_node *dnode, +static void vty_print_def_origin(struct vty *vty, const struct lyd_node *dnode, const char *family, const char *level, bool show_defaults) { @@ -1310,7 +1212,8 @@ static void vty_print_def_origin(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void cli_show_isis_def_origin_ipv4(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_def_origin_ipv4(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { const char *level = yang_dnode_get_string(dnode, "./level"); @@ -1318,7 +1221,8 @@ void cli_show_isis_def_origin_ipv4(struct vty *vty, struct lyd_node *dnode, vty_print_def_origin(vty, dnode, "ipv4", level, show_defaults); } -void cli_show_isis_def_origin_ipv6(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_def_origin_ipv6(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { const char *level = yang_dnode_get_string(dnode, "./level"); @@ -1361,7 +1265,8 @@ DEFPY_YANG(isis_redistribute, isis_redistribute_cmd, level); } -static void vty_print_redistribute(struct vty *vty, struct lyd_node *dnode, +static void vty_print_redistribute(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults, const char *family) { const char *level = yang_dnode_get_string(dnode, "./level"); @@ -1377,12 +1282,14 @@ static void vty_print_redistribute(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void cli_show_isis_redistribute_ipv4(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_redistribute_ipv4(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_print_redistribute(vty, dnode, show_defaults, "ipv4"); } -void cli_show_isis_redistribute_ipv6(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_redistribute_ipv6(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_print_redistribute(vty, dnode, show_defaults, "ipv6"); @@ -1435,7 +1342,8 @@ DEFPY_YANG(isis_topology, isis_topology_cmd, return nb_cli_apply_changes(vty, base_xpath); } -void cli_show_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv4_multicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " topology ipv4-multicast"); @@ -1444,7 +1352,7 @@ void cli_show_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " topology ipv4-mgmt"); @@ -1453,7 +1361,8 @@ void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void cli_show_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv6_unicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " topology ipv6-unicast"); @@ -1462,7 +1371,8 @@ void cli_show_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void cli_show_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv6_multicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " topology ipv6-multicast"); @@ -1471,7 +1381,7 @@ void cli_show_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void cli_show_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv6_mgmt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " topology ipv6-mgmt"); @@ -1480,7 +1390,7 @@ void cli_show_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " topology ipv6-dstsrc"); @@ -1517,7 +1427,7 @@ DEFPY_YANG (no_isis_sr_enable, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_sr_enabled(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_sr_enabled(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -1585,7 +1495,7 @@ DEFPY_YANG(no_isis_sr_global_block_label_range, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_label_blocks(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_label_blocks(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " segment-routing global-block %s %s", @@ -1671,7 +1581,7 @@ DEFPY_YANG (no_isis_sr_node_msd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_node_msd(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_node_msd(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " segment-routing node-msd %s\n", @@ -1748,7 +1658,7 @@ DEFPY_YANG (no_isis_sr_prefix_sid, prefix_str); } -void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_prefix_sid(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *prefix; @@ -1825,7 +1735,7 @@ DEFPY_YANG (isis_frr_lfa_priority_limit, } void cli_show_isis_frr_lfa_priority_limit(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " fast-reroute priority-limit %s %s\n", @@ -1890,7 +1800,8 @@ DEFPY_YANG (isis_frr_lfa_tiebreaker, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " fast-reroute lfa tiebreaker %s index %s %s\n", @@ -1938,10 +1849,11 @@ DEFPY_YANG (isis_frr_lfa_load_sharing, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { - if (!yang_dnode_get_bool(dnode, NULL)) + if (yang_dnode_get_bool(dnode, NULL)) vty_out(vty, " no"); vty_out(vty, " fast-reroute load-sharing disable %s\n", @@ -1996,7 +1908,8 @@ DEFPY_YANG (no_isis_frr_remote_lfa_plist, return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " fast-reroute remote-lfa prefix-list %s %s\n", @@ -2018,7 +1931,7 @@ DEFPY_YANG(isis_passive, isis_passive_cmd, "[no] isis passive", return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_passive(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_passive(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -2061,7 +1974,7 @@ DEFPY_YANG(no_isis_passwd, no_isis_passwd_cmd, "no isis password [<md5|clear> WO return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_password(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_password(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " isis password %s %s\n", @@ -2109,7 +2022,7 @@ DEFPY_YANG(no_isis_metric, no_isis_metric_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_metric(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_metric(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *l1 = yang_dnode_get_string(dnode, "./level-1"); @@ -2167,7 +2080,8 @@ DEFPY_YANG(no_isis_hello_interval, no_isis_hello_interval_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_hello_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_hello_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { const char *l1 = yang_dnode_get_string(dnode, "./level-1"); @@ -2225,7 +2139,7 @@ DEFPY_YANG(no_isis_hello_multiplier, no_isis_hello_multiplier_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_hello_multi(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_hello_multi(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *l1 = yang_dnode_get_string(dnode, "./level-1"); @@ -2255,7 +2169,8 @@ DEFPY_YANG(isis_threeway_adj, isis_threeway_adj_cmd, "[no] isis three-way-handsh return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_threeway_shake(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_threeway_shake(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (yang_dnode_get_bool(dnode, NULL)) @@ -2278,7 +2193,8 @@ DEFPY_YANG(isis_hello_padding, isis_hello_padding_cmd, "[no] isis hello padding" return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_hello_padding(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_hello_padding(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -2331,7 +2247,8 @@ DEFPY_YANG(no_csnp_interval, no_csnp_interval_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_csnp_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_csnp_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { const char *l1 = yang_dnode_get_string(dnode, "./level-1"); @@ -2389,7 +2306,8 @@ DEFPY_YANG(no_psnp_interval, no_psnp_interval_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_psnp_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_psnp_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { const char *l1 = yang_dnode_get_string(dnode, "./level-1"); @@ -2432,7 +2350,8 @@ DEFPY_YANG(circuit_topology, circuit_topology_cmd, vty, "./frr-isisd:isis/multi-topology/%s", topology); } -void cli_show_ip_isis_mt_ipv4_unicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv4_unicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -2440,7 +2359,8 @@ void cli_show_ip_isis_mt_ipv4_unicast(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " isis topology ipv4-unicast\n"); } -void cli_show_ip_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv4_multicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -2448,7 +2368,8 @@ void cli_show_ip_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " isis topology ipv4-multicast\n"); } -void cli_show_ip_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv4_mgmt(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -2456,7 +2377,8 @@ void cli_show_ip_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " isis topology ipv4-mgmt\n"); } -void cli_show_ip_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv6_unicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -2464,7 +2386,8 @@ void cli_show_ip_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " isis topology ipv6-unicast\n"); } -void cli_show_ip_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv6_multicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -2472,7 +2395,8 @@ void cli_show_ip_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " isis topology ipv6-multicast\n"); } -void cli_show_ip_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv6_mgmt(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -2480,7 +2404,8 @@ void cli_show_ip_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " isis topology ipv6-mgmt\n"); } -void cli_show_ip_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv6_dstsrc(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -2515,46 +2440,13 @@ DEFPY_YANG(no_isis_circuit_type, no_isis_circuit_type_cmd, "Level-1-2 adjacencies are formed\n" "Level-2 only adjacencies are formed\n") { - char inst_xpath[XPATH_MAXLEN]; - struct lyd_node *if_dnode, *inst_dnode; - const char *vrf_name; - const char *tag; - const char *circ_type = NULL; - - /* - * Default value depends on whether the circuit is part of an area, - * and the is-type of the area if there is one. So we need to do this - * here. - */ - if_dnode = yang_dnode_get(vty->candidate_config->dnode, VTY_CURR_XPATH); - if (!if_dnode) { - vty_out(vty, "%% Failed to get iface dnode in candidate DB\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - if (!yang_dnode_exists(if_dnode, "frr-isisd:isis/area-tag")) { - vty_out(vty, "%% ISIS is not configured on the interface\n"); - return CMD_WARNING_CONFIG_FAILED; - } - - vrf_name = yang_dnode_get_string(if_dnode, "vrf"); - tag = yang_dnode_get_string(if_dnode, "frr-isisd:isis/area-tag"); - - snprintf(inst_xpath, XPATH_MAXLEN, - "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']", tag, - vrf_name); - - inst_dnode = yang_dnode_get(vty->candidate_config->dnode, inst_xpath); - if (inst_dnode) - circ_type = yang_dnode_get_string(inst_dnode, "is-type"); - nb_cli_enqueue_change(vty, "./frr-isisd:isis/circuit-type", - NB_OP_MODIFY, circ_type); + NB_OP_MODIFY, NULL); return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_circ_type(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { int level = yang_dnode_get_enum(dnode, NULL); @@ -2588,7 +2480,8 @@ DEFPY_YANG(isis_network, isis_network_cmd, "[no] isis network point-to-point", return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_network_type(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_network_type(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (yang_dnode_get_enum(dnode, NULL) != CIRCUIT_T_P2P) @@ -2637,7 +2530,7 @@ DEFPY_YANG(no_isis_priority, no_isis_priority_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_priority(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *l1 = yang_dnode_get_string(dnode, "./level-1"); @@ -2654,7 +2547,7 @@ void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode, /* * XPath: /frr-interface:lib/interface/frr-isisd:isis/fast-reroute */ -void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_frr(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { bool l1_enabled, l2_enabled; @@ -2832,7 +2725,8 @@ DEFPY(isis_lfa_exclude_interface, isis_lfa_exclude_interface_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_frr_lfa_exclude_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_frr_lfa_exclude_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " isis fast-reroute lfa %s exclude interface %s\n", @@ -2930,7 +2824,8 @@ DEFPY(isis_remote_lfa_max_metric, isis_remote_lfa_max_metric_cmd, return nb_cli_apply_changes(vty, NULL); } -void cli_show_frr_remote_lfa_max_metric(struct vty *vty, struct lyd_node *dnode, +void cli_show_frr_remote_lfa_max_metric(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " isis fast-reroute remote-lfa maximum-metric %s %s\n", @@ -3028,7 +2923,7 @@ DEFPY_YANG(log_adj_changes, log_adj_changes_cmd, "[no] log-adjacency-changes", return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_log_adjacency(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -3055,7 +2950,7 @@ DEFPY(no_isis_mpls_ldp_sync, no_isis_mpls_ldp_sync_cmd, "no mpls ldp-sync", return nb_cli_apply_changes(vty, NULL); } -void cli_show_isis_mpls_ldp_sync(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mpls_ldp_sync(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " mpls ldp-sync\n"); @@ -3084,7 +2979,7 @@ DEFPY(no_isis_mpls_ldp_sync_holddown, no_isis_mpls_ldp_sync_holddown_cmd, } void cli_show_isis_mpls_ldp_sync_holddown(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " mpls ldp-sync holddown %s\n", @@ -3114,7 +3009,8 @@ DEFPY(isis_mpls_if_ldp_sync, isis_mpls_if_ldp_sync_cmd, } -void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -3165,7 +3061,7 @@ DEFPY(no_isis_mpls_if_ldp_sync_holddown, no_isis_mpls_if_ldp_sync_holddown_cmd, } void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " isis mpls ldp-sync holddown %s\n", diff --git a/isisd/isis_events.c b/isisd/isis_events.c index 0b987fc5cf..26c68db762 100644 --- a/isisd/isis_events.c +++ b/isisd/isis_events.c @@ -128,7 +128,7 @@ static void circuit_resign_level(struct isis_circuit *circuit, int level) void isis_circuit_is_type_set(struct isis_circuit *circuit, int newtype) { - if (circuit->state != C_STATE_UP) { + if (!circuit->area) { circuit->is_type = newtype; return; } @@ -151,6 +151,11 @@ void isis_circuit_is_type_set(struct isis_circuit *circuit, int newtype) return; } + if (circuit->state != C_STATE_UP) { + circuit->is_type = newtype; + return; + } + if (!circuit->is_passive) { switch (circuit->is_type) { case IS_LEVEL_1: diff --git a/isisd/isis_ldp_sync.c b/isisd/isis_ldp_sync.c index 62d8b8334a..0c541348df 100644 --- a/isisd/isis_ldp_sync.c +++ b/isisd/isis_ldp_sync.c @@ -218,7 +218,7 @@ static int isis_ldp_sync_adj_state_change(struct isis_adjacency *adj) struct isis_area *area = circuit->area; if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE) - || circuit->interface->vrf_id != VRF_DEFAULT + || circuit->interface->vrf->vrf_id != VRF_DEFAULT || if_is_loopback(circuit->interface)) return 0; @@ -486,6 +486,9 @@ void isis_if_ldp_sync_enable(struct isis_circuit *circuit) if (if_is_loopback(circuit->interface)) return; + if (circuit->interface->vrf->vrf_id != VRF_DEFAULT) + return; + ils_debug("ldp_sync: enable if %s", circuit->interface->name); if (!CHECK_FLAG(area->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) diff --git a/isisd/isis_main.c b/isisd/isis_main.c index 6deeebda95..fb4237f002 100644 --- a/isisd/isis_main.c +++ b/isisd/isis_main.c @@ -147,7 +147,7 @@ void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t isisd_signals[] = { +struct frr_signal_t isisd_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/isisd/isis_nb.h b/isisd/isis_nb.h index 4680dd5ded..ee7904163c 100644 --- a/isisd/isis_nb.h +++ b/isisd/isis_nb.h @@ -413,141 +413,174 @@ void isis_instance_segment_routing_prefix_sid_map_prefix_sid_apply_finish( struct nb_cb_apply_finish_args *args); /* Optional 'cli_show' callbacks. */ -void cli_show_router_isis(struct vty *vty, struct lyd_node *dnode, +void cli_show_router_isis(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_router_isis_end(struct vty *vty, struct lyd_node *dnode); -void cli_show_ip_isis_ipv4(struct vty *vty, struct lyd_node *dnode, +void cli_show_router_isis_end(struct vty *vty, const struct lyd_node *dnode); +void cli_show_ip_isis_ipv4(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_ipv6(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_ipv6(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_bfd_monitoring(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_bfd_monitoring(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_area_address(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_area_address(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_is_type(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_is_type(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_dynamic_hostname(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_dynamic_hostname(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_attached_send(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_attached_send(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_attached_receive(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_attached_receive(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_overload(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_overload(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_metric_style(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_metric_style(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_area_pwd(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_area_pwd(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_domain_pwd(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_domain_pwd(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_lsp_timers(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_lsp_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_lsp_mtu(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_lsp_mtu(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_spf_min_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_spf_min_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_spf_ietf_backoff(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_spf_ietf_backoff(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_spf_prefix_priority(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_spf_prefix_priority(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_purge_origin(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_purge_origin(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mpls_te(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mpls_te(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mpls_te_router_addr(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mpls_te_router_addr(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_def_origin_ipv4(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_def_origin_ipv4(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_def_origin_ipv6(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_def_origin_ipv6(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_redistribute_ipv4(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_redistribute_ipv4(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_redistribute_ipv6(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_redistribute_ipv6(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv4_multicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv4_mgmt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv6_unicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv6_multicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv6_mgmt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mt_ipv6_dstsrc(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_sr_enabled(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_sr_enabled(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_label_blocks(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_label_blocks(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_node_msd(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_node_msd(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_prefix_sid(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_prefix_sid(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_isis_frr_lfa_priority_limit(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_frr_lfa_tiebreaker(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_frr_lfa_load_sharing(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_frr_remote_lfa_plist(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_passive(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_passive(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_password(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_password(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_metric(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_metric(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_hello_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_hello_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_hello_multi(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_hello_multi(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_threeway_shake(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_threeway_shake(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_hello_padding(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_hello_padding(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_csnp_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_csnp_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_psnp_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_psnp_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_mt_ipv4_unicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv4_unicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_mt_ipv4_multicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv4_multicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_mt_ipv4_mgmt(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv4_mgmt(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_mt_ipv6_unicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv6_unicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_mt_ipv6_multicast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv6_multicast(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_mt_ipv6_mgmt(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv6_mgmt(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_mt_ipv6_dstsrc(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_mt_ipv6_dstsrc(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_frr(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_frr(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_frr_lfa_exclude_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_frr_lfa_exclude_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_frr_remote_lfa_max_metric(struct vty *vty, struct lyd_node *dnode, +void cli_show_frr_remote_lfa_max_metric(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_circ_type(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_circ_type(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_network_type(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_network_type(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_isis_priority(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_isis_priority(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_log_adjacency(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_log_adjacency(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mpls_ldp_sync(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mpls_ldp_sync(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_isis_mpls_ldp_sync_holddown(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, struct lyd_node *dnode, +void cli_show_isis_mpls_if_ldp_sync(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); void cli_show_isis_mpls_if_ldp_sync_holddown(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); /* Notifications. */ diff --git a/isisd/isis_nb_config.c b/isisd/isis_nb_config.c index 4a01c728f0..3674d69376 100644 --- a/isisd/isis_nb_config.c +++ b/isisd/isis_nb_config.c @@ -2479,7 +2479,7 @@ int lib_interface_isis_create(struct nb_cb_create_args *args) actual_mtu = if_is_broadcast(ifp) ? ifp->mtu - LLC_LEN : ifp->mtu; - area = isis_area_lookup(area_tag, ifp->vrf_id); + area = isis_area_lookup(area_tag, ifp->vrf->vrf_id); if (area) min_mtu = area->lsp_mtu; else @@ -2526,31 +2526,12 @@ int lib_interface_isis_destroy(struct nb_cb_destroy_args *args) int lib_interface_isis_area_tag_modify(struct nb_cb_modify_args *args) { struct isis_circuit *circuit; - struct interface *ifp; - struct vrf *vrf; - const char *area_tag, *ifname, *vrfname; if (args->event == NB_EV_VALIDATE) { - /* libyang doesn't like relative paths across module boundaries - */ - ifname = yang_dnode_get_string( - lyd_parent(lyd_parent(args->dnode)), "./name"); - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(args->dnode)), "./vrf"); - vrf = vrf_lookup_by_name(vrfname); - assert(vrf); - ifp = if_lookup_by_name(ifname, vrf->vrf_id); - - if (!ifp) - return NB_OK; - - circuit = circuit_scan_by_ifp(ifp); - area_tag = yang_dnode_get_string(args->dnode, NULL); - if (circuit && circuit->area && circuit->area->area_tag - && strcmp(circuit->area->area_tag, area_tag)) { + circuit = nb_running_get_entry_non_rec(lyd_parent(args->dnode), NULL, false); + if (circuit) { snprintf(args->errmsg, args->errmsg_len, - "ISIS circuit is already defined on %s", - circuit->area->area_tag); + "Changing area tag is not allowed"); return NB_ERR_VALIDATION; } } @@ -2565,39 +2546,15 @@ int lib_interface_isis_circuit_type_modify(struct nb_cb_modify_args *args) { int circ_type = yang_dnode_get_enum(args->dnode, NULL); struct isis_circuit *circuit; - struct interface *ifp; - struct vrf *vrf; - const char *ifname, *vrfname; switch (args->event) { case NB_EV_VALIDATE: - /* libyang doesn't like relative paths across module boundaries - */ - ifname = yang_dnode_get_string( - lyd_parent(lyd_parent(args->dnode)), "./name"); - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(args->dnode)), "./vrf"); - vrf = vrf_lookup_by_name(vrfname); - assert(vrf); - ifp = if_lookup_by_name(ifname, vrf->vrf_id); - if (!ifp) - break; - - circuit = circuit_scan_by_ifp(ifp); - if (circuit && circuit->state == C_STATE_UP - && circuit->area->is_type != IS_LEVEL_1_AND_2 - && circuit->area->is_type != circ_type) { - snprintf(args->errmsg, args->errmsg_len, - "Invalid circuit level for area %s", - circuit->area->area_tag); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: circuit = nb_running_get_entry(args->dnode, NULL, true); + circuit->is_type_config = circ_type; isis_circuit_is_type_set(circuit, circ_type); break; } @@ -2979,24 +2936,8 @@ int lib_interface_isis_network_type_modify(struct nb_cb_modify_args *args) int lib_interface_isis_passive_modify(struct nb_cb_modify_args *args) { struct isis_circuit *circuit; - struct interface *ifp; bool passive = yang_dnode_get_bool(args->dnode, NULL); - /* validation only applies if we are setting passive to false */ - if (!passive && args->event == NB_EV_VALIDATE) { - circuit = nb_running_get_entry(args->dnode, NULL, false); - if (!circuit) - return NB_OK; - ifp = circuit->interface; - if (!ifp) - return NB_OK; - if (if_is_loopback_or_vrf(ifp)) { - snprintf(args->errmsg, args->errmsg_len, - "Loopback is always passive"); - return NB_ERR_VALIDATION; - } - } - if (args->event != NB_EV_APPLY) return NB_OK; @@ -3204,19 +3145,9 @@ int lib_interface_isis_mpls_ldp_sync_modify(struct nb_cb_modify_args *args) struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; bool ldp_sync_enable; - const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(lyd_parent(args->dnode))), - "./vrf"); - if (strcmp(vrfname, VRF_DEFAULT_NAME)) { - snprintf(args->errmsg, args->errmsg_len, - "LDP-Sync only runs on Default VRF"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; @@ -3248,19 +3179,9 @@ int lib_interface_isis_mpls_holddown_modify(struct nb_cb_modify_args *args) struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; uint16_t holddown; - const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(lyd_parent(args->dnode))), - "./vrf"); - if (strcmp(vrfname, VRF_DEFAULT_NAME)) { - snprintf(args->errmsg, args->errmsg_len, - "LDP-Sync only runs on Default VRF"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; @@ -3281,19 +3202,9 @@ int lib_interface_isis_mpls_holddown_destroy(struct nb_cb_destroy_args *args) { struct isis_circuit *circuit; struct ldp_sync_info *ldp_sync_info; - const char *vrfname; switch (args->event) { case NB_EV_VALIDATE: - vrfname = yang_dnode_get_string( - lyd_parent(lyd_parent(lyd_parent(args->dnode))), - "./vrf"); - if (strcmp(vrfname, VRF_DEFAULT_NAME)) { - snprintf(args->errmsg, args->errmsg_len, - "LDP-Sync only runs on Default VRF"); - return NB_ERR_VALIDATION; - } - break; case NB_EV_PREPARE: case NB_EV_ABORT: break; diff --git a/isisd/isis_pfpacket.c b/isisd/isis_pfpacket.c index 4a884877f0..20224c73a1 100644 --- a/isisd/isis_pfpacket.c +++ b/isisd/isis_pfpacket.c @@ -123,15 +123,10 @@ static int open_packet_socket(struct isis_circuit *circuit) int fd, retval = ISIS_OK; struct vrf *vrf = NULL; - vrf = vrf_lookup_by_id(circuit->interface->vrf_id); + vrf = circuit->interface->vrf; - if (vrf == NULL) { - zlog_warn("open_packet_socket(): failed to find vrf node"); - return ISIS_WARNING; - } - - fd = vrf_socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL), - circuit->interface->vrf_id, vrf->name); + fd = vrf_socket(PF_PACKET, SOCK_DGRAM, htons(ETH_P_ALL), vrf->vrf_id, + vrf->name); if (fd < 0) { zlog_warn("open_packet_socket(): socket() failed %s", diff --git a/isisd/isis_spf.c b/isisd/isis_spf.c index 45e89897ff..5718b48b9d 100644 --- a/isisd/isis_spf.c +++ b/isisd/isis_spf.c @@ -1840,7 +1840,6 @@ static int isis_run_spf_cb(struct thread *thread) int have_run = 0; XFREE(MTYPE_ISIS_SPF_RUN, run); - area->spf_timer[level - 1] = NULL; if (!(area->is_type & level)) { if (IS_DEBUG_SPF_EVENTS) diff --git a/isisd/isis_sr.c b/isisd/isis_sr.c index f7cef43d0d..54e31f0040 100644 --- a/isisd/isis_sr.c +++ b/isisd/isis_sr.c @@ -550,13 +550,13 @@ static void sr_local_block_delete(struct isis_area *area) */ static mpls_label_t sr_local_block_request_label(struct sr_local_block *srlb) { - mpls_label_t label; uint32_t index; uint32_t pos; + uint32_t size = srlb->end - srlb->start + 1; /* Check if we ran out of available labels */ - if (srlb->current >= srlb->end) + if (srlb->current >= size) return MPLS_INVALID_LABEL; /* Get first available label and mark it used */ @@ -568,7 +568,7 @@ static mpls_label_t sr_local_block_request_label(struct sr_local_block *srlb) /* Jump to the next free position */ srlb->current++; pos = srlb->current % SRLB_BLOCK_SIZE; - while (srlb->current < srlb->end) { + while (srlb->current < size) { if (pos == 0) index++; if (!((1ULL << pos) & srlb->used_mark[index])) @@ -579,6 +579,10 @@ static mpls_label_t sr_local_block_request_label(struct sr_local_block *srlb) } } + if (srlb->current == size) + zlog_warn( + "SR: Warning, SRLB is depleted and next label request will fail"); + return label; } diff --git a/isisd/isis_tlvs.c b/isisd/isis_tlvs.c index 17dbb1903d..a66d3b00f7 100644 --- a/isisd/isis_tlvs.c +++ b/isisd/isis_tlvs.c @@ -539,9 +539,12 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, /* Read SubTLV Type and Length */ subtlv_type = stream_getc(s); subtlv_len = stream_getc(s); - if (subtlv_len > len - sum) { - sbuf_push(log, indent, "TLV %hhu: Available data %u is less than TLV size %u !\n", - subtlv_type, len - sum, subtlv_len); + if (subtlv_len > len - sum - ISIS_SUBTLV_HDR_SIZE) { + sbuf_push( + log, indent, + "TLV %hhu: Available data %u is less than TLV size %u !\n", + subtlv_type, len - sum - ISIS_SUBTLV_HDR_SIZE, + subtlv_len); return 1; } @@ -551,6 +554,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Administrative Group!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->adm_group = stream_getl(s); SET_SUBTLV(exts, EXT_ADM_GRP); @@ -560,6 +564,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_LLRI_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Link ID!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->local_llri = stream_getl(s); exts->remote_llri = stream_getl(s); @@ -570,6 +575,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Local IP address!\n"); + stream_forward_getp(s, subtlv_len); } else { stream_get(&exts->local_addr.s_addr, s, 4); SET_SUBTLV(exts, EXT_LOCAL_ADDR); @@ -579,6 +585,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Remote IP address!\n"); + stream_forward_getp(s, subtlv_len); } else { stream_get(&exts->neigh_addr.s_addr, s, 4); SET_SUBTLV(exts, EXT_NEIGH_ADDR); @@ -588,6 +595,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Local IPv6 address!\n"); + stream_forward_getp(s, subtlv_len); } else { stream_get(&exts->local_addr6, s, 16); SET_SUBTLV(exts, EXT_LOCAL_ADDR6); @@ -597,6 +605,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_IPV6_ADDR_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Remote IPv6 address!\n"); + stream_forward_getp(s, subtlv_len); } else { stream_get(&exts->neigh_addr6, s, 16); SET_SUBTLV(exts, EXT_NEIGH_ADDR6); @@ -606,6 +615,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Maximum Bandwidth!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->max_bw = stream_getf(s); SET_SUBTLV(exts, EXT_MAX_BW); @@ -615,6 +625,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Maximum Reservable Bandwidth!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->max_rsv_bw = stream_getf(s); SET_SUBTLV(exts, EXT_MAX_RSV_BW); @@ -624,6 +635,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_UNRSV_BW_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Unreserved Bandwidth!\n"); + stream_forward_getp(s, subtlv_len); } else { for (int i = 0; i < MAX_CLASS_TYPE; i++) exts->unrsv_bw[i] = stream_getf(s); @@ -634,6 +646,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_TE_METRIC_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Traffic Engineering Metric!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->te_metric = stream_get3(s); SET_SUBTLV(exts, EXT_TE_METRIC); @@ -643,6 +656,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Remote AS number!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->remote_as = stream_getl(s); SET_SUBTLV(exts, EXT_RMT_AS); @@ -652,6 +666,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Remote ASBR IP Address!\n"); + stream_forward_getp(s, subtlv_len); } else { stream_get(&exts->remote_ip.s_addr, s, 4); SET_SUBTLV(exts, EXT_RMT_IP); @@ -662,15 +677,17 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Average Link Delay!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->delay = stream_getl(s); SET_SUBTLV(exts, EXT_DELAY); } break; case ISIS_SUBTLV_MM_DELAY: - if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { + if (subtlv_len != ISIS_SUBTLV_MM_DELAY_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Min/Max Link Delay!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->min_delay = stream_getl(s); exts->max_delay = stream_getl(s); @@ -681,6 +698,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Delay Variation!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->delay_var = stream_getl(s); SET_SUBTLV(exts, EXT_DELAY_VAR); @@ -690,6 +708,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Link Packet Loss!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->pkt_loss = stream_getl(s); SET_SUBTLV(exts, EXT_PKT_LOSS); @@ -699,6 +718,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Unidirectional Residual Bandwidth!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->res_bw = stream_getf(s); SET_SUBTLV(exts, EXT_RES_BW); @@ -708,6 +728,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Unidirectional Available Bandwidth!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->ava_bw = stream_getf(s); SET_SUBTLV(exts, EXT_AVA_BW); @@ -717,6 +738,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, if (subtlv_len != ISIS_SUBTLV_DEF_SIZE) { sbuf_push(log, indent, "TLV size does not match expected size for Unidirectional Utilized Bandwidth!\n"); + stream_forward_getp(s, subtlv_len); } else { exts->use_bw = stream_getf(s); SET_SUBTLV(exts, EXT_USE_BW); @@ -728,6 +750,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE + 1) { sbuf_push(log, indent, "TLV size does not match expected size for Adjacency SID!\n"); + stream_forward_getp(s, subtlv_len); } else { struct isis_adj_sid *adj; @@ -735,6 +758,26 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, sizeof(struct isis_adj_sid)); adj->flags = stream_getc(s); adj->weight = stream_getc(s); + if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + && subtlv_len != ISIS_SUBTLV_ADJ_SID_SIZE) { + sbuf_push( + log, indent, + "TLV size does not match expected size for Adjacency SID!\n"); + stream_forward_getp(s, subtlv_len - 2); + break; + } + + if (!(adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) + && subtlv_len + != ISIS_SUBTLV_ADJ_SID_SIZE + + 1) { + sbuf_push( + log, indent, + "TLV size does not match expected size for Adjacency SID!\n"); + stream_forward_getp(s, subtlv_len - 2); + break; + } + if (adj->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) { adj->sid = stream_get3(s); adj->sid &= MPLS_LABEL_VALUE_MASK; @@ -756,6 +799,7 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, && subtlv_len != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + 1) { sbuf_push(log, indent, "TLV size does not match expected size for LAN-Adjacency SID!\n"); + stream_forward_getp(s, subtlv_len); } else { struct isis_lan_adj_sid *lan; @@ -765,6 +809,32 @@ static int unpack_item_ext_subtlvs(uint16_t mtid, uint8_t len, struct stream *s, lan->weight = stream_getc(s); stream_get(&(lan->neighbor_id), s, ISIS_SYS_ID_LEN); + + if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG + && subtlv_len + != ISIS_SUBTLV_LAN_ADJ_SID_SIZE) { + sbuf_push( + log, indent, + "TLV size does not match expected size for LAN-Adjacency SID!\n"); + stream_forward_getp( + s, subtlv_len - 2 + - ISIS_SYS_ID_LEN); + break; + } + + if (!(lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) + && subtlv_len + != ISIS_SUBTLV_LAN_ADJ_SID_SIZE + + 1) { + sbuf_push( + log, indent, + "TLV size does not match expected size for LAN-Adjacency SID!\n"); + stream_forward_getp( + s, subtlv_len - 2 + - ISIS_SYS_ID_LEN); + break; + } + if (lan->flags & EXT_SUBTLV_LINK_ADJ_SID_VFLG) { lan->sid = stream_get3(s); lan->sid &= MPLS_LABEL_VALUE_MASK; diff --git a/isisd/isis_zebra.c b/isisd/isis_zebra.c index 2c05cb8277..27e80e2501 100644 --- a/isisd/isis_zebra.c +++ b/isisd/isis_zebra.c @@ -800,23 +800,31 @@ static int isis_zebra_client_close_notify(ZAPI_CALLBACK_ARGS) return ret; } +static zclient_handler *const isis_handlers[] = { + [ZEBRA_ROUTER_ID_UPDATE] = isis_router_id_update_zebra, + [ZEBRA_INTERFACE_ADDRESS_ADD] = isis_zebra_if_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = isis_zebra_if_address_del, + [ZEBRA_INTERFACE_LINK_PARAMS] = isis_zebra_link_params, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = isis_zebra_read, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = isis_zebra_read, + + [ZEBRA_OPAQUE_MESSAGE] = isis_opaque_msg_handler, + + [ZEBRA_CLIENT_CLOSE_NOTIFY] = isis_zebra_client_close_notify, +}; + void isis_zebra_init(struct thread_master *master, int instance) { /* Initialize asynchronous zclient. */ - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, isis_handlers, + array_size(isis_handlers)); zclient_init(zclient, PROTO_TYPE, 0, &isisd_privs); zclient->zebra_connected = isis_zebra_connected; - zclient->router_id_update = isis_router_id_update_zebra; - zclient->interface_address_add = isis_zebra_if_address_add; - zclient->interface_address_delete = isis_zebra_if_address_del; - zclient->interface_link_params = isis_zebra_link_params; - zclient->redistribute_route_add = isis_zebra_read; - zclient->redistribute_route_del = isis_zebra_read; /* Initialize special zclient for synchronous message exchanges. */ struct zclient_options options = zclient_options_default; options.synchronous = true; - zclient_sync = zclient_new(master, &options); + zclient_sync = zclient_new(master, &options, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_ISIS; zclient_sync->instance = instance; @@ -826,10 +834,6 @@ void isis_zebra_init(struct thread_master *master, int instance) */ zclient_sync->session_id = 1; zclient_sync->privs = &isisd_privs; - - zclient->opaque_msg_handler = isis_opaque_msg_handler; - - zclient->zebra_client_close_notify = isis_zebra_client_close_notify; } void isis_zebra_stop(void) diff --git a/isisd/isisd.c b/isisd/isisd.c index 65764654ee..b33f272f56 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -646,7 +646,52 @@ static int isis_vrf_enable(struct vrf *vrf) vrf->vrf_id); isis = isis_lookup_by_vrfname(vrf->name); - if (isis) { + if (!isis) { + char *old_vrf_name = NULL; + + isis = (struct isis *)vrf->info; + if (!isis) + return 0; + /* update vrf name */ + if (isis->name) + old_vrf_name = isis->name; + isis->name = XSTRDUP(MTYPE_ISIS_NAME, vrf->name); + /* + * HACK: Change the ISIS VRF in the running configuration + * directly, bypassing the northbound layer. This is necessary + * to avoid deleting the ISIS and readding it in the new VRF, + * which would have several implications. + */ + if (yang_module_find("frr-isisd") && old_vrf_name) { + struct lyd_node *isis_dnode; + struct isis_area *area; + char oldpath[XPATH_MAXLEN]; + char newpath[XPATH_MAXLEN]; + struct listnode *node, *nnode; + + for (ALL_LIST_ELEMENTS(isis->area_list, node, nnode, + area)) { + isis_dnode = yang_dnode_getf( + running_config->dnode, + "/frr-isisd:isis/instance[area-tag='%s'][vrf='%s']/vrf", + area->area_tag, old_vrf_name); + if (isis_dnode) { + yang_dnode_get_path( + lyd_parent(isis_dnode), oldpath, + sizeof(oldpath)); + yang_dnode_change_leaf(isis_dnode, + vrf->name); + yang_dnode_get_path( + lyd_parent(isis_dnode), newpath, + sizeof(newpath)); + nb_running_move_tree(oldpath, newpath); + running_config->version++; + } + } + } + XFREE(MTYPE_ISIS_NAME, old_vrf_name); + } + if (isis && isis->vrf_id != vrf->vrf_id) { old_vrf_id = isis->vrf_id; /* We have instance configured, link to VRF and make it "up". */ isis_vrf_link(isis, vrf); @@ -654,12 +699,10 @@ static int isis_vrf_enable(struct vrf *vrf) zlog_debug( "%s: isis linked to vrf %s vrf_id %u (old id %u)", __func__, vrf->name, isis->vrf_id, old_vrf_id); - if (old_vrf_id != isis->vrf_id) { - /* start zebra redist to us for new vrf */ - isis_set_redist_vrf_bitmaps(isis, true); + /* start zebra redist to us for new vrf */ + isis_set_redist_vrf_bitmaps(isis, true); - isis_zebra_vrf_register(isis); - } + isis_zebra_vrf_register(isis); } return 0; @@ -2613,10 +2656,16 @@ void isis_area_is_type_set(struct isis_area *area, int is_type) area->is_type = is_type; - /* override circuit's is_type */ + /* + * If area's IS type is strict Level-1 or Level-2, override circuit's + * IS type. Otherwise use circuit's configured IS type. + */ if (area->is_type != IS_LEVEL_1_AND_2) { for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) isis_circuit_is_type_set(circuit, is_type); + } else { + for (ALL_LIST_ELEMENTS_RO(area->circuit_list, node, circuit)) + isis_circuit_is_type_set(circuit, circuit->is_type_config); } spftree_area_init(area); diff --git a/ldpd/hello.c b/ldpd/hello.c index 5aa14ed067..629fe46e70 100644 --- a/ldpd/hello.c +++ b/ldpd/hello.c @@ -415,13 +415,13 @@ recv_hello(struct in_addr lsr_id, struct ldp_msg *msg, int af, if (holdtime == 0) holdtime = LINK_DFLT_HOLDTIME; - adj->holdtime = min(if_get_hello_holdtime(ia), holdtime); + adj->holdtime = MIN(if_get_hello_holdtime(ia), holdtime); break; case HELLO_TARGETED: if (holdtime == 0) holdtime = TARGETED_DFLT_HOLDTIME; - adj->holdtime = min(tnbr_get_hello_holdtime(tnbr), holdtime); + adj->holdtime = MIN(tnbr_get_hello_holdtime(tnbr), holdtime); } if (adj->holdtime != INFINITE_HOLDTIME) adj_start_itimer(adj); diff --git a/ldpd/init.c b/ldpd/init.c index d394fb08ea..0ee64c16fa 100644 --- a/ldpd/init.c +++ b/ldpd/init.c @@ -197,7 +197,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) len -= tlv_len; } - nbr->keepalive = min(nbr_get_keepalive(nbr->af, nbr->id), + nbr->keepalive = MIN(nbr_get_keepalive(nbr->af, nbr->id), ntohs(sess.keepalive_time)); max_pdu_len = ntohs(sess.max_pdu_len); @@ -208,7 +208,7 @@ recv_init(struct nbr *nbr, char *buf, uint16_t len) */ if (max_pdu_len <= 255) max_pdu_len = LDP_MAX_LEN; - nbr->max_pdu_len = min(max_pdu_len, LDP_MAX_LEN); + nbr->max_pdu_len = MIN(max_pdu_len, LDP_MAX_LEN); nbr_fsm(nbr, NBR_EVT_INIT_RCVD); diff --git a/ldpd/lde.c b/ldpd/lde.c index babadc461f..55fa806d4d 100644 --- a/ldpd/lde.c +++ b/ldpd/lde.c @@ -107,7 +107,7 @@ sigint(void) lde_shutdown(); } -static struct quagga_signal_t lde_signals[] = +static struct frr_signal_t lde_signals[] = { { .signal = SIGHUP, @@ -2192,7 +2192,7 @@ static void zclient_sync_init(void) options.synchronous = true; /* Initialize special zclient for synchronous message exchanges. */ - zclient_sync = zclient_new(master, &options); + zclient_sync = zclient_new(master, &options, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_LDP; zclient_sync->session_id = 1; /* Distinguish from main session */ diff --git a/ldpd/ldp_vty_cmds.c b/ldpd/ldp_vty_cmds.c index b65ebf6f55..11d6930f06 100644 --- a/ldpd/ldp_vty_cmds.c +++ b/ldpd/ldp_vty_cmds.c @@ -253,14 +253,12 @@ DEFPY (ldp_allow_broken_lsps, DEFPY (ldp_discovery_targeted_hello_accept, ldp_discovery_targeted_hello_accept_cmd, - "[no] discovery targeted-hello accept [from <(1-199)|(1300-2699)|WORD>$from_acl]", + "[no] discovery targeted-hello accept [from ACCESSLIST_NAME$from_acl]", NO_STR "Configure discovery parameters\n" "LDP Targeted Hellos\n" "Accept and respond to targeted hellos\n" "Access list to specify acceptable targeted hello source\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP access-list name\n") { return (ldp_vty_targeted_hello_accept(vty, no, from_acl)); @@ -290,18 +288,14 @@ DEFPY (ldp_discovery_transport_address_ipv6, DEFPY (ldp_label_local_advertise, ldp_label_local_advertise_cmd, - "[no] label local advertise [{to <(1-199)|(1300-2699)|WORD>$to_acl|for <(1-199)|(1300-2699)|WORD>$for_acl}]", + "[no] label local advertise [{to ACCESSLIST_NAME$to_acl|for ACCESSLIST_NAME$for_acl}]", NO_STR "Configure label control and policies\n" "Configure local label control and policies\n" "Configure outbound label advertisement control\n" "IP Access-list specifying controls on LDP Peers\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP access-list name\n" "IP access-list for destination prefixes\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP access-list name\n") { return (ldp_vty_label_advertise(vty, no, to_acl, for_acl)); @@ -309,15 +303,13 @@ DEFPY (ldp_label_local_advertise, DEFPY (ldp_label_local_advertise_explicit_null, ldp_label_local_advertise_explicit_null_cmd, - "[no] label local advertise explicit-null [for <(1-199)|(1300-2699)|WORD>$for_acl]", + "[no] label local advertise explicit-null [for ACCESSLIST_NAME$for_acl]", NO_STR "Configure label control and policies\n" "Configure local label control and policies\n" "Configure outbound label advertisement control\n" "Configure explicit-null advertisement\n" "IP access-list for destination prefixes\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP access-list name\n") { return (ldp_vty_label_expnull(vty, no, for_acl)); @@ -325,15 +317,13 @@ DEFPY (ldp_label_local_advertise_explicit_null, DEFPY (ldp_label_local_allocate, ldp_label_local_allocate_cmd, - "[no] label local allocate <host-routes$host_routes|for <(1-199)|(1300-2699)|WORD>$for_acl>", + "[no] label local allocate <host-routes$host_routes|for ACCESSLIST_NAME$for_acl>", NO_STR "Configure label control and policies\n" "Configure local label control and policies\n" "Configure label allocation control\n" "allocate local label for host routes only\n" "IP access-list\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP access-list name\n") { return (ldp_vty_label_allocate(vty, no, host_routes, for_acl)); @@ -341,18 +331,14 @@ DEFPY (ldp_label_local_allocate, DEFPY (ldp_label_remote_accept, ldp_label_remote_accept_cmd, - "[no] label remote accept {from <(1-199)|(1300-2699)|WORD>$from_acl|for <(1-199)|(1300-2699)|WORD>$for_acl}", + "[no] label remote accept {from ACCESSLIST_NAME$from_acl|for ACCESSLIST_NAME$for_acl}", NO_STR "Configure label control and policies\n" "Configure remote/peer label control and policies\n" "Configure inbound label acceptance control\n" "Neighbor from whom to accept label advertisement\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP access-list name\n" "IP access-list for destination prefixes\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP access-list name\n") { return (ldp_vty_label_accept(vty, no, from_acl, for_acl)); diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c index 09b820e3f6..7bad1dca7c 100644 --- a/ldpd/ldp_vty_exec.c +++ b/ldpd/ldp_vty_exec.c @@ -447,7 +447,6 @@ show_discovery_msg_json(struct imsg *imsg, struct show_params *params, json_object *json) { struct ctl_adj *adj; - char buf[PREFIX_STRLEN]; json_object *json_array; json_object *json_adj; @@ -467,9 +466,8 @@ show_discovery_msg_json(struct imsg *imsg, struct show_params *params, json_adj = json_object_new_object(); json_object_string_add(json_adj, "addressFamily", af_name(adj->af)); - json_object_string_add(json_adj, "neighborId", - inet_ntop(AF_INET, &adj->id, buf, - sizeof(buf))); + json_object_string_addf(json_adj, "neighborId", "%pI4", + &adj->id); switch(adj->type) { case HELLO_LINK: json_object_string_add(json_adj, "type", "link"); @@ -498,7 +496,6 @@ show_discovery_msg_json(struct imsg *imsg, struct show_params *params, static void show_discovery_detail_adj_json(json_object *json, struct ctl_adj *adj) { - char buf[PREFIX_STRLEN]; json_object *json_adj; json_object *json_array; @@ -509,8 +506,7 @@ show_discovery_detail_adj_json(json_object *json, struct ctl_adj *adj) } json_adj = json_object_new_object(); - json_object_string_add(json_adj, "lsrId", inet_ntop(AF_INET, &adj->id, - buf, sizeof(buf))); + json_object_string_addf(json_adj, "lsrId", "%pI4", &adj->id); json_object_string_add(json_adj, "sourceAddress", log_addr(adj->af, &adj->src_addr)); json_object_string_add(json_adj, "transportAddress", log_addr(adj->af, @@ -532,7 +528,6 @@ show_discovery_detail_msg_json(struct imsg *imsg, struct show_params *params, struct ctl_disc_tnbr *tnbr; struct in_addr rtr_id; union ldpd_addr *trans_addr; - char buf[PREFIX_STRLEN]; json_object *json_interface; json_object *json_target; static json_object *json_interfaces; @@ -542,9 +537,7 @@ show_discovery_detail_msg_json(struct imsg *imsg, struct show_params *params, switch (imsg->hdr.type) { case IMSG_CTL_SHOW_DISCOVERY: rtr_id.s_addr = ldp_rtr_id_get(ldpd_conf); - json_object_string_add(json, "lsrId", - inet_ntop(AF_INET, &rtr_id, buf, - sizeof(buf))); + json_object_string_addf(json, "lsrId", "%pI4", &rtr_id); if (ldpd_conf->ipv4.flags & F_LDPD_AF_ENABLED) json_object_string_add(json, "transportAddressIPv4", log_addr(AF_INET, &ldpd_conf->ipv4.trans_addr)); @@ -749,7 +742,6 @@ show_nbr_msg_json(struct imsg *imsg, struct show_params *params, json_object *json) { struct ctl_nbr *nbr; - char buf[PREFIX_STRLEN]; json_object *json_array; json_object *json_nbr; @@ -766,9 +758,8 @@ show_nbr_msg_json(struct imsg *imsg, struct show_params *params, json_nbr = json_object_new_object(); json_object_string_add(json_nbr, "addressFamily", af_name(nbr->af)); - json_object_string_add(json_nbr, "neighborId", - inet_ntop(AF_INET, &nbr->id, buf, - sizeof(buf))); + json_object_string_addf(json_nbr, "neighborId", "%pI4", + &nbr->id); json_object_string_add(json_nbr, "state", nbr_state_name(nbr->nbr_state)); json_object_string_add(json_nbr, "transportAddress", @@ -830,9 +821,7 @@ show_nbr_detail_msg_json(struct imsg *imsg, struct show_params *params, json_object_object_add(json, inet_ntop(AF_INET, &nbr->id, buf, sizeof(buf)), json_nbr); - json_object_string_add(json_nbr, "peerId", - inet_ntop(AF_INET, &nbr->id, buf, - sizeof(buf))); + json_object_string_addf(json_nbr, "peerId", "%pI4", &nbr->id); json_object_string_add(json_nbr, "tcpLocalAddress", log_addr(nbr->af, &nbr->laddr)); json_object_int_add(json_nbr, "tcpLocalPort", @@ -1235,7 +1224,6 @@ show_lib_msg_json(struct imsg *imsg, struct show_params *params, json_object *json_array; json_object *json_lib_entry; char dstnet[BUFSIZ]; - char buf[PREFIX_STRLEN]; switch (imsg->hdr.type) { case IMSG_CTL_SHOW_LIB_BEGIN: @@ -1258,9 +1246,8 @@ show_lib_msg_json(struct imsg *imsg, struct show_params *params, snprintf(dstnet, sizeof(dstnet), "%s/%d", log_addr(rt->af, &rt->prefix), rt->prefixlen); json_object_string_add(json_lib_entry, "prefix", dstnet); - json_object_string_add(json_lib_entry, "neighborId", - inet_ntop(AF_INET, &rt->nexthop, buf, - sizeof(buf))); + json_object_string_addf(json_lib_entry, "neighborId", "%pI4", + &rt->nexthop); json_object_string_add(json_lib_entry, "localLabel", log_label(rt->local_label)); json_object_string_add(json_lib_entry, "remoteLabel", @@ -1284,7 +1271,6 @@ show_lib_detail_msg_json(struct imsg *imsg, struct show_params *params, { struct ctl_rt *rt = NULL; char dstnet[BUFSIZ]; - char buf[PREFIX_STRLEN]; static json_object *json_lib_entry; static json_object *json_adv_labels; json_object *json_adv_label; @@ -1316,18 +1302,16 @@ show_lib_detail_msg_json(struct imsg *imsg, struct show_params *params, rt = imsg->data; json_adv_label = json_object_new_object(); - json_object_string_add(json_adv_label, "neighborId", - inet_ntop(AF_INET, &rt->nexthop, buf, - sizeof(buf))); + json_object_string_addf(json_adv_label, "neighborId", "%pI4", + &rt->nexthop); json_object_array_add(json_adv_labels, json_adv_label); break; case IMSG_CTL_SHOW_LIB_RCVD: rt = imsg->data; json_remote_label = json_object_new_object(); - json_object_string_add(json_remote_label, "neighborId", - inet_ntop(AF_INET, &rt->nexthop, - buf, sizeof(buf))); + json_object_string_addf(json_remote_label, "neighborId", "%pI4", + &rt->nexthop); json_object_string_add(json_remote_label, "label", log_label(rt->remote_label)); json_object_int_add(json_remote_label, "inUse", rt->in_use); @@ -1394,16 +1378,14 @@ show_l2vpn_binding_msg_json(struct imsg *imsg, struct show_params *params, struct ctl_pw *pw; json_object *json_pw; char key_name[64]; - char buf[PREFIX_STRLEN]; switch (imsg->hdr.type) { case IMSG_CTL_SHOW_L2VPN_BINDING: pw = imsg->data; json_pw = json_object_new_object(); - json_object_string_add(json_pw, "destination", - inet_ntop(AF_INET, &pw->lsr_id, buf, - sizeof(buf))); + json_object_string_addf(json_pw, "destination", "%pI4", + &pw->lsr_id); json_object_int_add(json_pw, "vcId", pw->pwid); /* local binding */ @@ -1481,7 +1463,6 @@ show_l2vpn_pw_msg_json(struct imsg *imsg, struct show_params *params, json_object *json) { struct ctl_pw *pw; - char buf[PREFIX_STRLEN]; json_object *json_pw; switch (imsg->hdr.type) { @@ -1489,9 +1470,7 @@ show_l2vpn_pw_msg_json(struct imsg *imsg, struct show_params *params, pw = imsg->data; json_pw = json_object_new_object(); - json_object_string_add(json_pw, "peerId", - inet_ntop(AF_INET, &pw->lsr_id, - buf, sizeof(buf))); + json_object_string_addf(json_pw, "peerId", "%pI4", &pw->lsr_id); json_object_int_add(json_pw, "vcId", pw->pwid); json_object_string_add(json_pw, "VpnName", pw->l2vpn_name); if (pw->status == PW_FORWARDING) @@ -1865,9 +1844,7 @@ ldp_vty_dispatch(struct vty *vty, struct imsgbuf *ibuf, enum show_command cmd, done: close(ibuf->fd); if (json) { - vty_out (vty, "%s\n", - json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } return (ret); @@ -2027,9 +2004,7 @@ ldp_vty_show_capabilities(struct vty *vty, const char *json) "0x0603"); json_object_array_add(json_array, json_cap); - vty_out (vty, "%s\n", - json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); return (0); } diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 2d90412d17..059115915a 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -694,6 +694,16 @@ ldp_zebra_filter_update(struct access_list *access) extern struct zebra_privs_t ldpd_privs; +static zclient_handler *const ldp_handlers[] = { + [ZEBRA_ROUTER_ID_UPDATE] = ldp_router_id_update, + [ZEBRA_INTERFACE_ADDRESS_ADD] = ldp_interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = ldp_interface_address_delete, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ldp_zebra_read_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ldp_zebra_read_route, + [ZEBRA_PW_STATUS_UPDATE] = ldp_zebra_read_pw_status_update, + [ZEBRA_OPAQUE_MESSAGE] = ldp_zebra_opaque_msg_handler, +}; + void ldp_zebra_init(struct thread_master *master) { @@ -701,18 +711,12 @@ ldp_zebra_init(struct thread_master *master) ldp_ifp_down, ldp_ifp_destroy); /* Set default values. */ - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, ldp_handlers, + array_size(ldp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_LDP, 0, &ldpd_privs); /* set callbacks */ zclient->zebra_connected = ldp_zebra_connected; - zclient->router_id_update = ldp_router_id_update; - zclient->interface_address_add = ldp_interface_address_add; - zclient->interface_address_delete = ldp_interface_address_delete; - zclient->redistribute_route_add = ldp_zebra_read_route; - zclient->redistribute_route_del = ldp_zebra_read_route; - zclient->pw_status_update = ldp_zebra_read_pw_status_update; - zclient->opaque_msg_handler = ldp_zebra_opaque_msg_handler; /* Access list initialize. */ access_list_add_hook(ldp_zebra_filter_update); diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index 0ff3238ff9..6fa0e330f8 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -180,7 +180,7 @@ sigusr1(void) zlog_rotate(); } -static struct quagga_signal_t ldp_signals[] = +static struct frr_signal_t ldp_signals[] = { { .signal = SIGHUP, diff --git a/ldpd/ldpe.c b/ldpd/ldpe.c index fff7ee7c67..31f8026e3f 100644 --- a/ldpd/ldpe.c +++ b/ldpd/ldpe.c @@ -82,7 +82,7 @@ sigint(void) ldpe_shutdown(); } -static struct quagga_signal_t ldpe_signals[] = +static struct frr_signal_t ldpe_signals[] = { { .signal = SIGHUP, diff --git a/ldpd/ldpe.h b/ldpd/ldpe.h index 880722424e..0f650a86d3 100644 --- a/ldpd/ldpe.h +++ b/ldpd/ldpe.h @@ -30,9 +30,6 @@ #include "ldpd.h" #include "lib/ldp_sync.h" -#define min(x,y) ((x) <= (y) ? (x) : (y)) -#define max(x,y) ((x) > (y) ? (x) : (y)) - /* forward declarations */ TAILQ_HEAD(mapping_head, mapping_entry); diff --git a/lib/atomlist.c b/lib/atomlist.c index 8169ba9eb4..b7c9516a00 100644 --- a/lib/atomlist.c +++ b/lib/atomlist.c @@ -18,6 +18,8 @@ #include "config.h" #endif +#include <assert.h> + #include "atomlist.h" void atomlist_add_head(struct atomlist_head *h, struct atomlist_item *item) @@ -121,7 +123,7 @@ static void atomlist_del_core(struct atomlist_head *h, memory_order_consume); /* track the beginning of a chain of deleted items - * this is neccessary to make this lock-free; we can + * this is necessary to make this lock-free; we can * complete deletions started by other threads. */ if (!atomptr_l(prevval)) { diff --git a/lib/atomlist.h b/lib/atomlist.h index c795128a34..b0c4da4baa 100644 --- a/lib/atomlist.h +++ b/lib/atomlist.h @@ -100,7 +100,7 @@ static inline bool atomptr_u(atomptr_t val) /* single-linked list, unsorted/arbitrary. * can be used as queue with add_tail / pop * - * all operations are lock-free, but not neccessarily wait-free. this means + * all operations are lock-free, but not necessarily wait-free. this means * that there is no state where the system as a whole stops making process, * but it *is* possible that a *particular* thread is delayed by some time. * @@ -143,8 +143,8 @@ static struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, if (ifp == NULL) { if (bsglobal.debugging) zlog_debug( - "zebra_interface_bfd_read: Can't find interface by ifindex: %d ", - ifindex); + "%s: Can't find interface by ifindex: %d ", + __func__, ifindex); return NULL; } } @@ -203,7 +203,7 @@ static void bfd_last_update(time_t last_update, char *buf, size_t len) struct tm tm; struct timeval tv; - /* If no BFD satatus update has ever been received, print `never'. */ + /* If no BFD status update has ever been received, print `never'. */ if (last_update == 0) { snprintf(buf, len, "never"); return; @@ -251,8 +251,8 @@ void bfd_client_sendmsg(struct zclient *zclient, int command, if (ret == ZCLIENT_SEND_FAILURE) { if (bsglobal.debugging) zlog_debug( - "bfd_client_sendmsg %ld: zclient_send_message() failed", - (long)getpid()); + "%s: %ld: zclient_send_message() failed", + __func__, (long)getpid()); return; } @@ -552,7 +552,8 @@ static bool bfd_sess_address_changed(const struct bfd_session_params *bsp, } void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, - struct in_addr *src, struct in_addr *dst) + const struct in_addr *src, + const struct in_addr *dst) { if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src, (struct in6_addr *)dst)) @@ -576,10 +577,10 @@ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, } void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, - struct in6_addr *src, struct in6_addr *dst) + const struct in6_addr *src, + const struct in6_addr *dst) { - if (!bfd_sess_address_changed(bsp, AF_INET, (struct in6_addr *)src, - (struct in6_addr *)dst)) + if (!bfd_sess_address_changed(bsp, AF_INET6, src, dst)) return; /* If already installed, remove the old setting. */ @@ -645,32 +646,16 @@ void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id) bsp->args.vrf_id = vrf_id; } -void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl) -{ - assert(min_ttl != 0); - - if (bsp->args.ttl == ((BFD_SINGLE_HOP_TTL + 1) - min_ttl)) - return; - - /* If already installed, remove the old setting. */ - _bfd_sess_remove(bsp); - - /* Invert TTL value: protocol expects number of hops. */ - min_ttl = (BFD_SINGLE_HOP_TTL + 1) - min_ttl; - bsp->args.ttl = min_ttl; - bsp->args.mhop = (min_ttl > 1); -} - -void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl) +void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t hops) { - if (bsp->args.ttl == min_ttl) + if (bsp->args.ttl == hops) return; /* If already installed, remove the old setting. */ _bfd_sess_remove(bsp); - bsp->args.ttl = min_ttl; - bsp->args.mhop = (min_ttl > 1); + bsp->args.ttl = hops; + bsp->args.mhop = (hops > 1); } @@ -705,11 +690,6 @@ enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp) return bsp->bss.state; } -uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp) -{ - return ((BFD_SINGLE_HOP_TTL + 1) - bsp->args.ttl); -} - uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp) { return bsp->args.ttl; @@ -821,10 +801,13 @@ void bfd_sess_show(struct vty *vty, struct json_object *json, * * Use this as `zclient` `bfd_dest_replay` callback. */ -static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS) +int zclient_bfd_session_replay(ZAPI_CALLBACK_ARGS) { struct bfd_session_params *bsp; + if (!zclient->bfd_integration) + return 0; + /* Do nothing when shutting down. */ if (bsglobal.shutting_down) return 0; @@ -855,7 +838,7 @@ static int zclient_bfd_session_reply(ZAPI_CALLBACK_ARGS) return 0; } -static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) +int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) { struct bfd_session_params *bsp, *bspn; size_t sessions_updated = 0; @@ -868,6 +851,9 @@ static int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS) struct prefix sp; char ifstr[128], cbitstr[32]; + if (!zclient->bfd_integration) + return 0; + /* Do nothing when shutting down. */ if (bsglobal.shutting_down) return 0; @@ -969,9 +955,8 @@ void bfd_protocol_integration_init(struct zclient *zc, struct thread_master *tm) bsglobal.zc = zc; bsglobal.tm = tm; - /* Install our callbacks. */ - zc->interface_bfd_dest_update = zclient_bfd_session_update; - zc->bfd_dest_replay = zclient_bfd_session_reply; + /* Enable BFD callbacks. */ + zc->bfd_integration = true; /* Send the client registration */ bfd_client_sendmsg(zc, ZEBRA_BFD_CLIENT_REGISTER, VRF_DEFAULT); @@ -124,7 +124,8 @@ void bfd_sess_free(struct bfd_session_params **bsp); * \param dst remote address (mandatory). */ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, - struct in_addr *src, struct in_addr *dst); + const struct in_addr *src, + const struct in_addr *dst); /** * Set the local and peer address of the BFD session. @@ -138,7 +139,8 @@ void bfd_sess_set_ipv4_addrs(struct bfd_session_params *bsp, * \param dst remote address (mandatory). */ void bfd_sess_set_ipv6_addrs(struct bfd_session_params *bsp, - struct in6_addr *src, struct in6_addr *dst); + const struct in6_addr *src, + const struct in6_addr *dst); /** * Configure the BFD session interface. @@ -179,39 +181,14 @@ void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id); * Configure the BFD session single/multi hop setting. * * NOTE: - * If the TTL changed the session is removed and must be installed again - * with `bfd_sess_install`. + * If the number of hops is changed the session is removed and must be + * installed again with `bfd_sess_install`. * * \param bsp BFD session parameters. - * \param min_ttl minimum TTL value expected (255 for single hop, 254 for - * multi hop with single hop, 253 for multi hop with two hops - * and so on). See `BFD_SINGLE_HOP_TTL` and - * `BFD_MULTI_HOP_MIN_TTL` for defaults. - * - * To simplify things if your protocol only knows the amount of hops it is - * better to use `bfd_sess_set_hops` instead. + * \param hops maximum amount of hops expected (1 for single hop, 2 or + * more for multi hop). */ -void bfd_sess_set_mininum_ttl(struct bfd_session_params *bsp, uint8_t min_ttl); - -/** To use single hop the minimum TTL must be set to this. */ -#define BFD_SINGLE_HOP_TTL 255 -/** To use multi hop the minimum TTL must be set to this or less. */ -#define BFD_MULTI_HOP_MIN_TTL 254 - -/** - * This function is the inverted version of `bfd_sess_set_minimum_ttl`. - * Instead of receiving the minimum expected TTL, it receives the amount of - * hops the protocol will jump. - * - * NOTE: - * If the TTL changed the session is removed and must be installed again - * with `bfd_sess_install`. - * - * \param bsp BFD session parameters. - * \param min_ttl minimum amount of hops expected (1 for single hop, 2 or - * more for multi hop). - */ -void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t min_ttl); +void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t hops); /** * Configure the BFD session to set the Control Plane Independent bit. @@ -276,17 +253,7 @@ void bfd_sess_uninstall(struct bfd_session_params *bsp); enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp); /** - * Get BFD session minimum TTL configured value. - * - * \param bsp session parameters. - * - * \returns configured minimum TTL. - */ -uint8_t bfd_sess_minimum_ttl(const struct bfd_session_params *bsp); - -/** - * Inverted version of `bfd_sess_minimum_ttl`. Gets the amount of hops in the - * way to the peer. + * Get BFD session amount of hops configured value. * * \param bsp session parameters. * diff --git a/lib/buffer.c b/lib/buffer.c index 41b1adc9fc..e976fecc1f 100644 --- a/lib/buffer.c +++ b/lib/buffer.c @@ -59,7 +59,7 @@ struct buffer_data { /* It should always be true that: 0 <= sp <= cp <= size */ /* Default buffer size (used if none specified). It is rounded up to the - next page boundery. */ + next page boundary. */ #define BUFFER_SIZE_DEFAULT 4096 #define BUFFER_DATA_FREE(D) XFREE(MTYPE_BUFFER_DATA, (D)) diff --git a/lib/command.c b/lib/command.c index 53aa064705..9cf93ea192 100644 --- a/lib/command.c +++ b/lib/command.c @@ -86,6 +86,9 @@ vector cmdvec = NULL; /* Host information structure. */ struct host host; +/* for vtysh, put together CLI trees only when switching into node */ +static bool defer_cli_tree; + /* * Returns host.name if any, otherwise * it returns the system hostname. @@ -142,31 +145,6 @@ static struct cmd_node config_node = { .node_exit = vty_config_node_exit, }; -static bool vty_check_node_for_xpath_decrement(enum node_type target_node, - enum node_type node) -{ - /* bgp afi-safi (`address-family <afi> <safi>`) node - * does not increment xpath_index. - * In order to use (`router bgp`) BGP_NODE's xpath as a base, - * retain xpath_index as 1 upon exiting from - * afi-safi node. - */ - - if (target_node == BGP_NODE - && (node == BGP_IPV4_NODE || node == BGP_IPV6_NODE - || node == BGP_IPV4M_NODE || node == BGP_IPV6M_NODE - || node == BGP_VPNV4_NODE || node == BGP_VPNV6_NODE - || node == BGP_EVPN_NODE || node == BGP_IPV4L_NODE - || node == BGP_IPV6L_NODE || node == BGP_FLOWSPECV4_NODE - || node == BGP_FLOWSPECV6_NODE)) - return false; - - if (target_node == INTERFACE_NODE && node == LINK_PARAMS_NODE) - return false; - - return true; -} - /* This is called from main when a daemon is invoked with -v or --version. */ void print_version(const char *progname) { @@ -285,6 +263,11 @@ const char *cmd_prompt(enum node_type node) return cnode->prompt; } +void cmd_defer_tree(bool val) +{ + defer_cli_tree = val; +} + /* Install a command into a node. */ void _install_element(enum node_type ntype, const struct cmd_element *cmd) { @@ -319,20 +302,50 @@ void _install_element(enum node_type ntype, const struct cmd_element *cmd) assert(hash_get(cnode->cmd_hash, (void *)cmd, hash_alloc_intern)); + if (cnode->graph_built || !defer_cli_tree) { + struct graph *graph = graph_new(); + struct cmd_token *token = + cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL); + graph_new_node(graph, token, + (void (*)(void *)) & cmd_token_del); + + cmd_graph_parse(graph, cmd); + cmd_graph_names(graph); + cmd_graph_merge(cnode->cmdgraph, graph, +1); + graph_delete_graph(graph); + + cnode->graph_built = true; + } + + vector_set(cnode->cmd_vector, (void *)cmd); + + if (ntype == VIEW_NODE) + _install_element(ENABLE_NODE, cmd); +} + +static void cmd_finalize_iter(struct hash_bucket *hb, void *arg) +{ + struct cmd_node *cnode = arg; + const struct cmd_element *cmd = hb->data; struct graph *graph = graph_new(); struct cmd_token *token = cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL); + graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del); cmd_graph_parse(graph, cmd); cmd_graph_names(graph); cmd_graph_merge(cnode->cmdgraph, graph, +1); graph_delete_graph(graph); +} - vector_set(cnode->cmd_vector, (void *)cmd); +void cmd_finalize_node(struct cmd_node *cnode) +{ + if (cnode->graph_built) + return; - if (ntype == VIEW_NODE) - _install_element(ENABLE_NODE, cmd); + hash_iterate(cnode->cmd_hash, cmd_finalize_iter, cnode); + cnode->graph_built = true; } void uninstall_element(enum node_type ntype, const struct cmd_element *cmd) @@ -368,15 +381,18 @@ void uninstall_element(enum node_type ntype, const struct cmd_element *cmd) vector_unset_value(cnode->cmd_vector, (void *)cmd); - struct graph *graph = graph_new(); - struct cmd_token *token = - cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL); - graph_new_node(graph, token, (void (*)(void *)) & cmd_token_del); + if (cnode->graph_built) { + struct graph *graph = graph_new(); + struct cmd_token *token = + cmd_token_new(START_TKN, CMD_ATTR_NORMAL, NULL, NULL); + graph_new_node(graph, token, + (void (*)(void *)) & cmd_token_del); - cmd_graph_parse(graph, cmd); - cmd_graph_names(graph); - cmd_graph_merge(cnode->cmdgraph, graph, -1); - graph_delete_graph(graph); + cmd_graph_parse(graph, cmd); + cmd_graph_names(graph); + cmd_graph_merge(cnode->cmdgraph, graph, -1); + graph_delete_graph(graph); + } if (ntype == VIEW_NODE) uninstall_element(ENABLE_NODE, cmd); @@ -503,6 +519,8 @@ static int config_write_host(struct vty *vty) static struct graph *cmd_node_graph(vector v, enum node_type ntype) { struct cmd_node *cnode = vector_slot(v, ntype); + + cmd_finalize_node(cnode); return cnode->cmdgraph; } @@ -879,13 +897,15 @@ static int cmd_execute_command_real(vector vline, enum cmd_filter_type filter, * a match before calling node_exit handlers below */ for (i = 0; i < up_level; i++) { + struct cmd_node *cnode; + if (node <= CONFIG_NODE) return CMD_NO_LEVEL_UP; + cnode = vector_slot(cmdvec, node); node = node_parent(node); - if (xpath_index > 0 - && vty_check_node_for_xpath_decrement(node, vty->node)) + if (xpath_index > 0 && !cnode->no_xpath) xpath_index--; } @@ -1019,12 +1039,13 @@ int cmd_execute_command(vector vline, struct vty *vty, /* This assumes all nodes above CONFIG_NODE are childs of * CONFIG_NODE */ while (vty->node > CONFIG_NODE) { + struct cmd_node *cnode = vector_slot(cmdvec, try_node); + try_node = node_parent(try_node); vty->node = try_node; - if (vty->xpath_index > 0 - && vty_check_node_for_xpath_decrement(try_node, - onode)) + if (vty->xpath_index > 0 && !cnode->no_xpath) vty->xpath_index--; + ret = cmd_execute_command_real(vline, FILTER_RELAXED, vty, cmd, 0); if (ret == CMD_SUCCESS || ret == CMD_WARNING @@ -1343,8 +1364,7 @@ void cmd_exit(struct vty *vty) } if (cnode->parent_node) vty->node = cnode->parent_node; - if (vty->xpath_index > 0 - && vty_check_node_for_xpath_decrement(vty->node, cnode->node)) + if (vty->xpath_index > 0 && !cnode->no_xpath) vty->xpath_index--; } @@ -1506,9 +1526,10 @@ int cmd_list_cmds(struct vty *vty, int do_permute) { struct cmd_node *node = vector_slot(cmdvec, vty->node); - if (do_permute) + if (do_permute) { + cmd_finalize_node(node); permute(vector_slot(node->cmdgraph->nodes, 0), vty); - else { + } else { /* loop over all commands at this node */ const struct cmd_element *element = NULL; for (unsigned int i = 0; i < vector_active(node->cmd_vector); @@ -1551,7 +1572,10 @@ DEFUN_HIDDEN(show_cli_graph, "Dump current command space as DOT graph\n") { struct cmd_node *cn = vector_slot(cmdvec, vty->node); - char *dot = cmd_graph_dump_dot(cn->cmdgraph); + char *dot; + + cmd_finalize_node(cn); + dot = cmd_graph_dump_dot(cn->cmdgraph); vty_out(vty, "%s\n", dot); XFREE(MTYPE_TMP, dot); diff --git a/lib/command.h b/lib/command.h index 8a7c9a2048..c888356d61 100644 --- a/lib/command.h +++ b/lib/command.h @@ -210,6 +210,12 @@ struct cmd_node { /* Hashed index of command node list, for de-dupping primarily */ struct hash *cmd_hash; + + /* set as soon as any command is in cmdgraph */ + bool graph_built; + + /* don't decrement vty->xpath_index on leaving this node */ + bool no_xpath; }; /* Return value of the commands. */ @@ -234,7 +240,7 @@ struct cmd_node { /* Argc max counts. */ #define CMD_ARGC_MAX 256 -/* Turn off these macros when uisng cpp with extract.pl */ +/* Turn off these macros when using cpp with extract.pl */ #ifndef VTYSH_EXTRACT_PL /* helper defines for end-user DEFUN* macros */ @@ -526,6 +532,12 @@ extern void _install_element(enum node_type, const struct cmd_element *); * deprecated/hidden) are not reversed. */ extern void uninstall_element(enum node_type, const struct cmd_element *); +/* construct CLI tree only when entering nodes */ +extern void cmd_defer_tree(bool val); + +/* finish CLI tree for node when above is true (noop otherwise) */ +extern void cmd_finalize_node(struct cmd_node *node); + /* Concatenates argv[shift] through argv[argc-1] into a single NUL-terminated string with a space between each element (allocated using XMALLOC(MTYPE_TMP)). Returns NULL if shift >= argc. */ diff --git a/lib/command_graph.c b/lib/command_graph.c index 15c8302e63..09d802e796 100644 --- a/lib/command_graph.c +++ b/lib/command_graph.c @@ -77,16 +77,17 @@ struct cmd_token *cmd_token_dup(struct cmd_token *token) return copy; } -void cmd_token_varname_set(struct cmd_token *token, const char *varname) +static void cmd_token_varname_do(struct cmd_token *token, const char *varname, + uint8_t varname_src) { - XFREE(MTYPE_CMD_VAR, token->varname); - if (!varname) { - token->varname = NULL; + if (token->varname_src >= varname_src) return; - } + + XFREE(MTYPE_CMD_VAR, token->varname); size_t len = strlen(varname), i; token->varname = XMALLOC(MTYPE_CMD_VAR, len + 1); + token->varname_src = varname_src; for (i = 0; i < len; i++) switch (varname[i]) { @@ -102,6 +103,80 @@ void cmd_token_varname_set(struct cmd_token *token, const char *varname) token->varname[len] = '\0'; } +void cmd_token_varname_set(struct cmd_token *token, const char *varname) +{ + if (varname) { + cmd_token_varname_do(token, varname, VARNAME_EXPLICIT); + return; + } + if (token->type == VARIABLE_TKN) { + if (strcmp(token->text, "WORD") && strcmp(token->text, "NAME")) + cmd_token_varname_do(token, token->text, VARNAME_TEXT); + } +} + +static void cmd_token_varname_fork(struct graph_node *node, + struct cmd_token *prevtoken) +{ + for (size_t i = 0; i < vector_active(node->to); i++) { + struct graph_node *next = vector_slot(node->to, i); + struct cmd_token *nexttoken = next->data; + + if (nexttoken->type == FORK_TKN) { + cmd_token_varname_fork(next, prevtoken); + continue; + } + if (nexttoken->varname) + continue; + if (!IS_VARYING_TOKEN(nexttoken->type)) + continue; + + cmd_token_varname_do(nexttoken, prevtoken->text, VARNAME_TEXT); + } +} + +void cmd_token_varname_join(struct graph_node *join, const char *varname) +{ + if (!varname) + return; + + for (size_t i = 0; i < vector_active(join->from); i++) { + struct graph_node *prev = vector_slot(join->from, i); + struct cmd_token *token = prev->data; + + if (token->type == JOIN_TKN) + cmd_token_varname_join(prev, varname); + else if (token->type < SPECIAL_TKN) + cmd_token_varname_do(token, varname, VARNAME_EXPLICIT); + } +} + +void cmd_token_varname_seqappend(struct graph_node *node) +{ + struct graph_node *prevnode = node; + struct cmd_token *token = node->data; + struct cmd_token *prevtoken; + + if (token->type == WORD_TKN) + return; + + do { + if (vector_active(prevnode->from) != 1) + return; + + prevnode = vector_slot(prevnode->from, 0); + prevtoken = prevnode->data; + } while (prevtoken->type == FORK_TKN); + + if (prevtoken->type != WORD_TKN) + return; + + if (token->type == FORK_TKN) + cmd_token_varname_fork(node, prevtoken); + else + cmd_token_varname_do(token, prevtoken->text, VARNAME_TEXT); +} + static bool cmd_nodes_link(struct graph_node *from, struct graph_node *to) { for (size_t i = 0; i < vector_active(from->to); i++) @@ -357,72 +432,6 @@ void cmd_graph_merge(struct graph *old, struct graph *new, int direction) vector_slot(new->nodes, 0), direction); } -static void cmd_node_names(struct graph_node *gn, struct graph_node *join, - const char *prevname) -{ - size_t i; - struct cmd_token *tok = gn->data, *jointok; - struct graph_node *stop = cmd_loopstop(gn); - - switch (tok->type) { - case WORD_TKN: - prevname = tok->text; - break; - - case VARIABLE_TKN: - if (!tok->varname && strcmp(tok->text, "WORD") - && strcmp(tok->text, "NAME")) - cmd_token_varname_set(tok, tok->text); - /* fallthrough */ - case RANGE_TKN: - case IPV4_TKN: - case IPV4_PREFIX_TKN: - case IPV6_TKN: - case IPV6_PREFIX_TKN: - case MAC_TKN: - case MAC_PREFIX_TKN: - if (!tok->varname && prevname) - cmd_token_varname_set(tok, prevname); - prevname = NULL; - break; - - case START_TKN: - case JOIN_TKN: - case NEG_ONLY_TKN: - /* "<foo|bar> WORD" -> word is not "bar" or "foo" */ - prevname = NULL; - break; - - case FORK_TKN: - /* apply "<A.B.C.D|X:X::X:X>$name" */ - jointok = tok->forkjoin->data; - if (!jointok->varname) - break; - for (i = 0; i < vector_active(tok->forkjoin->from); i++) { - struct graph_node *tail = - vector_slot(tok->forkjoin->from, i); - struct cmd_token *tailtok = tail->data; - if (tail == gn || tailtok->varname) - continue; - cmd_token_varname_set(tailtok, jointok->varname); - } - break; - - case END_TKN: - return; - } - - for (i = 0; i < vector_active(gn->to); i++) { - struct graph_node *next = vector_slot(gn->to, i); - if (next == stop || next == join) - continue; - cmd_node_names(next, join, prevname); - } - - if (tok->type == FORK_TKN && tok->forkjoin != join) - cmd_node_names(tok->forkjoin, join, NULL); -} - void cmd_graph_names(struct graph *graph) { struct graph_node *start; @@ -451,12 +460,10 @@ void cmd_graph_names(struct graph *graph) struct cmd_token *tok1 = next1->data; /* the other one needs to be "no" (only one will match here) */ if ((tok0->type == WORD_TKN && !strcmp(tok0->text, "no"))) - cmd_token_varname_set(tok0, "no"); + cmd_token_varname_do(tok0, "no", VARNAME_AUTO); if ((tok1->type == WORD_TKN && !strcmp(tok1->text, "no"))) - cmd_token_varname_set(tok1, "no"); + cmd_token_varname_do(tok1, "no", VARNAME_AUTO); } while (0); - - cmd_node_names(start, NULL, NULL); } #ifndef BUILDING_CLIPPY diff --git a/lib/command_graph.h b/lib/command_graph.h index 86157f872e..ed4da6aa4c 100644 --- a/lib/command_graph.h +++ b/lib/command_graph.h @@ -79,11 +79,20 @@ enum { CMD_ATTR_NORMAL, CMD_ATTR_YANG, }; +enum varname_src { + VARNAME_NONE = 0, + VARNAME_AUTO, + VARNAME_VAR, + VARNAME_TEXT, + VARNAME_EXPLICIT, +}; + /* Command token struct. */ struct cmd_token { enum cmd_token_type type; // token type uint8_t attr; // token attributes bool allowrepeat; // matcher allowed to match token repetitively? + uint8_t varname_src; uint32_t refcnt; char *text; // token text @@ -119,6 +128,8 @@ extern struct cmd_token *cmd_token_new(enum cmd_token_type, uint8_t attr, extern struct cmd_token *cmd_token_dup(struct cmd_token *); extern void cmd_token_del(struct cmd_token *); extern void cmd_token_varname_set(struct cmd_token *token, const char *varname); +extern void cmd_token_varname_seqappend(struct graph_node *n); +extern void cmd_token_varname_join(struct graph_node *n, const char *varname); extern void cmd_graph_parse(struct graph *graph, const struct cmd_element *cmd); extern void cmd_graph_names(struct graph *graph); diff --git a/lib/command_match.h b/lib/command_match.h index fcb333120f..0488cc1a1f 100644 --- a/lib/command_match.h +++ b/lib/command_match.h @@ -68,7 +68,7 @@ enum match_type { * @param[in] vline vectorized input string * @param[out] argv pointer to argument list if successful match, NULL * otherwise. The elements of this list are pointers to struct cmd_token - * and represent the sequence of tokens matched by the inpu. The ->arg + * and represent the sequence of tokens matched by the input. The ->arg * field of each token points to a copy of the input matched on it. These * may be safely deleted or modified. * @param[out] element pointer to matched cmd_element if successful match, diff --git a/lib/command_parse.y b/lib/command_parse.y index 3e2cdc79af..35c119691b 100644 --- a/lib/command_parse.y +++ b/lib/command_parse.y @@ -217,10 +217,12 @@ cmd_token: { if ((ctx->currnode = graph_add_edge (ctx->currnode, $1)) != $1) graph_delete_node (ctx->graph, $1); + cmd_token_varname_seqappend($1); } | selector { graph_add_edge (ctx->currnode, $1.start); + cmd_token_varname_seqappend($1.start); ctx->currnode = $1.end; } ; @@ -295,9 +297,8 @@ placeholder_token_real: placeholder_token: placeholder_token_real varname_token { - struct cmd_token *token = $$->data; $$ = $1; - cmd_token_varname_set (token, $2); + cmd_token_varname_set ($$->data, $2); XFREE (MTYPE_LEX, $2); }; @@ -306,7 +307,7 @@ placeholder_token: selector: '<' selector_seq_seq '>' varname_token { $$ = $2; - cmd_token_varname_set ($2.end->data, $4); + cmd_token_varname_join ($2.end, $4); XFREE (MTYPE_LEX, $4); }; @@ -338,11 +339,11 @@ selector: '{' selector_seq_seq '}' varname_token * 1) this allows "at least 1 of" semantics, which are otherwise impossible * 2) this would add a start->end->start loop in the graph that the current * loop-avoidal fails to handle - * just use [{a|b}] if neccessary, that will work perfectly fine, and reason + * just use [{a|b}] if necessary, that will work perfectly fine, and reason * #1 is good enough to keep it this way. */ loopcheck(ctx, &$$); - cmd_token_varname_set ($2.end->data, $4); + cmd_token_varname_join ($2.end, $4); XFREE (MTYPE_LEX, $4); }; @@ -359,6 +360,7 @@ selector_token_seq: selector_token_seq selector_token { graph_add_edge ($1.end, $2.start); + cmd_token_varname_seqappend($2.start); $$.start = $1.start; $$.end = $2.end; } @@ -370,7 +372,7 @@ selector: '[' selector_seq_seq ']' varname_token { $$ = $2; graph_add_edge ($$.start, $$.end); - cmd_token_varname_set ($2.end->data, $4); + cmd_token_varname_join ($2.end, $4); XFREE (MTYPE_LEX, $4); } ; @@ -383,7 +385,7 @@ selector: EXCL_BRACKET selector_seq_seq ']' varname_token $$ = $2; graph_add_edge ($$.start, neg_only); graph_add_edge (neg_only, $$.end); - cmd_token_varname_set ($2.end->data, $4); + cmd_token_varname_join ($2.end, $4); XFREE (MTYPE_LEX, $4); } ; @@ -60,7 +60,7 @@ int db_init(const char *path_fmt, ...) (SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE), NULL) != SQLITE_OK) { if (dbp == NULL) { - zlog_warn("%s: failed to open dabatase '%s'", __func__, + zlog_warn("%s: failed to open database '%s'", __func__, path); return -1; } diff --git a/lib/distribute.h b/lib/distribute.h index 83682dea6a..6b3226e8b4 100644 --- a/lib/distribute.h +++ b/lib/distribute.h @@ -29,7 +29,7 @@ extern "C" { #endif -/* Disctirubte list types. */ +/* Distribute list types. */ enum distribute_type { DISTRIBUTE_V4_IN, DISTRIBUTE_V6_IN, diff --git a/lib/elf_py.c b/lib/elf_py.c index 1c306893ad..f230add695 100644 --- a/lib/elf_py.c +++ b/lib/elf_py.c @@ -636,6 +636,9 @@ static Elf_Scn *elf_find_addr(struct elffile *ef, uint64_t addr, size_t *idx) Elf_Scn *scn = elf_getscn(ef->elf, i); GElf_Shdr _shdr, *shdr = gelf_getshdr(scn, &_shdr); + /* virtual address is kinda meaningless for TLS sections */ + if (shdr->sh_flags & SHF_TLS) + continue; if (addr < shdr->sh_addr || addr >= shdr->sh_addr + shdr->sh_size) continue; diff --git a/lib/ferr.c b/lib/ferr.c index 513ef5ebec..e5b6d7552d 100644 --- a/lib/ferr.c +++ b/lib/ferr.c @@ -157,13 +157,7 @@ void log_ref_display(struct vty *vty, uint32_t code, bool json) } } - if (json) { - const char *str = json_object_to_json_string_ext( - top, JSON_C_TO_STRING_PRETTY); - vty_out(vty, "%s\n", str); - json_object_free(top); - } - + vty_json(vty, top); list_delete(&errlist); } diff --git a/lib/ferr.h b/lib/ferr.h index 4e95431cea..c27601f66c 100644 --- a/lib/ferr.h +++ b/lib/ferr.h @@ -34,7 +34,7 @@ extern "C" { /* return type when this error indication stuff is used. * * guaranteed to have boolean evaluation to "false" when OK, "true" when error - * (i.e. can be changed to pointer in the future if neccessary) + * (i.e. can be changed to pointer in the future if necessary) * * For checking, always use "if (value)", nothing else. * Do _NOT_ use any integer constant (!= 0), or sign check (< 0). diff --git a/lib/filter.c b/lib/filter.c index 744ea9c480..fc4b578e77 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -192,7 +192,7 @@ void access_list_delete(struct access_list *access) access_list_free(access); } -/* Insert new access list to list of access_list. Each acceess_list +/* Insert new access list to list of access_list. Each access_list is sorted by the name. */ static struct access_list *access_list_insert(afi_t afi, const char *name) { @@ -387,7 +387,7 @@ void access_list_filter_add(struct access_list *access, struct filter *replace; struct filter *point; - /* Automatic asignment of seq no. */ + /* Automatic assignment of seq no. */ if (filter->seq == -1) filter->seq = filter_new_seq_get(access); @@ -558,18 +558,12 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi, json_rule); else { if (json) { - char buf[BUFSIZ]; - - json_object_string_add( - json_rule, "address", - inet_ntop(AF_INET, - &filter->addr, buf, - sizeof(buf))); - json_object_string_add( - json_rule, "mask", - inet_ntop(AF_INET, - &filter->addr_mask, - buf, sizeof(buf))); + json_object_string_addf( + json_rule, "address", "%pI4", + &filter->addr); + json_object_string_addf( + json_rule, "mask", "%pI4", + &filter->addr_mask); } else { if (filter->addr_mask.s_addr == 0xffffffff) @@ -589,14 +583,7 @@ static int filter_show(struct vty *vty, const char *name, afi_t afi, } } - if (json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } - - return CMD_SUCCESS; + return vty_json(vty, json); } /* show MAC access list - this only has MAC filters for now*/ @@ -612,7 +599,7 @@ DEFUN (show_mac_access_list, DEFUN (show_mac_access_list_name, show_mac_access_list_name_cmd, - "show mac access-list WORD", + "show mac access-list ACCESSLIST_MAC_NAME", SHOW_STR "mac access lists\n" "List mac access lists\n" @@ -635,15 +622,11 @@ DEFUN (show_ip_access_list, DEFUN (show_ip_access_list_name, show_ip_access_list_name_cmd, - "show ip access-list <(1-99)|(100-199)|(1300-1999)|(2000-2699)|WORD> [json]", + "show ip access-list ACCESSLIST4_NAME [json]", SHOW_STR IP_STR "List IP access lists\n" - "IP standard access list\n" - "IP extended access list\n" - "IP standard access list (expanded range)\n" - "IP extended access list (expanded range)\n" - "IP zebra access-list\n" + "IP access-list name\n" JSON_STR) { bool uj = use_json(argc, argv); @@ -665,11 +648,11 @@ DEFUN (show_ipv6_access_list, DEFUN (show_ipv6_access_list_name, show_ipv6_access_list_name_cmd, - "show ipv6 access-list WORD [json]", + "show ipv6 access-list ACCESSLIST6_NAME [json]", SHOW_STR IPV6_STR "List IPv6 access lists\n" - "IPv6 zebra access-list\n" + "IPv6 access-list name\n" JSON_STR) { bool uj = use_json(argc, argv); @@ -685,21 +668,15 @@ static void config_write_access_cisco(struct vty *vty, struct filter *mfilter, filter = &mfilter->u.cfilter; if (json) { - char buf[BUFSIZ]; - json_object_boolean_add(json, "extended", !!filter->extended); - json_object_string_add( - json, "sourceAddress", - inet_ntop(AF_INET, &filter->addr, buf, sizeof(buf))); - json_object_string_add(json, "sourceMask", - inet_ntop(AF_INET, &filter->addr_mask, - buf, sizeof(buf))); - json_object_string_add( - json, "destinationAddress", - inet_ntop(AF_INET, &filter->mask, buf, sizeof(buf))); - json_object_string_add(json, "destinationMask", - inet_ntop(AF_INET, &filter->mask_mask, - buf, sizeof(buf))); + json_object_string_addf(json, "sourceAddress", "%pI4", + &filter->addr); + json_object_string_addf(json, "sourceMask", "%pI4", + &filter->addr_mask); + json_object_string_addf(json, "destinationAddress", "%pI4", + &filter->mask); + json_object_string_addf(json, "destinationMask", "%pI4", + &filter->mask_mask); } else { vty_out(vty, " ip"); if (filter->addr_mask.s_addr == 0xffffffff) @@ -734,16 +711,13 @@ static void config_write_access_zebra(struct vty *vty, struct filter *mfilter, p = &filter->prefix; if (json) { - json_object_string_add(json, "prefix", - prefix2str(p, buf, sizeof(buf))); + json_object_string_addf(json, "prefix", "%pFX", p); json_object_boolean_add(json, "exact-match", !!filter->exact); } else { if (p->prefixlen == 0 && !filter->exact) vty_out(vty, " any"); else if (p->family == AF_INET6 || p->family == AF_INET) - vty_out(vty, " %s/%d%s", - inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), - p->prefixlen, + vty_out(vty, " %pFX%s", p, filter->exact ? " exact-match" : ""); else if (p->family == AF_ETHERNET) { if (p->prefixlen == 0) @@ -843,12 +817,62 @@ static void access_list_init_ipv4(void) install_element(ENABLE_NODE, &show_ip_access_list_name_cmd); } +static void access_list_autocomplete_afi(afi_t afi, vector comps, + struct cmd_token *token) +{ + struct access_list *access; + struct access_list *next; + struct access_master *master; + + master = access_master_get(afi); + if (master == NULL) + return; + + for (access = master->str.head; access; access = next) { + next = access->next; + vector_set(comps, XSTRDUP(MTYPE_COMPLETION, access->name)); + } +} + static struct cmd_node access_ipv6_node = { .name = "ipv6 access list", .node = ACCESS_IPV6_NODE, .prompt = "", }; +static void access_list_autocomplete(vector comps, struct cmd_token *token) +{ + access_list_autocomplete_afi(AFI_IP, comps, token); + access_list_autocomplete_afi(AFI_IP6, comps, token); + access_list_autocomplete_afi(AFI_L2VPN, comps, token); +} + +static void access_list4_autocomplete(vector comps, struct cmd_token *token) +{ + access_list_autocomplete_afi(AFI_IP, comps, token); +} + +static void access_list6_autocomplete(vector comps, struct cmd_token *token) +{ + access_list_autocomplete_afi(AFI_IP6, comps, token); +} + +static void access_list_mac_autocomplete(vector comps, struct cmd_token *token) +{ + access_list_autocomplete_afi(AFI_L2VPN, comps, token); +} + +static const struct cmd_variable_handler access_list_handlers[] = { + {.tokenname = "ACCESSLIST_NAME", + .completions = access_list_autocomplete}, + {.tokenname = "ACCESSLIST4_NAME", + .completions = access_list4_autocomplete}, + {.tokenname = "ACCESSLIST6_NAME", + .completions = access_list6_autocomplete}, + {.tokenname = "ACCESSLIST_MAC_NAME", + .completions = access_list_mac_autocomplete}, + {.completions = NULL}}; + static void access_list_reset_ipv6(void) { struct access_list *access; @@ -878,6 +902,8 @@ static void access_list_init_ipv6(void) void access_list_init(void) { + cmd_variable_handler_register(access_list_handlers); + access_list_init_ipv4(); access_list_init_ipv6(); access_list_init_mac(); diff --git a/lib/filter.h b/lib/filter.h index d1956ec019..b378288c58 100644 --- a/lib/filter.h +++ b/lib/filter.h @@ -234,15 +234,19 @@ bool plist_is_dup(const struct lyd_node *dnode, struct plist_dup_args *pda); struct lyd_node; struct vty; -extern int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); -extern void access_list_show(struct vty *vty, struct lyd_node *dnode, +extern int access_list_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2); +extern void access_list_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -extern void access_list_remark_show(struct vty *vty, struct lyd_node *dnode, +extern void access_list_remark_show(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -extern int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); -extern void prefix_list_show(struct vty *vty, struct lyd_node *dnode, +extern int prefix_list_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2); +extern void prefix_list_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -extern void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode, +extern void prefix_list_remark_show(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); void filter_cli_init(void); diff --git a/lib/filter_cli.c b/lib/filter_cli.c index 45c7544a3b..fb40c527dd 100644 --- a/lib/filter_cli.c +++ b/lib/filter_cli.c @@ -36,10 +36,7 @@ #endif /* VTYSH_EXTRACT_PL */ #define ACCESS_LIST_STR "Access list entry\n" -#define ACCESS_LIST_LEG_STR "IP standard access list\n" -#define ACCESS_LIST_ELEG_STR "IP extended access list\n" -#define ACCESS_LIST_ELEG_EXT_STR "IP extended access list (expanded range)\n" -#define ACCESS_LIST_ZEBRA_STR "Access list entry\n" +#define ACCESS_LIST_ZEBRA_STR "Access list name\n" #define ACCESS_LIST_SEQ_STR \ "Sequence number of an entry\n" \ "Sequence number\n" @@ -137,7 +134,7 @@ DEFPY_YANG( access_list_std, access_list_std_cmd, "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>", ACCESS_LIST_STR - ACCESS_LIST_LEG_STR + ACCESS_LIST_ZEBRA_STR ACCESS_LIST_SEQ_STR ACCESS_LIST_ACTION_STR "A single host address\n" @@ -214,7 +211,7 @@ DEFPY_YANG( "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <[host] A.B.C.D$host|A.B.C.D$host A.B.C.D$mask>", NO_STR ACCESS_LIST_STR - ACCESS_LIST_LEG_STR + ACCESS_LIST_ZEBRA_STR ACCESS_LIST_SEQ_STR ACCESS_LIST_ACTION_STR "A single host address\n" @@ -258,7 +255,7 @@ DEFPY_YANG( access_list_ext, access_list_ext_cmd, "access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>", ACCESS_LIST_STR - ACCESS_LIST_ELEG_STR + ACCESS_LIST_ZEBRA_STR ACCESS_LIST_SEQ_STR ACCESS_LIST_ACTION_STR "IPv4 address\n" @@ -377,7 +374,7 @@ DEFPY_YANG( "no access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action ip <A.B.C.D$src A.B.C.D$src_mask|host A.B.C.D$src|any> <A.B.C.D$dst A.B.C.D$dst_mask|host A.B.C.D$dst|any>", NO_STR ACCESS_LIST_STR - ACCESS_LIST_ELEG_STR + ACCESS_LIST_ZEBRA_STR ACCESS_LIST_SEQ_STR ACCESS_LIST_ACTION_STR "Any Internet Protocol\n" @@ -825,7 +822,7 @@ DEFPY_YANG( ALIAS( no_ipv6_access_list_remark, no_ipv6_access_list_remark_line_cmd, - "no ipv6 access-list WORD$name remark LINE...", + "no ipv6 access-list ACCESSLIST6_NAME$name remark LINE...", NO_STR IPV6_STR ACCESS_LIST_STR @@ -835,7 +832,7 @@ ALIAS( DEFPY_YANG( mac_access_list, mac_access_list_cmd, - "mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", + "mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", MAC_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -901,7 +898,7 @@ DEFPY_YANG( DEFPY_YANG( no_mac_access_list, no_mac_access_list_cmd, - "no mac access-list WORD$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", + "no mac access-list ACCESSLIST_MAC_NAME$name [seq (1-4294967295)$seq] <deny|permit>$action <X:X:X:X:X:X$mac|any>", NO_STR MAC_STR ACCESS_LIST_STR @@ -941,7 +938,7 @@ DEFPY_YANG( DEFPY_YANG( no_mac_access_list_all, no_mac_access_list_all_cmd, - "no mac access-list WORD$name", + "no mac access-list ACCESSLIST_MAC_NAME$name", NO_STR MAC_STR ACCESS_LIST_STR @@ -958,7 +955,7 @@ DEFPY_YANG( DEFPY_YANG( mac_access_list_remark, mac_access_list_remark_cmd, - "mac access-list WORD$name remark LINE...", + "mac access-list ACCESSLIST_MAC_NAME$name remark LINE...", MAC_STR ACCESS_LIST_STR ACCESS_LIST_ZEBRA_STR @@ -983,7 +980,7 @@ DEFPY_YANG( DEFPY_YANG( no_mac_access_list_remark, no_mac_access_list_remark_cmd, - "no mac access-list WORD$name remark", + "no mac access-list ACCESSLIST_MAC_NAME$name remark", NO_STR MAC_STR ACCESS_LIST_STR @@ -1007,7 +1004,7 @@ DEFPY_YANG( ALIAS( no_mac_access_list_remark, no_mac_access_list_remark_line_cmd, - "no mac access-list WORD$name remark LINE...", + "no mac access-list ACCESSLIST_MAC_NAME$name remark LINE...", NO_STR MAC_STR ACCESS_LIST_STR @@ -1015,7 +1012,8 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) -int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +int access_list_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence"); uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence"); @@ -1023,7 +1021,7 @@ int access_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) return seq1 - seq2; } -void access_list_show(struct vty *vty, struct lyd_node *dnode, +void access_list_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { int type = yang_dnode_get_enum(dnode, "../type"); @@ -1137,7 +1135,7 @@ void access_list_show(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void access_list_remark_show(struct vty *vty, struct lyd_node *dnode, +void access_list_remark_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { int type = yang_dnode_get_enum(dnode, "../type"); @@ -1658,7 +1656,8 @@ ALIAS( ACCESS_LIST_REMARK_STR ACCESS_LIST_REMARK_LINE_STR) -int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +int prefix_list_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { uint32_t seq1 = yang_dnode_get_uint32(dnode1, "./sequence"); uint32_t seq2 = yang_dnode_get_uint32(dnode2, "./sequence"); @@ -1666,7 +1665,7 @@ int prefix_list_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) return seq1 - seq2; } -void prefix_list_show(struct vty *vty, struct lyd_node *dnode, +void prefix_list_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { int type = yang_dnode_get_enum(dnode, "../type"); @@ -1725,7 +1724,7 @@ void prefix_list_show(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "\n"); } -void prefix_list_remark_show(struct vty *vty, struct lyd_node *dnode, +void prefix_list_remark_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { int type = yang_dnode_get_enum(dnode, "../type"); diff --git a/lib/frr_zmq.c b/lib/frr_zmq.c index 4e947a8a84..e572558de1 100644 --- a/lib/frr_zmq.c +++ b/lib/frr_zmq.c @@ -19,7 +19,7 @@ /* * IF YOU MODIFY THIS FILE PLEASE RUN `make check` and ensure that - * the test_zmq.c unit test is still working. There are dependancies + * the test_zmq.c unit test is still working. There are dependencies * between the two that are extremely fragile. My understanding * is that there is specialized ownership of the cb pointer based * upon what is happening. Those assumptions are supposed to be diff --git a/lib/frrcu.h b/lib/frrcu.h index 3808259040..ae840926b5 100644 --- a/lib/frrcu.h +++ b/lib/frrcu.h @@ -17,6 +17,8 @@ #ifndef _FRRCU_H #define _FRRCU_H +#include <assert.h> + #include "memory.h" #include "atomlist.h" diff --git a/lib/frrlua.c b/lib/frrlua.c index 00491568f6..535649eff2 100644 --- a/lib/frrlua.c +++ b/lib/frrlua.c @@ -223,6 +223,21 @@ void *lua_toin6addr(lua_State *L, int idx) return in6addr; } +void lua_pushipaddr(lua_State *L, const struct ipaddr *addr) +{ + if (IS_IPADDR_V4(addr)) + lua_pushinaddr(L, &addr->ipaddr_v4); + else + lua_pushin6addr(L, &addr->ipaddr_v6); +} + +void lua_pushethaddr(lua_State *L, const struct ethaddr *addr) +{ + lua_newtable(L); + lua_pushinteger(L, *(addr->octet)); + lua_setfield(L, -2, "octet"); +} + void lua_pushsockunion(lua_State *L, const union sockunion *su) { char buf[SU_ADDRSTRLEN]; @@ -297,6 +312,58 @@ void *lua_tointegerp(lua_State *L, int idx) return num; } +void lua_pushnexthop(lua_State *L, const struct nexthop *nexthop) +{ + lua_newtable(L); + lua_pushinteger(L, nexthop->vrf_id); + lua_setfield(L, -2, "vrf_id"); + lua_pushinteger(L, nexthop->ifindex); + lua_setfield(L, -2, "ifindex"); + lua_pushinteger(L, nexthop->type); + lua_setfield(L, -2, "type"); + lua_pushinteger(L, nexthop->flags); + lua_setfield(L, -2, "flags"); + if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { + lua_pushinteger(L, nexthop->bh_type); + lua_setfield(L, -2, "bh_type"); + } else if (nexthop->type == NEXTHOP_TYPE_IPV4) { + lua_pushinaddr(L, &nexthop->gate.ipv4); + lua_setfield(L, -2, "gate"); + } else if (nexthop->type == NEXTHOP_TYPE_IPV6) { + lua_pushin6addr(L, &nexthop->gate.ipv6); + lua_setfield(L, -2, "gate"); + } + lua_pushinteger(L, nexthop->nh_label_type); + lua_setfield(L, -2, "nh_label_type"); + lua_pushinteger(L, nexthop->weight); + lua_setfield(L, -2, "weight"); + lua_pushinteger(L, nexthop->backup_num); + lua_setfield(L, -2, "backup_num"); + lua_pushinteger(L, *(nexthop->backup_idx)); + lua_setfield(L, -2, "backup_idx"); + if (nexthop->nh_encap_type == NET_VXLAN) { + lua_pushinteger(L, nexthop->nh_encap.vni); + lua_setfield(L, -2, "vni"); + } + lua_pushinteger(L, nexthop->nh_encap_type); + lua_setfield(L, -2, "nh_encap_type"); + lua_pushinteger(L, nexthop->srte_color); + lua_setfield(L, -2, "srte_color"); +} + +void lua_pushnexthop_group(lua_State *L, const struct nexthop_group *ng) +{ + lua_newtable(L); + struct nexthop *nexthop; + int i = 0; + + for (ALL_NEXTHOPS_PTR(ng, nexthop)) { + lua_pushnexthop(L, nexthop); + lua_seti(L, -2, i); + i++; + } +} + void lua_decode_stringp(lua_State *L, int idx, char *str) { strlcpy(str, lua_tostring(L, idx), strlen(str) + 1); diff --git a/lib/frrlua.h b/lib/frrlua.h index 3e16c82e22..a82009a779 100644 --- a/lib/frrlua.h +++ b/lib/frrlua.h @@ -100,6 +100,10 @@ void lua_pushin6addr(lua_State *L, const struct in6_addr *addr); void lua_decode_in6addr(lua_State *L, int idx, struct in6_addr *addr); +void lua_pushipaddr(lua_State *L, const struct ipaddr *addr); + +void lua_pushethaddr(lua_State *L, const struct ethaddr *addr); + /* * Converts the Lua value at idx to an in6_addr. * @@ -138,6 +142,10 @@ void lua_decode_sockunion(lua_State *L, int idx, union sockunion *su); */ void *lua_tosockunion(lua_State *L, int idx); +void lua_pushnexthop_group(lua_State *L, const struct nexthop_group *ng); + +void lua_pushnexthop(lua_State *L, const struct nexthop *nexthop); + /* * Converts an int to a Lua value and pushes it on the stack. */ diff --git a/lib/frrscript.c b/lib/frrscript.c index 0e0d3c030c..4fee79991a 100644 --- a/lib/frrscript.c +++ b/lib/frrscript.c @@ -32,6 +32,96 @@ DEFINE_MTYPE_STATIC(LIB, SCRIPT, "Scripting"); +/* + * Script name hash utilities + */ + +struct frrscript_names_head frrscript_names_hash; + +/* + * Wrapper for frrscript_names_add + * Use this to register hook calls when a daemon starts up + */ +int frrscript_names_add_function_name(const char *function_name) +{ + struct frrscript_names_entry *insert = + XCALLOC(MTYPE_SCRIPT, sizeof(*insert)); + strlcpy(insert->function_name, function_name, + sizeof(insert->function_name)); + + if (frrscript_names_add(&frrscript_names_hash, insert)) { + zlog_warn( + "Failed to add hook call function name to script_names"); + return 1; + } + return 0; +} + +void frrscript_names_destroy(void) +{ + struct frrscript_names_entry *ne; + + while ((ne = frrscript_names_pop(&frrscript_names_hash))) + XFREE(MTYPE_SCRIPT, ne); +} + +/* + * Given a function_name, set its script_name. function_names and script_names + * are one-to-one. Each set will wipe the previous script_name. + * Return 0 if set was successful, else 1. + * + * script_name is the base name of the file, without .lua. + */ +int frrscript_names_set_script_name(const char *function_name, + const char *script_name) +{ + struct frrscript_names_entry lookup; + + strlcpy(lookup.function_name, function_name, + sizeof(lookup.function_name)); + struct frrscript_names_entry *snhe = + frrscript_names_find(&frrscript_names_hash, &lookup); + if (!snhe) + return 1; + strlcpy(snhe->script_name, script_name, sizeof(snhe->script_name)); + return 0; +} + +/* + * Given a function_name, get its script_name. + * Return NULL if function_name not found. + * + * script_name is the base name of the file, without .lua. + */ +char *frrscript_names_get_script_name(const char *function_name) +{ + struct frrscript_names_entry lookup; + + strlcpy(lookup.function_name, function_name, + sizeof(lookup.function_name)); + struct frrscript_names_entry *snhe = + frrscript_names_find(&frrscript_names_hash, &lookup); + if (!snhe) + return NULL; + + if (snhe->script_name[0] == '\0') + return NULL; + + return snhe->script_name; +} + +uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe) +{ + return string_hash_make(snhe->function_name); +} + +int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1, + const struct frrscript_names_entry *snhe2) +{ + return strncmp(snhe1->function_name, snhe2->function_name, + sizeof(snhe1->function_name)); +} + /* Codecs */ struct frrscript_codec frrscript_codecs_lib[] = { @@ -226,7 +316,7 @@ void *frrscript_get_result(struct frrscript *fs, const char *function_name, p = lua_to(lfs->L, 2); /* At the end, the Lua state should be same as it was at the start - * i.e. containing soley the returned table. + * i.e. containing solely the returned table. */ assert(lua_gettop(lfs->L) == 1); assert(lua_istable(lfs->L, -1) == 1); diff --git a/lib/frrscript.h b/lib/frrscript.h index c089df61fc..4db3e6f1b2 100644 --- a/lib/frrscript.h +++ b/lib/frrscript.h @@ -24,6 +24,8 @@ #ifdef HAVE_SCRIPTING #include <lua.h> +#include <nexthop.h> +#include <nexthop_group.h> #include "frrlua.h" #include "bgpd/bgp_script.h" // for peer and attr encoders/decoders @@ -31,6 +33,43 @@ extern "C" { #endif +/* Forward declarations */ +extern struct zebra_dplane_ctx ctx; +extern void lua_pushzebra_dplane_ctx(lua_State *L, + const struct zebra_dplane_ctx *ctx); +extern void lua_decode_zebra_dplane_ctx(lua_State *L, int idx, + struct zebra_dplane_ctx *ctx); + +/* + * Script name hash + */ +PREDECL_HASH(frrscript_names); + +struct frrscript_names_entry { + /* Name of a Lua hook call */ + char function_name[MAXPATHLEN]; + + /* Lua script in which to look for it */ + char script_name[MAXPATHLEN]; + + struct frrscript_names_item item; +}; + +extern struct frrscript_names_head frrscript_names_hash; + +int frrscript_names_hash_cmp(const struct frrscript_names_entry *snhe1, + const struct frrscript_names_entry *snhe2); +uint32_t frrscript_names_hash_key(const struct frrscript_names_entry *snhe); + +DECLARE_HASH(frrscript_names, struct frrscript_names_entry, item, + frrscript_names_hash_cmp, frrscript_names_hash_key); + +int frrscript_names_add_function_name(const char *function_name); +void frrscript_names_destroy(void); +int frrscript_names_set_script_name(const char *function_name, + const char *script_name); +char *frrscript_names_get_script_name(const char *function_name); + typedef void (*encoder_func)(lua_State *, const void *); typedef void *(*decoder_func)(lua_State *, int); @@ -171,7 +210,12 @@ time_t * : lua_pushtimet, \ char * : lua_pushstring_wrapper, \ struct attr * : lua_pushattr, \ struct peer * : lua_pushpeer, \ -const struct prefix * : lua_pushprefix \ +const struct prefix * : lua_pushprefix, \ +const struct ipaddr * : lua_pushipaddr, \ +const struct ethaddr * : lua_pushethaddr, \ +const struct nexthop_group * : lua_pushnexthop_group, \ +const struct nexthop * : lua_pushnexthop, \ +struct zebra_dplane_ctx * : lua_pushzebra_dplane_ctx \ )((L), (value)) #define DECODE_ARGS_WITH_STATE(L, value) \ @@ -187,7 +231,12 @@ time_t * : lua_decode_timet, \ char * : lua_decode_stringp, \ struct attr * : lua_decode_attr, \ struct peer * : lua_decode_noop, \ -const struct prefix * : lua_decode_noop \ +const struct prefix * : lua_decode_noop, \ +const struct ipaddr * : lua_decode_noop, \ +const struct ethaddr * : lua_decode_noop, \ +const struct nexthop_group * : lua_decode_noop, \ +const struct nexthop * : lua_decode_noop, \ +struct zebra_dplane_ctx * : lua_decode_noop \ )((L), -1, (value)) /* diff --git a/lib/grammar_sandbox.c b/lib/grammar_sandbox.c index 209765bd6f..f9778c5d4c 100644 --- a/lib/grammar_sandbox.c +++ b/lib/grammar_sandbox.c @@ -395,6 +395,7 @@ DEFUN (grammar_findambig, vector_slot(cmdvec, scannode++); if (!cnode) continue; + cmd_finalize_node(cnode); nodegraph = cnode->cmdgraph; if (!nodegraph) continue; @@ -466,6 +467,7 @@ DEFUN (grammar_access, } vty_out(vty, "node %d\n", (int)cnode->node); + cmd_finalize_node(cnode); nodegraph = cnode->cmdgraph; return CMD_SUCCESS; } diff --git a/lib/graph.c b/lib/graph.c index 1cbe1b90f9..ba7314fb25 100644 --- a/lib/graph.c +++ b/lib/graph.c @@ -69,7 +69,7 @@ static void graph_vector_remove(vector v, unsigned int ix) * and v->active is > ix. */ v->active--; /* if ix == v->active--, we set the item to itself, then to NULL... - * still correct, no check neccessary. */ + * still correct, no check necessary. */ v->index[ix] = v->index[v->active]; v->index[v->active] = NULL; } diff --git a/lib/hash.h b/lib/hash.h index 47d951a34b..f3b24f051b 100644 --- a/lib/hash.h +++ b/lib/hash.h @@ -161,7 +161,7 @@ hash_create_size(unsigned int size, unsigned int (*hash_key)(const void *), * an element from its key, you must provide the data item itself, with the * portions used in the hash function set to the same values as the data item * to retrieve. To insert a data element, either provide the key as just - * described and provide alloc_func as descrbied below to allocate the full + * described and provide alloc_func as described below to allocate the full * data element, or provide the full data element and pass 'hash_alloc_intern' * to alloc_func. * diff --git a/lib/hook.h b/lib/hook.h index 3a0db6009b..d75e623edc 100644 --- a/lib/hook.h +++ b/lib/hook.h @@ -193,7 +193,7 @@ extern void _hook_unregister(struct hook *hook, void *funcptr, void *arg, * usage: DECLARE_HOOK(my_hook, (int arg1, struct foo *arg2), (arg1, arg2)); * as above, "passlist" must use the same order and same names as "arglist" * - * theoretically passlist is not neccessary, but let's keep things simple and + * theoretically passlist is not necessary, but let's keep things simple and * use exact same args on DECLARE and DEFINE. */ #define DECLARE_HOOK(hookname, arglist, passlist) \ @@ -45,8 +45,10 @@ DEFINE_MTYPE_STATIC(LIB, NBR_CONNECTED, "Neighbor Connected"); DEFINE_MTYPE(LIB, CONNECTED_LABEL, "Connected interface label"); DEFINE_MTYPE_STATIC(LIB, IF_LINK_PARAMS, "Informational Link Parameters"); +static void if_set_name(struct interface *ifp, const char *name); static struct interface *if_lookup_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); +static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex); static int if_cmp_func(const struct interface *, const struct interface *); static int if_cmp_index_func(const struct interface *ifp1, const struct interface *ifp2); @@ -153,16 +155,18 @@ static void ifp_connected_free(void *arg) } /* Create new interface structure. */ -static struct interface *if_new(vrf_id_t vrf_id) +static struct interface *if_new(struct vrf *vrf) { struct interface *ifp; + assert(vrf); + ifp = XCALLOC(MTYPE_IF, sizeof(struct interface)); ifp->ifindex = IFINDEX_INTERNAL; ifp->name[0] = '\0'; - ifp->vrf_id = vrf_id; + ifp->vrf = vrf; ifp->connected = list_new(); ifp->connected->del = ifp_connected_free; @@ -207,11 +211,11 @@ void if_down_via_zapi(struct interface *ifp) (*ifp_master.down_hook)(ifp); } -struct interface *if_create_name(const char *name, vrf_id_t vrf_id) +static struct interface *if_create_name(const char *name, struct vrf *vrf) { struct interface *ifp; - ifp = if_new(vrf_id); + ifp = if_new(vrf); if_set_name(ifp, name); @@ -219,71 +223,28 @@ struct interface *if_create_name(const char *name, vrf_id_t vrf_id) return ifp; } -struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) -{ - struct interface *ifp; - - ifp = if_new(vrf_id); - - if_set_index(ifp, ifindex); - - hook_call(if_add, ifp); - return ifp; -} - /* Create new interface structure. */ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id) { struct vrf *old_vrf, *vrf; /* remove interface from old master vrf list */ - old_vrf = vrf_lookup_by_id(ifp->vrf_id); - if (old_vrf) { - if (ifp->name[0] != '\0') - IFNAME_RB_REMOVE(old_vrf, ifp); + old_vrf = ifp->vrf; - if (ifp->ifindex != IFINDEX_INTERNAL) - IFINDEX_RB_REMOVE(old_vrf, ifp); - } + if (ifp->name[0] != '\0') + IFNAME_RB_REMOVE(old_vrf, ifp); - ifp->vrf_id = vrf_id; - vrf = vrf_get(ifp->vrf_id, NULL); + if (ifp->ifindex != IFINDEX_INTERNAL) + IFINDEX_RB_REMOVE(old_vrf, ifp); + + vrf = vrf_get(vrf_id, NULL); + ifp->vrf = vrf; if (ifp->name[0] != '\0') IFNAME_RB_INSERT(vrf, ifp); if (ifp->ifindex != IFINDEX_INTERNAL) IFINDEX_RB_INSERT(vrf, ifp); - - /* - * HACK: Change the interface VRF in the running configuration directly, - * bypassing the northbound layer. This is necessary to avoid deleting - * the interface and readding it in the new VRF, which would have - * several implications. - */ - if (yang_module_find("frr-interface")) { - struct lyd_node *if_dnode; - char oldpath[XPATH_MAXLEN]; - char newpath[XPATH_MAXLEN]; - - snprintf(oldpath, sizeof(oldpath), - "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifp->name, old_vrf->name); - snprintf(newpath, sizeof(newpath), - "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifp->name, vrf->name); - - if_dnode = yang_dnode_getf(running_config->dnode, "%s/vrf", - oldpath); - - if (if_dnode) { - yang_dnode_change_leaf(if_dnode, vrf->name); - nb_running_move_tree(oldpath, newpath); - running_config->version++; - } - - vty_update_xpath(oldpath, newpath); - } } @@ -304,10 +265,7 @@ void if_delete_retain(struct interface *ifp) void if_delete(struct interface **ifp) { struct interface *ptr = *ifp; - struct vrf *vrf; - - vrf = vrf_lookup_by_id(ptr->vrf_id); - assert(vrf); + struct vrf *vrf = ptr->vrf; IFNAME_RB_REMOVE(vrf, ptr); if (ptr->ifindex != IFINDEX_INTERNAL) @@ -341,7 +299,7 @@ static struct interface *if_lookup_by_ifindex(ifindex_t ifindex, return RB_FIND(if_index_head, &vrf->ifaces_by_index, &if_tmp); } -/* Interface existance check by index. */ +/* Interface existence check by index. */ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id) { switch (vrf_get_backend()) { @@ -354,7 +312,7 @@ struct interface *if_lookup_by_index(ifindex_t ifindex, vrf_id_t vrf_id) return NULL; } -/* Interface existance check by index. */ +/* Interface existence check by index. */ struct interface *if_vrf_lookup_by_index_next(ifindex_t ifindex, vrf_id_t vrf_id) { @@ -406,7 +364,7 @@ ifindex_t ifname2ifindex(const char *name, vrf_id_t vrf_id) : IFINDEX_INTERNAL; } -/* Interface existance check by interface name. */ +/* Interface existence check by interface name. */ struct interface *if_lookup_by_name(const char *name, vrf_id_t vrf_id) { struct vrf *vrf = vrf_lookup_by_id(vrf_id); @@ -431,7 +389,7 @@ struct interface *if_lookup_by_name_vrf(const char *name, struct vrf *vrf) return RB_FIND(if_name_head, &vrf->ifaces_by_name, &if_tmp); } -struct interface *if_lookup_by_name_all_vrf(const char *name) +static struct interface *if_lookup_by_name_all_vrf(const char *name) { struct vrf *vrf; struct interface *ifp; @@ -439,8 +397,8 @@ struct interface *if_lookup_by_name_all_vrf(const char *name) if (!name || strnlen(name, INTERFACE_NAMSIZ) == INTERFACE_NAMSIZ) return NULL; - RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { - ifp = if_lookup_by_name(name, vrf->vrf_id); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + ifp = if_lookup_by_name_vrf(name, vrf); if (ifp) return ifp; } @@ -448,7 +406,7 @@ struct interface *if_lookup_by_name_all_vrf(const char *name) return NULL; } -struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) +static struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) { struct vrf *vrf; struct interface *ifp; @@ -465,36 +423,51 @@ struct interface *if_lookup_by_index_all_vrf(ifindex_t ifindex) return NULL; } -/* Lookup interface by IP address. */ -struct interface *if_lookup_exact_address(const void *src, int family, +/* Lookup interface by IP address. + * + * supersedes if_lookup_exact_address(), which didn't care about up/down + * state. but all users we have either only care if the address is local + * (=> use if_address_is_local() please), or care about UP interfaces before + * anything else + * + * to accept only UP interfaces, check if_is_up() on the returned ifp. + */ +struct interface *if_lookup_address_local(const void *src, int family, vrf_id_t vrf_id) { struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct listnode *cnode; - struct interface *ifp; + struct interface *ifp, *best_down = NULL; struct prefix *p; struct connected *c; + if (family != AF_INET && family != AF_INET6) + return NULL; + FOR_ALL_INTERFACES (vrf, ifp) { for (ALL_LIST_ELEMENTS_RO(ifp->connected, cnode, c)) { p = c->address; - if (p && (p->family == family)) { - if (family == AF_INET) { - if (IPV4_ADDR_SAME( - &p->u.prefix4, + if (!p || p->family != family) + continue; + + if (family == AF_INET) { + if (!IPV4_ADDR_SAME(&p->u.prefix4, (struct in_addr *)src)) - return ifp; - } else if (family == AF_INET6) { - if (IPV6_ADDR_SAME( - &p->u.prefix6, + continue; + } else if (family == AF_INET6) { + if (!IPV6_ADDR_SAME(&p->u.prefix6, (struct in6_addr *)src)) - return ifp; - } + continue; } + + if (if_is_up(ifp)) + return ifp; + if (!best_down) + best_down = ifp; } } - return NULL; + return best_down; } /* Lookup interface by IP address. */ @@ -582,81 +555,67 @@ size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz, /* Get interface by name if given name interface doesn't exist create one. */ -struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id) +struct interface *if_get_by_name(const char *name, vrf_id_t vrf_id, + const char *vrf_name) { - struct interface *ifp; + struct interface *ifp = NULL; + struct vrf *vrf; switch (vrf_get_backend()) { case VRF_BACKEND_UNKNOWN: case VRF_BACKEND_NETNS: - ifp = if_lookup_by_name(name, vrf_id); - if (ifp) - return ifp; - return if_create_name(name, vrf_id); - case VRF_BACKEND_VRF_LITE: - ifp = if_lookup_by_name_all_vrf(name); + vrf = vrf_get(vrf_id, vrf_name); + assert(vrf); + + ifp = if_lookup_by_name_vrf(name, vrf); if (ifp) { - if (ifp->vrf_id == vrf_id) - return ifp; /* If it came from the kernel or by way of zclient, * believe it and update the ifp accordingly. */ - if_update_to_new_vrf(ifp, vrf_id); + if (ifp->vrf->vrf_id != vrf_id && vrf_id != VRF_UNKNOWN) + if_update_to_new_vrf(ifp, vrf_id); + return ifp; } - return if_create_name(name, vrf_id); - } - return NULL; -} - -struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id) -{ - struct interface *ifp; - - switch (vrf_get_backend()) { - case VRF_BACKEND_UNKNOWN: - case VRF_BACKEND_NETNS: - ifp = if_lookup_by_ifindex(ifindex, vrf_id); - if (ifp) - return ifp; - return if_create_ifindex(ifindex, vrf_id); + break; case VRF_BACKEND_VRF_LITE: - ifp = if_lookup_by_index_all_vrf(ifindex); + ifp = if_lookup_by_name_all_vrf(name); if (ifp) { - if (ifp->vrf_id == vrf_id) - return ifp; /* If it came from the kernel or by way of zclient, * believe it and update the ifp accordingly. */ - if_update_to_new_vrf(ifp, vrf_id); + if (ifp->vrf->vrf_id != vrf_id && vrf_id != VRF_UNKNOWN) + if_update_to_new_vrf(ifp, vrf_id); + return ifp; } - return if_create_ifindex(ifindex, vrf_id); + + vrf = vrf_get(vrf_id, vrf_name); + assert(vrf); + + break; + default: + return NULL; } - return NULL; + return if_create_name(name, vrf); } int if_set_index(struct interface *ifp, ifindex_t ifindex) { - struct vrf *vrf; - if (ifp->ifindex == ifindex) return 0; - vrf = vrf_get(ifp->vrf_id, NULL); - assert(vrf); - /* * If there is already an interface with this ifindex, we will collide * on insertion, so don't even try. */ - if (if_lookup_by_ifindex(ifindex, ifp->vrf_id)) + if (if_lookup_by_ifindex(ifindex, ifp->vrf->vrf_id)) return -1; if (ifp->ifindex != IFINDEX_INTERNAL) - IFINDEX_RB_REMOVE(vrf, ifp); + IFINDEX_RB_REMOVE(ifp->vrf, ifp); ifp->ifindex = ifindex; @@ -666,30 +625,25 @@ int if_set_index(struct interface *ifp, ifindex_t ifindex) * already an interface with the desired ifindex at the top of * the function. Nevertheless. */ - if (IFINDEX_RB_INSERT(vrf, ifp)) + if (IFINDEX_RB_INSERT(ifp->vrf, ifp)) return -1; } return 0; } -void if_set_name(struct interface *ifp, const char *name) +static void if_set_name(struct interface *ifp, const char *name) { - struct vrf *vrf; - - vrf = vrf_get(ifp->vrf_id, NULL); - assert(vrf); - if (if_cmp_name_func(ifp->name, name) == 0) return; if (ifp->name[0] != '\0') - IFNAME_RB_REMOVE(vrf, ifp); + IFNAME_RB_REMOVE(ifp->vrf, ifp); strlcpy(ifp->name, name, sizeof(ifp->name)); if (ifp->name[0] != '\0') - IFNAME_RB_INSERT(vrf, ifp); + IFNAME_RB_INSERT(ifp->vrf, ifp); } /* Does interface up ? */ @@ -727,7 +681,7 @@ int if_is_no_ptm_operative(const struct interface *ifp) } /* Is this loopback interface ? */ -int if_is_loopback(const struct interface *ifp) +int if_is_loopback_exact(const struct interface *ifp) { /* XXX: Do this better, eg what if IFF_WHATEVER means X on platform M * but Y on platform N? @@ -741,9 +695,10 @@ int if_is_vrf(const struct interface *ifp) return CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_VRF_LOOPBACK); } -bool if_is_loopback_or_vrf(const struct interface *ifp) +/* Should this interface be treated as a loopback? */ +bool if_is_loopback(const struct interface *ifp) { - if (if_is_loopback(ifp) || if_is_vrf(ifp)) + if (if_is_loopback_exact(ifp) || if_is_vrf(ifp)) return true; return false; @@ -817,15 +772,12 @@ static void if_dump(const struct interface *ifp) struct listnode *node; struct connected *c __attribute__((unused)); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c)) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c)) zlog_info( "Interface %s vrf %s(%u) index %d metric %d mtu %d mtu6 %d %s", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, - ifp->metric, ifp->mtu, ifp->mtu6, + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, ifp->metric, ifp->mtu, ifp->mtu6, if_flag_dump(ifp->flags)); - } } /* Interface printing for all interface. */ @@ -894,16 +846,14 @@ connected_log(struct connected *connected, char *str) { struct prefix *p; struct interface *ifp; - struct vrf *vrf; char logbuf[BUFSIZ]; char buf[BUFSIZ]; ifp = connected->ifp; p = connected->address; - vrf = vrf_lookup_by_id(ifp->vrf_id); snprintf(logbuf, sizeof(logbuf), "%s interface %s vrf %s(%u) %s %pFX ", - str, ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, + str, ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, prefix_family_str(p), p); p = connected->destination; @@ -1059,30 +1009,15 @@ struct connected *connected_get_linklocal(struct interface *ifp) void if_terminate(struct vrf *vrf) { struct interface *ifp; - bool delete; - - /* - * If the default VRF is being terminated or has - * already been terminated it means that - * the program is shutting down and we need to - * delete all the interfaces. Otherwise, we only - * need to move VRF's interfaces to the default VRF. - */ - delete = vrf_is_backend_netns() || vrf->vrf_id == VRF_DEFAULT - || !vrf_lookup_by_id(VRF_DEFAULT); while (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) { ifp = RB_ROOT(if_name_head, &vrf->ifaces_by_name); - if (delete) { - if (ifp->node) { - ifp->node->info = NULL; - route_unlock_node(ifp->node); - } - if_delete(&ifp); - } else { - if_update_to_new_vrf(ifp, VRF_DEFAULT); + if (ifp->node) { + ifp->node->info = NULL; + route_unlock_node(ifp->node); } + if_delete(&ifp); } } @@ -1108,6 +1043,8 @@ const char *if_link_type_str(enum zebra_link_type llt) llts(ZEBRA_LLT_CSLIP, "Compressed SLIP"); llts(ZEBRA_LLT_SLIP6, "SLIPv6"); llts(ZEBRA_LLT_CSLIP6, "Compressed SLIPv6"); + llts(ZEBRA_LLT_RSRVD, "Reserved"); + llts(ZEBRA_LLT_ADAPT, "Adapt"); llts(ZEBRA_LLT_ROSE, "ROSE packet radio"); llts(ZEBRA_LLT_X25, "CCITT X.25"); llts(ZEBRA_LLT_PPP, "PPP"); @@ -1124,8 +1061,10 @@ const char *if_link_type_str(enum zebra_link_type llt) llts(ZEBRA_LLT_SIT, "IPv6-in-IPv4 SIT"); llts(ZEBRA_LLT_IPDDP, "IP-in-DDP tunnel"); llts(ZEBRA_LLT_IPGRE, "GRE over IP"); + llts(ZEBRA_LLT_IP6GRE, "GRE over IPv6"); llts(ZEBRA_LLT_PIMREG, "PIMSM registration"); llts(ZEBRA_LLT_HIPPI, "HiPPI"); + llts(ZEBRA_LLT_ECONET, "Acorn Econet"); llts(ZEBRA_LLT_IRDA, "IrDA"); llts(ZEBRA_LLT_FCPP, "Fibre-Channel PtP"); llts(ZEBRA_LLT_FCAL, "Fibre-Channel Arbitrated Loop"); @@ -1136,9 +1075,6 @@ const char *if_link_type_str(enum zebra_link_type llt) llts(ZEBRA_LLT_IEEE80211_RADIOTAP, "IEEE 802.11 Radiotap"); llts(ZEBRA_LLT_IEEE802154, "IEEE 802.15.4"); llts(ZEBRA_LLT_IEEE802154_PHY, "IEEE 802.15.4 Phy"); - default: - flog_err(EC_LIB_DEVELOPMENT, "Unknown value %d", llt); - return "Unknown type!"; #undef llts } return NULL; @@ -1185,6 +1121,25 @@ void if_link_params_free(struct interface *ifp) /* ----------- CLI commands ----------- */ +/* Guess the VRF of an interface. */ +static int vrfname_by_ifname(const char *ifname, const char **vrfname) +{ + struct vrf *vrf; + struct interface *ifp; + int count = 0; + + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + FOR_ALL_INTERFACES (vrf, ifp) { + if (strmatch(ifp->name, ifname)) { + *vrfname = vrf->name; + count++; + } + } + } + + return count; +} + /* * XPath: /frr-interface:lib/interface */ @@ -1196,50 +1151,30 @@ DEFPY_YANG_NOSH (interface, VRF_CMD_HELP_STR) { char xpath_list[XPATH_MAXLEN]; - vrf_id_t vrf_id; struct interface *ifp; - int ret; - - if (!vrf_name) - vrf_name = VRF_DEFAULT_NAME; - - /* - * This command requires special handling to maintain backward - * compatibility. If a VRF name is not specified, it means we're willing - * to accept any interface with the given name on any VRF. If no - * interface is found, then a new one should be created on the default - * VRF. - */ - VRF_GET_ID(vrf_id, vrf_name, false); - ifp = if_lookup_by_name_all_vrf(ifname); - if (ifp && ifp->vrf_id != vrf_id) { - struct vrf *vrf; + struct vrf *vrf; + int ret, count; + if (vrf_is_backend_netns()) { /* - * Special case 1: a VRF name was specified, but the found - * interface is associated to different VRF. Reject the command. + * For backward compatibility, if the VRF name is not specified + * and there is exactly one interface with this name in the + * system, use its VRF. Otherwise fallback to the default VRF. */ - if (vrf_id != VRF_DEFAULT) { - vty_out(vty, "%% interface %s not in %s vrf\n", ifname, - vrf_name); - return CMD_WARNING_CONFIG_FAILED; + if (!vrf_name) { + count = vrfname_by_ifname(ifname, &vrf_name); + if (count != 1) + vrf_name = VRF_DEFAULT_NAME; } - /* - * Special case 2: a VRF name was *not* specified, and the found - * interface is associated to a VRF other than the default one. - * Update vrf_id and vrf_name to account for that. - */ - vrf = vrf_lookup_by_id(ifp->vrf_id); - assert(vrf); - vrf_id = ifp->vrf_id; - vrf_name = vrf->name; + snprintf(xpath_list, XPATH_MAXLEN, + "/frr-interface:lib/interface[name='%s:%s']", vrf_name, + ifname); + } else { + snprintf(xpath_list, XPATH_MAXLEN, + "/frr-interface:lib/interface[name='%s']", ifname); } - snprintf(xpath_list, sizeof(xpath_list), - "/frr-interface:lib/interface[name='%s'][vrf='%s']", ifname, - vrf_name); - nb_cli_enqueue_change(vty, ".", NB_OP_CREATE, NULL); ret = nb_cli_apply_changes_clear_pending(vty, xpath_list); if (ret == CMD_SUCCESS) { @@ -1251,7 +1186,15 @@ DEFPY_YANG_NOSH (interface, * all interface-level commands are converted to the new * northbound model. */ - ifp = if_lookup_by_name(ifname, vrf_id); + if (vrf_is_backend_netns()) { + vrf = vrf_lookup_by_name(vrf_name); + if (vrf) + ifp = if_lookup_by_name_vrf(ifname, vrf); + else + ifp = NULL; + } else { + ifp = if_lookup_by_name_all_vrf(ifname); + } if (ifp) VTY_PUSH_CONTEXT(INTERFACE_NODE, ifp); } @@ -1267,31 +1210,77 @@ DEFPY_YANG (no_interface, "Interface's name\n" VRF_CMD_HELP_STR) { - if (!vrf_name) - vrf_name = VRF_DEFAULT_NAME; + char xpath_list[XPATH_MAXLEN]; + int count; + + if (vrf_is_backend_netns()) { + /* + * For backward compatibility, if the VRF name is not specified + * and there is exactly one interface with this name in the + * system, use its VRF. Otherwise fallback to the default VRF. + */ + if (!vrf_name) { + count = vrfname_by_ifname(ifname, &vrf_name); + if (count != 1) + vrf_name = VRF_DEFAULT_NAME; + } + + snprintf(xpath_list, XPATH_MAXLEN, + "/frr-interface:lib/interface[name='%s:%s']", vrf_name, + ifname); + } else { + snprintf(xpath_list, XPATH_MAXLEN, + "/frr-interface:lib/interface[name='%s']", ifname); + } nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes( - vty, "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifname, vrf_name); + return nb_cli_apply_changes(vty, xpath_list); } -static void cli_show_interface(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) +static void netns_ifname_split(const char *xpath, char *ifname, char *vrfname) { - const char *vrf; + char *delim; + int len; - vrf = yang_dnode_get_string(dnode, "./vrf"); + assert(vrf_is_backend_netns()); + delim = strchr(xpath, ':'); + assert(delim); + + len = delim - xpath; + memcpy(vrfname, xpath, len); + vrfname[len] = 0; + + strlcpy(ifname, delim + 1, XPATH_MAXLEN); +} + +static void cli_show_interface(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) +{ vty_out(vty, "!\n"); - vty_out(vty, "interface %s", yang_dnode_get_string(dnode, "./name")); - if (!strmatch(vrf, VRF_DEFAULT_NAME)) - vty_out(vty, " vrf %s", vrf); + + if (vrf_is_backend_netns()) { + char ifname[XPATH_MAXLEN]; + char vrfname[XPATH_MAXLEN]; + + netns_ifname_split(yang_dnode_get_string(dnode, "./name"), + ifname, vrfname); + + vty_out(vty, "interface %s", ifname); + if (!strmatch(vrfname, VRF_DEFAULT_NAME)) + vty_out(vty, " vrf %s", vrfname); + } else { + const char *ifname = yang_dnode_get_string(dnode, "./name"); + + vty_out(vty, "interface %s", ifname); + } + vty_out(vty, "\n"); } -static void cli_show_interface_end(struct vty *vty, struct lyd_node *dnode) +static void cli_show_interface_end(struct vty *vty, + const struct lyd_node *dnode) { vty_out(vty, "exit\n"); } @@ -1327,8 +1316,9 @@ DEFPY_YANG (no_interface_desc, return nb_cli_apply_changes(vty, NULL); } -static void cli_show_interface_desc(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) +static void cli_show_interface_desc(struct vty *vty, + const struct lyd_node *dnode, + bool show_defaults) { vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL)); } @@ -1361,6 +1351,20 @@ static struct cmd_node interface_node = { .prompt = "%s(config-if)# ", }; +static int if_config_write_single(const struct lyd_node *dnode, void *arg) +{ + nb_cli_show_dnode_cmds(arg, dnode, false); + + return YANG_ITER_CONTINUE; +} + +static int if_nb_config_write(struct vty *vty) +{ + yang_dnode_iterate(if_config_write_single, vty, running_config->dnode, + "/frr-interface:lib/interface"); + return 1; +} + void if_cmd_init(int (*config_write)(struct vty *)) { cmd_variable_handler_register(if_var_handlers); @@ -1376,6 +1380,11 @@ void if_cmd_init(int (*config_write)(struct vty *)) install_element(INTERFACE_NODE, &no_interface_desc_cmd); } +void if_cmd_init_default(void) +{ + if_cmd_init(if_nb_config_write); +} + void if_zapi_callbacks(int (*create)(struct interface *ifp), int (*up)(struct interface *ifp), int (*down)(struct interface *ifp), @@ -1395,37 +1404,35 @@ void if_zapi_callbacks(int (*create)(struct interface *ifp), static int lib_interface_create(struct nb_cb_create_args *args) { const char *ifname; - const char *vrfname; - struct vrf *vrf; struct interface *ifp; ifname = yang_dnode_get_string(args->dnode, "./name"); - vrfname = yang_dnode_get_string(args->dnode, "./vrf"); switch (args->event) { case NB_EV_VALIDATE: - vrf = vrf_lookup_by_name(vrfname); - if (!vrf) { - zlog_warn("%s: VRF %s doesn't exist", __func__, - vrfname); - return NB_ERR_VALIDATION; - } - if (vrf->vrf_id == VRF_UNKNOWN) { - zlog_warn("%s: VRF %s is not active", __func__, - vrf->name); - return NB_ERR_VALIDATION; - } + if (vrf_is_backend_netns()) { + char ifname_ns[XPATH_MAXLEN]; + char vrfname_ns[XPATH_MAXLEN]; - /* if VRF is netns or not yet known - init for instance - * then assumption is that passed config is exact - * then the user intent was not to use an other iface - */ - if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) { - ifp = if_lookup_by_name_all_vrf(ifname); - if (ifp && ifp->vrf_id != vrf->vrf_id) { - zlog_warn( - "%s: interface %s already exists in another VRF", - __func__, ifp->name); + netns_ifname_split(ifname, ifname_ns, vrfname_ns); + + if (strlen(ifname_ns) > 16) { + snprintf( + args->errmsg, args->errmsg_len, + "Maximum interface name length is 16 characters"); + return NB_ERR_VALIDATION; + } + if (strlen(vrfname_ns) > 36) { + snprintf( + args->errmsg, args->errmsg_len, + "Maximum VRF name length is 36 characters"); + return NB_ERR_VALIDATION; + } + } else { + if (strlen(ifname) > 16) { + snprintf( + args->errmsg, args->errmsg_len, + "Maximum interface name length is 16 characters"); return NB_ERR_VALIDATION; } } @@ -1434,9 +1441,18 @@ static int lib_interface_create(struct nb_cb_create_args *args) case NB_EV_ABORT: break; case NB_EV_APPLY: - vrf = vrf_lookup_by_name(vrfname); - assert(vrf); - ifp = if_get_by_name(ifname, vrf->vrf_id); + if (vrf_is_backend_netns()) { + char ifname_ns[XPATH_MAXLEN]; + char vrfname_ns[XPATH_MAXLEN]; + + netns_ifname_split(ifname, ifname_ns, vrfname_ns); + + ifp = if_get_by_name(ifname_ns, VRF_UNKNOWN, + vrfname_ns); + } else { + ifp = if_get_by_name(ifname, VRF_UNKNOWN, + VRF_DEFAULT_NAME); + } ifp->configured = true; nb_running_set_entry(args->dnode, ifp); @@ -1449,7 +1465,7 @@ static int lib_interface_create(struct nb_cb_create_args *args) static int lib_interface_destroy(struct nb_cb_destroy_args *args) { struct interface *ifp; - + struct vrf *vrf; switch (args->event) { case NB_EV_VALIDATE: @@ -1465,9 +1481,13 @@ static int lib_interface_destroy(struct nb_cb_destroy_args *args) break; case NB_EV_APPLY: ifp = nb_running_unset_entry(args->dnode); + vrf = ifp->vrf; ifp->configured = false; if_delete(&ifp); + + if (!vrf_is_enabled(vrf)) + vrf_delete(vrf); break; } @@ -1487,7 +1507,7 @@ static const void *lib_interface_get_next(struct nb_cb_get_next_args *args) assert(vrf); pif = RB_MIN(if_name_head, &vrf->ifaces_by_name); } else { - vrf = vrf_lookup_by_id(pif->vrf_id); + vrf = pif->vrf; pif = RB_NEXT(if_name_head, pif); /* if no more interfaces, switch to next vrf */ while (pif == NULL) { @@ -1505,13 +1525,14 @@ static int lib_interface_get_keys(struct nb_cb_get_keys_args *args) { const struct interface *ifp = args->list_entry; - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + args->keys->num = 1; - assert(vrf); - - args->keys->num = 2; - strlcpy(args->keys->key[0], ifp->name, sizeof(args->keys->key[0])); - strlcpy(args->keys->key[1], vrf->name, sizeof(args->keys->key[1])); + if (vrf_is_backend_netns()) + snprintf(args->keys->key[0], sizeof(args->keys->key[0]), + "%s:%s", ifp->vrf->name, ifp->name); + else + snprintf(args->keys->key[0], sizeof(args->keys->key[0]), "%s", + ifp->name); return NB_OK; } @@ -1519,11 +1540,19 @@ static int lib_interface_get_keys(struct nb_cb_get_keys_args *args) static const void * lib_interface_lookup_entry(struct nb_cb_lookup_entry_args *args) { - const char *ifname = args->keys->key[0]; - const char *vrfname = args->keys->key[1]; - struct vrf *vrf = vrf_lookup_by_name(vrfname); + if (vrf_is_backend_netns()) { + char ifname[XPATH_MAXLEN]; + char vrfname[XPATH_MAXLEN]; + struct vrf *vrf; + + netns_ifname_split(args->keys->key[0], ifname, vrfname); + + vrf = vrf_lookup_by_name(vrfname); - return vrf ? if_lookup_by_name(ifname, vrf->vrf_id) : NULL; + return vrf ? if_lookup_by_name(ifname, vrf->vrf_id) : NULL; + } else { + return if_lookup_by_name_all_vrf(args->keys->key[0]); + } } /* @@ -1559,6 +1588,17 @@ static int lib_interface_description_destroy(struct nb_cb_destroy_args *args) } /* + * XPath: /frr-interface:lib/interface/vrf + */ +static struct yang_data * +lib_interface_vrf_get_elem(struct nb_cb_get_elem_args *args) +{ + const struct interface *ifp = args->list_entry; + + return yang_data_new_string(args->xpath, ifp->vrf->name); +} + +/* * XPath: /frr-interface:lib/interface/state/if-index */ static struct yang_data * @@ -1672,6 +1712,12 @@ const struct frr_yang_module_info frr_interface_info = { }, }, { + .xpath = "/frr-interface:lib/interface/vrf", + .cbs = { + .get_elem = lib_interface_vrf_get_elem, + } + }, + { .xpath = "/frr-interface:lib/interface/state/if-index", .cbs = { .get_elem = lib_interface_state_if_index_get_elem, @@ -251,8 +251,8 @@ struct interface { /* Interface MTU. */ unsigned int mtu; /* IPv4 MTU */ unsigned int - mtu6; /* IPv6 MTU - probably, but not neccessarily same as mtu - */ + mtu6; /* IPv6 MTU - probably, but not necessarily same as mtu + */ /* Link-layer information and hardware address */ enum zebra_link_type ll_type; @@ -293,7 +293,8 @@ struct interface { #endif /* HAVE_NET_RT_IFLIST */ struct route_node *node; - vrf_id_t vrf_id; + + struct vrf *vrf; /* * Has the end users entered `interface XXXX` from the cli in some @@ -310,56 +311,56 @@ RB_HEAD(if_index_head, interface); RB_PROTOTYPE(if_index_head, interface, index_entry, if_cmp_index_func) DECLARE_QOBJ_TYPE(interface); -#define IFNAME_RB_INSERT(vrf, ifp) \ +#define IFNAME_RB_INSERT(v, ifp) \ ({ \ struct interface *_iz = \ - RB_INSERT(if_name_head, &vrf->ifaces_by_name, (ifp)); \ + RB_INSERT(if_name_head, &v->ifaces_by_name, (ifp)); \ if (_iz) \ flog_err( \ EC_LIB_INTERFACE, \ "%s(%s): corruption detected -- interface with this " \ - "name exists already in VRF %u!", \ - __func__, (ifp)->name, (ifp)->vrf_id); \ + "name exists already in VRF %s!", \ + __func__, (ifp)->name, (ifp)->vrf->name); \ _iz; \ }) -#define IFNAME_RB_REMOVE(vrf, ifp) \ +#define IFNAME_RB_REMOVE(v, ifp) \ ({ \ struct interface *_iz = \ - RB_REMOVE(if_name_head, &vrf->ifaces_by_name, (ifp)); \ + RB_REMOVE(if_name_head, &v->ifaces_by_name, (ifp)); \ if (_iz == NULL) \ flog_err( \ EC_LIB_INTERFACE, \ "%s(%s): corruption detected -- interface with this " \ - "name doesn't exist in VRF %u!", \ - __func__, (ifp)->name, (ifp)->vrf_id); \ + "name doesn't exist in VRF %s!", \ + __func__, (ifp)->name, (ifp)->vrf->name); \ _iz; \ }) -#define IFINDEX_RB_INSERT(vrf, ifp) \ +#define IFINDEX_RB_INSERT(v, ifp) \ ({ \ - struct interface *_iz = RB_INSERT( \ - if_index_head, &vrf->ifaces_by_index, (ifp)); \ + struct interface *_iz = \ + RB_INSERT(if_index_head, &v->ifaces_by_index, (ifp)); \ if (_iz) \ flog_err( \ EC_LIB_INTERFACE, \ "%s(%u): corruption detected -- interface with this " \ - "ifindex exists already in VRF %u!", \ - __func__, (ifp)->ifindex, (ifp)->vrf_id); \ + "ifindex exists already in VRF %s!", \ + __func__, (ifp)->ifindex, (ifp)->vrf->name); \ _iz; \ }) -#define IFINDEX_RB_REMOVE(vrf, ifp) \ +#define IFINDEX_RB_REMOVE(v, ifp) \ ({ \ - struct interface *_iz = RB_REMOVE( \ - if_index_head, &vrf->ifaces_by_index, (ifp)); \ + struct interface *_iz = \ + RB_REMOVE(if_index_head, &v->ifaces_by_index, (ifp)); \ if (_iz == NULL) \ flog_err( \ EC_LIB_INTERFACE, \ "%s(%u): corruption detected -- interface with this " \ - "ifindex doesn't exist in VRF %u!", \ - __func__, (ifp)->ifindex, (ifp)->vrf_id); \ + "ifindex doesn't exist in VRF %s!", \ + __func__, (ifp)->ifindex, (ifp)->vrf->name); \ _iz; \ }) @@ -397,16 +398,12 @@ struct connected { /* The ZEBRA_IFC_REAL flag should be set if and only if this address exists in the kernel and is actually usable. (A case where it exists - but - is not yet usable would be IPv6 with DAD) + but is not yet usable would be IPv6 with DAD) The ZEBRA_IFC_CONFIGURED flag should be set if and only if this - address - was configured by the user from inside quagga. + address was configured by the user from inside frr. The ZEBRA_IFC_QUEUED flag should be set if and only if the address - exists - in the kernel. It may and should be set although the address might - not be - usable yet. (compare with ZEBRA_IFC_REAL) + exists in the kernel. It may and should be set although the + address might not be usable yet. (compare with ZEBRA_IFC_REAL) The ZEBRA_IFC_DOWN flag is used to record that an address is present, but down/unavailable. */ @@ -510,16 +507,10 @@ extern int if_cmp_name_func(const char *p1, const char *p2); */ extern void if_update_to_new_vrf(struct interface *, vrf_id_t vrf_id); -/* Create new interface, adds to name list only */ -extern struct interface *if_create_name(const char *name, vrf_id_t vrf_id); - -/* Create new interface, adds to index list only */ -extern struct interface *if_create_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); extern struct interface *if_lookup_by_index(ifindex_t, vrf_id_t vrf_id); extern struct interface *if_vrf_lookup_by_index_next(ifindex_t ifindex, vrf_id_t vrf_id); -extern struct interface *if_lookup_by_index_all_vrf(ifindex_t); -extern struct interface *if_lookup_exact_address(const void *matchaddr, +extern struct interface *if_lookup_address_local(const void *matchaddr, int family, vrf_id_t vrf_id); extern struct connected *if_lookup_address(const void *matchaddr, int family, vrf_id_t vrf_id); @@ -528,17 +519,20 @@ extern struct interface *if_lookup_prefix(const struct prefix *prefix, size_t if_lookup_by_hwaddr(const uint8_t *hw_addr, size_t addrsz, struct interface ***result, vrf_id_t vrf_id); +static inline bool if_address_is_local(const void *matchaddr, int family, + vrf_id_t vrf_id) +{ + return if_lookup_address_local(matchaddr, family, vrf_id) != NULL; +} + struct vrf; -extern struct interface *if_lookup_by_name_all_vrf(const char *ifname); extern struct interface *if_lookup_by_name_vrf(const char *name, struct vrf *vrf); extern struct interface *if_lookup_by_name(const char *ifname, vrf_id_t vrf_id); -extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id); -extern struct interface *if_get_by_ifindex(ifindex_t ifindex, vrf_id_t vrf_id); +extern struct interface *if_get_by_name(const char *ifname, vrf_id_t vrf_id, + const char *vrf_name); /* Sets the index and adds to index list */ extern int if_set_index(struct interface *ifp, ifindex_t ifindex); -/* Sets the name and adds to name list */ -extern void if_set_name(struct interface *ifp, const char *name); /* Delete the interface, but do not free the structure, and leave it in the interface list. It is often advisable to leave the pseudo interface @@ -553,9 +547,9 @@ extern int if_is_up(const struct interface *ifp); extern int if_is_running(const struct interface *ifp); extern int if_is_operative(const struct interface *ifp); extern int if_is_no_ptm_operative(const struct interface *ifp); -extern int if_is_loopback(const struct interface *ifp); +extern int if_is_loopback_exact(const struct interface *ifp); extern int if_is_vrf(const struct interface *ifp); -extern bool if_is_loopback_or_vrf(const struct interface *ifp); +extern bool if_is_loopback(const struct interface *ifp); extern int if_is_broadcast(const struct interface *ifp); extern int if_is_pointopoint(const struct interface *ifp); extern int if_is_multicast(const struct interface *ifp); @@ -599,6 +593,7 @@ void if_link_params_free(struct interface *); /* Northbound. */ struct vty; extern void if_cmd_init(int (*config_write)(struct vty *)); +extern void if_cmd_init_default(void); extern void if_zapi_callbacks(int (*create)(struct interface *ifp), int (*up)(struct interface *ifp), int (*down)(struct interface *ifp), diff --git a/lib/json.c b/lib/json.c index cfba6ea3b6..854a3d59d1 100644 --- a/lib/json.c +++ b/lib/json.c @@ -39,17 +39,41 @@ bool use_json(const int argc, struct cmd_token *argv[]) return false; } +struct json_object *json_object_new_stringv(const char *fmt, va_list args) +{ + struct json_object *ret; + char *text, buf[256]; + + text = vasnprintfrr(MTYPE_TMP, buf, sizeof(buf), fmt, args); + ret = json_object_new_string(text); + + if (text != buf) + XFREE(MTYPE_TMP, text); + return ret; +} + void json_array_string_add(json_object *json, const char *str) { json_object_array_add(json, json_object_new_string(str)); } +void json_array_string_addv(json_object *json, const char *fmt, va_list args) +{ + json_object_array_add(json, json_object_new_stringv(fmt, args)); +} + void json_object_string_add(struct json_object *obj, const char *key, const char *s) { json_object_object_add(obj, key, json_object_new_string(s)); } +void json_object_string_addv(struct json_object *obj, const char *key, + const char *fmt, va_list args) +{ + json_object_object_add(obj, key, json_object_new_stringv(fmt, args)); +} + void json_object_int_add(struct json_object *obj, const char *key, int64_t i) { json_object_object_add(obj, key, json_object_new_int64(i)); diff --git a/lib/json.h b/lib/json.h index fe208f4fa9..9d33ac7ae3 100644 --- a/lib/json.h +++ b/lib/json.h @@ -26,6 +26,7 @@ extern "C" { #endif #include "command.h" +#include "printfrr.h" #include <json-c/json.h> /* @@ -59,6 +60,53 @@ extern struct json_object *json_object_lock(struct json_object *obj); extern void json_object_free(struct json_object *obj); extern void json_array_string_add(json_object *json, const char *str); +/* printfrr => json helpers */ + +PRINTFRR(3, 0) +extern void json_object_string_addv(struct json_object *obj, const char *key, + const char *fmt, va_list args); +PRINTFRR(3, 4) +static inline void json_object_string_addf(struct json_object *obj, + const char *key, const char *fmt, + ...) +{ + va_list args; + + va_start(args, fmt); + json_object_string_addv(obj, key, fmt, args); + va_end(args); +} + +PRINTFRR(2, 0) +extern void json_array_string_addv(json_object *json, const char *fmt, + va_list args); +PRINTFRR(2, 3) +static inline void json_array_string_addf(struct json_object *obj, + const char *fmt, ...) +{ + va_list args; + + va_start(args, fmt); + json_array_string_addv(obj, fmt, args); + va_end(args); +} + +PRINTFRR(1, 0) +extern struct json_object *json_object_new_stringv(const char *fmt, + va_list args); +PRINTFRR(1, 2) +static inline struct json_object *json_object_new_stringf(const char *fmt, ...) +{ + struct json_object *ret; + va_list args; + + va_start(args, fmt); + ret = json_object_new_stringv(fmt, args); + va_end(args); + + return ret; +} + #define JSON_STR "JavaScript Object Notation\n" /* NOTE: json-c lib has following commit 316da85 which diff --git a/lib/lib_errors.c b/lib/lib_errors.c index 17695e6607..a139b9a14c 100644 --- a/lib/lib_errors.c +++ b/lib/lib_errors.c @@ -41,19 +41,19 @@ static struct log_ref ferr_lib_warn[] = { { .code = EC_LIB_LINUX_NS, .title = "The Linux namespace subsystem has encountered a parsing error", - .description = "During system startup an invalid parameter for the namesapce was give to FRR", + .description = "During system startup an invalid parameter for the namespace was give to FRR", .suggestion = "Gather log data and open an Issue. restart FRR", }, { .code = EC_LIB_SLOW_THREAD_CPU, .title = "The Event subsystem has detected a slow cpu time process", - .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination therof. In this case total CPU time was over 5 seconds. Which indicates that FRR is very busy doing some work and should be addressed", + .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug, or some combination thereof. In this case total CPU time was over 5 seconds. Which indicates that FRR is very busy doing some work and should be addressed", .suggestion = "Gather log data and open an Issue", }, { .code = EC_LIB_SLOW_THREAD_WALL, .title = "The Event subsystem has detected a slow wall time process", - .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug or some combination therof. In this case total WALL time was over 5 seconds. Which indicates that FRR might be having trouble being scheduled or some system call is delaying", + .description = "The Event subsystem has detected a slow process, this typically indicates that FRR is having trouble completing work in a timely manner. This can be either a misconfiguration, bug or some combination thereof. In this case total WALL time was over 5 seconds. Which indicates that FRR might be having trouble being scheduled or some system call is delaying", .suggestion = "Gather log data and open an Issue", }, { @@ -286,7 +286,7 @@ static struct log_ref ferr_lib_err[] = { }, { .code = EC_LIB_NB_CB_INVALID_PRIO, - .title = "Norhtbound callback has an invalid priority", + .title = "Northbound callback has an invalid priority", .description = "The northbound subsystem, during initialization, has detected a callback whose priority is invalid", .suggestion = "This is a bug; please report it" }, diff --git a/lib/libfrr.c b/lib/libfrr.c index 9b05bb4fbf..1610ba4e7d 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -121,7 +121,6 @@ static const struct option lo_always[] = { {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR}, {"log", required_argument, NULL, OPTION_LOG}, {"log-level", required_argument, NULL, OPTION_LOGLEVEL}, - {"tcli", no_argument, NULL, OPTION_TCLI}, {"command-log-always", no_argument, NULL, OPTION_LOGGING}, {"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS}, {NULL}}; @@ -138,31 +137,43 @@ static const struct optspec os_always = { " --scriptdir Override scripts directory\n" " --log Set Logging to stdout, syslog, or file:<name>\n" " --log-level Set Logging Level to use, debug, info, warn, etc\n" - " --tcli Use transaction-based CLI\n" " --limit-fds Limit number of fds supported\n", lo_always}; -static const struct option lo_cfg_pid_dry[] = { - {"pid_file", required_argument, NULL, 'i'}, +static const struct option lo_cfg[] = { {"config_file", required_argument, NULL, 'f'}, -#ifdef HAVE_SQLITE3 - {"db_file", required_argument, NULL, OPTION_DB_FILE}, -#endif {"dryrun", no_argument, NULL, 'C'}, - {"terminal", no_argument, NULL, 't'}, {NULL}}; -static const struct optspec os_cfg_pid_dry = { - "f:i:Ct", +static const struct optspec os_cfg = { + "f:C", " -f, --config_file Set configuration file name\n" - " -i, --pid_file Set process identifier file name\n" + " -C, --dryrun Check configuration for validity and exit\n", + lo_cfg}; + + +static const struct option lo_fullcli[] = { + {"terminal", no_argument, NULL, 't'}, + {"tcli", no_argument, NULL, OPTION_TCLI}, #ifdef HAVE_SQLITE3 - " --db_file Set database file name\n" + {"db_file", required_argument, NULL, OPTION_DB_FILE}, #endif - " -C, --dryrun Check configuration for validity and exit\n" + {NULL}}; +static const struct optspec os_fullcli = { + "t", + " --tcli Use transaction-based CLI\n" " -t, --terminal Open terminal session on stdio\n" " -d -t Daemonize after terminal session ends\n", - lo_cfg_pid_dry}; + lo_fullcli}; + + +static const struct option lo_pid[] = { + {"pid_file", required_argument, NULL, 'i'}, + {NULL}}; +static const struct optspec os_pid = { + "i:", + " -i, --pid_file Set process identifier file name\n", + lo_pid}; static const struct option lo_zclient[] = { @@ -320,8 +331,12 @@ void frr_preinit(struct frr_daemon_info *daemon, int argc, char **argv) umask(0027); opt_extend(&os_always); - if (!(di->flags & FRR_NO_CFG_PID_DRY)) - opt_extend(&os_cfg_pid_dry); + if (!(di->flags & FRR_NO_SPLIT_CONFIG)) + opt_extend(&os_cfg); + if (!(di->flags & FRR_LIMITED_CLI)) + opt_extend(&os_fullcli); + if (!(di->flags & FRR_NO_PID)) + opt_extend(&os_pid); if (!(di->flags & FRR_NO_PRIVSEP)) opt_extend(&os_user); if (!(di->flags & FRR_NO_ZCLIENT)) @@ -459,12 +474,12 @@ static int frr_opt(int opt) frr_defaults_profile_set(optarg); break; case 'i': - if (di->flags & FRR_NO_CFG_PID_DRY) + if (di->flags & FRR_NO_PID) return 1; di->pid_file = optarg; break; case 'f': - if (di->flags & FRR_NO_CFG_PID_DRY) + if (di->flags & FRR_NO_SPLIT_CONFIG) return 1; di->config_file = optarg; break; @@ -497,18 +512,18 @@ static int frr_opt(int opt) break; #ifdef HAVE_SQLITE3 case OPTION_DB_FILE: - if (di->flags & FRR_NO_CFG_PID_DRY) + if (di->flags & FRR_NO_PID) return 1; di->db_file = optarg; break; #endif case 'C': - if (di->flags & FRR_NO_CFG_PID_DRY) + if (di->flags & FRR_NO_SPLIT_CONFIG) return 1; di->dryrun = true; break; case 't': - if (di->flags & FRR_NO_CFG_PID_DRY) + if (di->flags & FRR_LIMITED_CLI) return 1; di->terminal = true; break; @@ -986,7 +1001,7 @@ void frr_config_fork(void) { hook_call(frr_late_init, master); - if (!(di->flags & FRR_NO_CFG_PID_DRY)) { + if (!(di->flags & FRR_NO_SPLIT_CONFIG)) { /* Don't start execution if we are in dry-run mode */ if (di->dryrun) { frr_config_read_in(NULL); diff --git a/lib/libfrr.h b/lib/libfrr.h index 3dc5d7af81..e0642ef847 100644 --- a/lib/libfrr.h +++ b/lib/libfrr.h @@ -40,15 +40,17 @@ extern "C" { #define FRR_NO_PRIVSEP (1 << 0) #define FRR_NO_TCPVTY (1 << 1) #define FRR_LIMITED_CLI (1 << 2) -#define FRR_NO_CFG_PID_DRY (1 << 3) -#define FRR_NO_ZCLIENT (1 << 4) +#define FRR_NO_SPLIT_CONFIG (1 << 3) +#define FRR_NO_PID (1 << 4) +#define FRR_NO_CFG_PID_DRY (FRR_NO_PID | FRR_NO_SPLIT_CONFIG) +#define FRR_NO_ZCLIENT (1 << 5) /* If FRR_DETACH_LATER is used, the daemon will keep its parent running * until frr_detach() is called. Normally "somedaemon -d" returns once the * main event loop is reached in the daemon; use this for extra startup bits. * * Does nothing if -d isn't used. */ -#define FRR_DETACH_LATER (1 << 5) +#define FRR_DETACH_LATER (1 << 6) enum frr_cli_mode { FRR_CLI_CLASSIC = 0, @@ -94,7 +96,7 @@ struct frr_daemon_info { const char *copyright; char startinfo[128]; - struct quagga_signal_t *signals; + struct frr_signal_t *signals; size_t n_signals; struct zebra_privs_t *privs; diff --git a/lib/libospf.h b/lib/libospf.h index d2bb29d80e..c8ada9d3c5 100644 --- a/lib/libospf.h +++ b/lib/libospf.h @@ -36,7 +36,7 @@ extern "C" { #define IPPROTO_OSPFIGP 89 #endif /* IPPROTO_OSPFIGP */ -/* Architectual Constants */ +/* Architectural Constants */ #ifdef DEBUG #define OSPF_LS_REFRESH_TIME 120 #else diff --git a/lib/link_state.c b/lib/link_state.c index 062384aac7..b0bc386b79 100644 --- a/lib/link_state.c +++ b/lib/link_state.c @@ -46,6 +46,28 @@ DEFINE_MTYPE_STATIC(LIB, LS_DB, "Link State Database"); /** * Link State Node management functions */ +int ls_node_id_same(struct ls_node_id i1, struct ls_node_id i2) +{ + if (i1.origin != i2.origin) + return 0; + + if (i1.origin == UNKNOWN) + return 1; + + if (i1.origin == ISIS_L1 || i1.origin == ISIS_L2) { + if (memcmp(i1.id.iso.sys_id, i2.id.iso.sys_id, ISO_SYS_ID_LEN) + != 0 + || (i1.id.iso.level != i2.id.iso.level)) + return 0; + } else { + if (!IPV4_ADDR_SAME(&i1.id.ip.addr, &i2.id.ip.addr) + || !IPV4_ADDR_SAME(&i1.id.ip.area_id, &i2.id.ip.area_id)) + return 1; + } + + return 1; +} + struct ls_node *ls_node_new(struct ls_node_id adv, struct in_addr rid, struct in6_addr rid6) { @@ -83,29 +105,56 @@ void ls_node_del(struct ls_node *node) int ls_node_same(struct ls_node *n1, struct ls_node *n2) { + /* First, check pointer */ if ((n1 && !n2) || (!n1 && n2)) return 0; if (n1 == n2) return 1; + /* Then, verify Flags and Origin */ if (n1->flags != n2->flags) return 0; - if (n1->adv.origin != n2->adv.origin) + if (!ls_node_id_same(n1->adv, n2->adv)) return 0; - if (!memcmp(&n1->adv.id, &n2->adv.id, sizeof(struct ls_node_id))) + /* Finally, check each individual parameters that are valid */ + if (CHECK_FLAG(n1->flags, LS_NODE_NAME) + && (strncmp(n1->name, n2->name, MAX_NAME_LENGTH) != 0)) return 0; - - /* Do we need to test individually each field, instead performing a - * global memcmp? There is a risk that an old value that is bit masked - * i.e. corresponding flag = 0, will result into a false negative - */ - if (!memcmp(n1, n2, sizeof(struct ls_node))) + if (CHECK_FLAG(n1->flags, LS_NODE_ROUTER_ID) + && !IPV4_ADDR_SAME(&n1->router_id, &n2->router_id)) return 0; - else - return 1; + if (CHECK_FLAG(n1->flags, LS_NODE_ROUTER_ID6) + && !IPV6_ADDR_SAME(&n1->router6_id, &n2->router6_id)) + return 0; + if (CHECK_FLAG(n1->flags, LS_NODE_FLAG) + && (n1->node_flag != n2->node_flag)) + return 0; + if (CHECK_FLAG(n1->flags, LS_NODE_TYPE) && (n1->type != n2->type)) + return 0; + if (CHECK_FLAG(n1->flags, LS_NODE_AS_NUMBER) + && (n1->as_number != n2->as_number)) + return 0; + if (CHECK_FLAG(n1->flags, LS_NODE_SR)) { + if (n1->srgb.flag != n2->srgb.flag + || n1->srgb.lower_bound != n2->srgb.lower_bound + || n1->srgb.range_size != n2->srgb.range_size) + return 0; + if ((n1->algo[0] != n2->algo[0]) + || (n1->algo[1] != n2->algo[1])) + return 0; + if (CHECK_FLAG(n1->flags, LS_NODE_SRLB) + && ((n1->srlb.lower_bound != n2->srlb.lower_bound + || n1->srlb.range_size != n2->srlb.range_size))) + return 0; + if (CHECK_FLAG(n1->flags, LS_NODE_MSD) && (n1->msd != n2->msd)) + return 0; + } + + /* OK, n1 & n2 are equal */ + return 1; } /** @@ -171,29 +220,133 @@ void ls_attributes_del(struct ls_attributes *attr) int ls_attributes_same(struct ls_attributes *l1, struct ls_attributes *l2) { + /* First, check pointer */ if ((l1 && !l2) || (!l1 && l2)) return 0; if (l1 == l2) return 1; + /* Then, verify Flags and Origin */ if (l1->flags != l2->flags) return 0; - if (l1->adv.origin != l2->adv.origin) + if (!ls_node_id_same(l1->adv, l2->adv)) return 0; - if (!memcmp(&l1->adv.id, &l2->adv.id, sizeof(struct ls_node_id))) + /* Finally, check each individual parameters that are valid */ + if (CHECK_FLAG(l1->flags, LS_ATTR_NAME) + && strncmp(l1->name, l2->name, MAX_NAME_LENGTH) != 0) return 0; - - /* Do we need to test individually each field, instead performing a - * global memcmp? There is a risk that an old value that is bit masked - * i.e. corresponding flag = 0, will result into a false negative - */ - if (!memcmp(l1, l2, sizeof(struct ls_attributes))) + if (CHECK_FLAG(l1->flags, LS_ATTR_METRIC) && (l1->metric != l2->metric)) return 0; - else - return 1; + if (CHECK_FLAG(l1->flags, LS_ATTR_TE_METRIC) + && (l1->standard.te_metric != l2->standard.te_metric)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_ADM_GRP) + && (l1->standard.admin_group != l2->standard.admin_group)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_LOCAL_ADDR) + && !IPV4_ADDR_SAME(&l1->standard.local, &l2->standard.local)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_NEIGH_ADDR) + && !IPV4_ADDR_SAME(&l1->standard.remote, &l2->standard.remote)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_LOCAL_ADDR6) + && !IPV6_ADDR_SAME(&l1->standard.local6, &l2->standard.local6)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_NEIGH_ADDR6) + && !IPV6_ADDR_SAME(&l1->standard.remote6, &l2->standard.remote6)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_LOCAL_ID) + && (l1->standard.local_id != l2->standard.local_id)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_NEIGH_ID) + && (l1->standard.remote_id != l2->standard.remote_id)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_MAX_BW) + && (l1->standard.max_bw != l2->standard.max_bw)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_MAX_RSV_BW) + && (l1->standard.max_rsv_bw != l2->standard.max_rsv_bw)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_UNRSV_BW) + && memcmp(&l1->standard.unrsv_bw, &l2->standard.unrsv_bw, 32) != 0) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_REMOTE_AS) + && (l1->standard.remote_as != l2->standard.remote_as)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_REMOTE_ADDR) + && !IPV4_ADDR_SAME(&l1->standard.remote_addr, + &l2->standard.remote_addr)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_REMOTE_ADDR6) + && !IPV6_ADDR_SAME(&l1->standard.remote_addr6, + &l2->standard.remote_addr6)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_DELAY) + && (l1->extended.delay != l2->extended.delay)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_MIN_MAX_DELAY) + && ((l1->extended.min_delay != l2->extended.min_delay) + || (l1->extended.max_delay != l2->extended.max_delay))) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_JITTER) + && (l1->extended.jitter != l2->extended.jitter)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_PACKET_LOSS) + && (l1->extended.pkt_loss != l2->extended.pkt_loss)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_AVA_BW) + && (l1->extended.ava_bw != l2->extended.ava_bw)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_RSV_BW) + && (l1->extended.rsv_bw != l2->extended.rsv_bw)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_USE_BW) + && (l1->extended.used_bw != l2->extended.used_bw)) + return 0; + if (CHECK_FLAG(l1->flags, LS_ATTR_ADJ_SID)) { + if ((l1->adj_sid[0].sid != l2->adj_sid[0].sid) + || (l1->adj_sid[0].flags != l2->adj_sid[0].flags) + || (l1->adj_sid[0].weight != l2->adj_sid[0].weight)) + return 0; + if (((l1->adv.origin == ISIS_L1) || (l1->adv.origin == ISIS_L2)) + && (memcmp(&l1->adj_sid[0].neighbor.sysid, + &l2->adj_sid[0].neighbor.sysid, ISO_SYS_ID_LEN) + != 0)) + return 0; + if (((l1->adv.origin == OSPFv2) || (l1->adv.origin == STATIC) + || (l1->adv.origin == DIRECT)) + && (!IPV4_ADDR_SAME(&l1->adj_sid[0].neighbor.addr, + &l2->adj_sid[0].neighbor.addr))) + return 0; + } + if (CHECK_FLAG(l1->flags, LS_ATTR_BCK_ADJ_SID)) { + if ((l1->adj_sid[1].sid != l2->adj_sid[1].sid) + || (l1->adj_sid[1].flags != l2->adj_sid[1].flags) + || (l1->adj_sid[1].weight != l2->adj_sid[1].weight)) + return 0; + if (((l1->adv.origin == ISIS_L1) || (l1->adv.origin == ISIS_L2)) + && (memcmp(&l1->adj_sid[1].neighbor.sysid, + &l2->adj_sid[1].neighbor.sysid, ISO_SYS_ID_LEN) + != 0)) + return 0; + if (((l1->adv.origin == OSPFv2) || (l1->adv.origin == STATIC) + || (l1->adv.origin == DIRECT)) + && (!IPV4_ADDR_SAME(&l1->adj_sid[1].neighbor.addr, + &l2->adj_sid[1].neighbor.addr))) + return 0; + } + if (CHECK_FLAG(l1->flags, LS_ATTR_SRLG) + && ((l1->srlg_len != l2->srlg_len) + || memcmp(l1->srlgs, l2->srlgs, + l1->srlg_len * sizeof(uint32_t)) + != 0)) + return 0; + + /* OK, l1 & l2 are equal */ + return 1; } /** @@ -223,29 +376,42 @@ void ls_prefix_del(struct ls_prefix *pref) int ls_prefix_same(struct ls_prefix *p1, struct ls_prefix *p2) { + /* First, check pointer */ if ((p1 && !p2) || (!p1 && p2)) return 0; if (p1 == p2) return 1; + /* Then, verify Flags and Origin */ if (p1->flags != p2->flags) return 0; - if (p1->adv.origin != p2->adv.origin) + if (!ls_node_id_same(p1->adv, p2->adv)) return 0; - if (!memcmp(&p1->adv.id, &p2->adv.id, sizeof(struct ls_node_id))) + /* Finally, check each individual parameters that are valid */ + if (prefix_same(&p1->pref, &p2->pref) == 0) return 0; - - /* Do we need to test individually each field, instead performing a - * global memcmp? There is a risk that an old value that is bit masked - * i.e. corresponding flag = 0, will result into a false negative - */ - if (!memcmp(p1, p2, sizeof(struct ls_prefix))) + if (CHECK_FLAG(p1->flags, LS_PREF_IGP_FLAG) + && (p1->igp_flag != p2->igp_flag)) return 0; - else - return 1; + if (CHECK_FLAG(p1->flags, LS_PREF_ROUTE_TAG) + && (p1->route_tag != p2->route_tag)) + return 0; + if (CHECK_FLAG(p1->flags, LS_PREF_EXTENDED_TAG) + && (p1->extended_tag != p2->extended_tag)) + return 0; + if (CHECK_FLAG(p1->flags, LS_PREF_METRIC) && (p1->metric != p2->metric)) + return 0; + if (CHECK_FLAG(p1->flags, LS_PREF_SR)) { + if ((p1->sr.algo != p2->sr.algo) || (p1->sr.sid != p2->sr.sid) + || (p1->sr.sid_flag != p2->sr.sid_flag)) + return 0; + } + + /* OK, p1 & p2 are equal */ + return 1; } /** @@ -844,11 +1010,11 @@ void ls_ted_del_all(struct ls_ted *ted) return; /* First remove Vertices, Edges and Subnets and associated Link State */ - frr_each (vertices, &ted->vertices, vertex) + frr_each_safe (vertices, &ted->vertices, vertex) ls_vertex_del_all(ted, vertex); - frr_each (edges, &ted->edges, edge) + frr_each_safe (edges, &ted->edges, edge) ls_edge_del_all(ted, edge); - frr_each (subnets, &ted->subnets, subnet) + frr_each_safe (subnets, &ted->subnets, subnet) ls_subnet_del_all(ted, subnet); /* then remove TED itself */ @@ -865,17 +1031,17 @@ void ls_ted_clean(struct ls_ted *ted) return; /* First, start with Vertices */ - frr_each (vertices, &ted->vertices, vertex) + frr_each_safe (vertices, &ted->vertices, vertex) if (vertex->status == ORPHAN) ls_vertex_del_all(ted, vertex); /* Then Edges */ - frr_each (edges, &ted->edges, edge) + frr_each_safe (edges, &ted->edges, edge) if (edge->status == ORPHAN) ls_edge_del_all(ted, edge); /* and Subnets */ - frr_each (subnets, &ted->subnets, subnet) + frr_each_safe (subnets, &ted->subnets, subnet) if (subnet->status == ORPHAN) ls_subnet_del_all(ted, subnet); diff --git a/lib/link_state.h b/lib/link_state.h index de116df89e..981e8b5285 100644 --- a/lib/link_state.h +++ b/lib/link_state.h @@ -94,6 +94,16 @@ struct ls_node_id { } id __attribute__((aligned(8))); }; +/** + * Check if two Link State Node IDs are equal. Note that this routine has the + * same return value sense as '==' (which is different from a comparison). + * + * @param i1 First Link State Node Identifier + * @param i2 Second Link State Node Identifier + * @return 1 if equal, 0 otherwise + */ +extern int ls_node_id_same(struct ls_node_id i1, struct ls_node_id i2); + /* Link State flags to indicate which Node parameters are valid */ #define LS_NODE_UNSET 0x0000 #define LS_NODE_NAME 0x0001 @@ -64,7 +64,7 @@ const char *lookup_msg(const struct message *mz, int kz, const char *nf) } /* For time string format. */ -size_t quagga_timestamp(int timestamp_precision, char *buf, size_t buflen) +size_t frr_timestamp(int timestamp_precision, char *buf, size_t buflen) { static struct { time_t last; @@ -355,9 +355,6 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_INTERFACE_NBR_ADDRESS_ADD), DESC_ENTRY(ZEBRA_INTERFACE_NBR_ADDRESS_DELETE), DESC_ENTRY(ZEBRA_INTERFACE_BFD_DEST_UPDATE), - DESC_ENTRY(ZEBRA_IMPORT_ROUTE_REGISTER), - DESC_ENTRY(ZEBRA_IMPORT_ROUTE_UNREGISTER), - DESC_ENTRY(ZEBRA_IMPORT_CHECK_UPDATE), DESC_ENTRY(ZEBRA_BFD_DEST_REGISTER), DESC_ENTRY(ZEBRA_BFD_DEST_DEREGISTER), DESC_ENTRY(ZEBRA_BFD_DEST_UPDATE), @@ -102,9 +102,9 @@ extern void zlog_backtrace_sigsafe(int priority, void *program_counter); It caches the most recent localtime result and can therefore avoid multiple calls within the same second. If buflen is too small, *buf will be set to '\0', and 0 will be returned. */ -#define QUAGGA_TIMESTAMP_LEN 40 -extern size_t quagga_timestamp(int timestamp_precision /* # subsecond digits */, - char *buf, size_t buflen); +#define FRR_TIMESTAMP_LEN 40 +extern size_t frr_timestamp(int timestamp_precision /* # subsecond digits */, + char *buf, size_t buflen); extern void zlog_hexdump(const void *mem, size_t len); extern const char *zlog_sanitize(char *buf, size_t bufsz, const void *in, @@ -135,8 +135,8 @@ struct timestamp_control { size_t len; /* length of rendered timestamp */ int precision; /* configuration parameter */ int already_rendered; /* should be initialized to 0 */ - char buf[QUAGGA_TIMESTAMP_LEN]; /* will contain the rendered timestamp - */ + char buf[FRR_TIMESTAMP_LEN]; /* will contain the rendered timestamp + */ }; /* Defines for use in command construction: */ diff --git a/lib/log_vty.c b/lib/log_vty.c index cbb8de8976..621949ab57 100644 --- a/lib/log_vty.c +++ b/lib/log_vty.c @@ -36,6 +36,8 @@ DEFINE_HOOK(zlog_rotate, (), ()); DEFINE_HOOK(zlog_cli_show, (struct vty * vty), (vty)); +static unsigned logmsgs_with_persist_bt; + static const int log_default_lvl = LOG_DEBUG; static int log_config_stdout_lvl = ZLOG_DISABLED; @@ -267,6 +269,43 @@ DEFUN_HIDDEN (no_config_log_monitor, return CMD_SUCCESS; } +DEFPY_NOSH (debug_uid_backtrace, + debug_uid_backtrace_cmd, + "[no] debug unique-id UID backtrace", + NO_STR + DEBUG_STR + "Options per individual log message, by unique ID\n" + "Log message unique ID (XXXXX-XXXXX)\n" + "Add backtrace to log when message is printed\n") +{ + struct xrefdata search, *xrd; + struct xrefdata_logmsg *xrdl; + uint8_t flag; + + strlcpy(search.uid, uid, sizeof(search.uid)); + xrd = xrefdata_uid_find(&xrefdata_uid, &search); + + if (!xrd) + return CMD_ERR_NOTHING_TODO; + + if (xrd->xref->type != XREFT_LOGMSG) { + vty_out(vty, "%% ID \"%s\" is not a log message\n", uid); + return CMD_WARNING; + } + xrdl = container_of(xrd, struct xrefdata_logmsg, xrefdata); + + flag = (vty->node == CONFIG_NODE) ? LOGMSG_FLAG_PERSISTENT + : LOGMSG_FLAG_EPHEMERAL; + + if ((xrdl->fl_print_bt & flag) == (no ? 0 : flag)) + return CMD_SUCCESS; + if (flag == LOGMSG_FLAG_PERSISTENT) + logmsgs_with_persist_bt += no ? -1 : 1; + + xrdl->fl_print_bt ^= flag; + return CMD_SUCCESS; +} + static int set_log_file(struct zlog_cfg_file *target, struct vty *vty, const char *fname, int loglevel) { @@ -751,6 +790,24 @@ void log_config_write(struct vty *vty) vty_out(vty, "no log error-category\n"); if (!zlog_get_prefix_xid()) vty_out(vty, "no log unique-id\n"); + + if (logmsgs_with_persist_bt) { + struct xrefdata *xrd; + struct xrefdata_logmsg *xrdl; + + vty_out(vty, "!\n"); + + frr_each (xrefdata_uid, &xrefdata_uid, xrd) { + if (xrd->xref->type != XREFT_LOGMSG) + continue; + + xrdl = container_of(xrd, struct xrefdata_logmsg, + xrefdata); + if (xrdl->fl_print_bt & LOGMSG_FLAG_PERSISTENT) + vty_out(vty, "debug unique-id %s backtrace\n", + xrd->uid); + } + } } static int log_vty_init(const char *progname, const char *protoname, @@ -801,4 +858,7 @@ void log_cmd_init(void) install_element(CONFIG_NODE, &config_log_filterfile_cmd); install_element(CONFIG_NODE, &no_config_log_filterfile_cmd); install_element(CONFIG_NODE, &log_immediate_mode_cmd); + + install_element(ENABLE_NODE, &debug_uid_backtrace_cmd); + install_element(CONFIG_NODE, &debug_uid_backtrace_cmd); } diff --git a/lib/netns_linux.c b/lib/netns_linux.c index cde842b88c..43c0d8c359 100644 --- a/lib/netns_linux.c +++ b/lib/netns_linux.c @@ -279,7 +279,7 @@ static void ns_disable_internal(struct ns *ns) } } -/* VRF list existance check by name. */ +/* VRF list existence check by name. */ static struct ns_map_nsid *ns_map_nsid_lookup_by_nsid(ns_id_t ns_id) { struct ns_map_nsid ns_map; diff --git a/lib/network.h b/lib/network.h index 4a9666984f..10ed917572 100644 --- a/lib/network.h +++ b/lib/network.h @@ -22,6 +22,13 @@ #ifndef _ZEBRA_NETWORK_H #define _ZEBRA_NETWORK_H +#ifdef HAVE_SYS_ENDIAN_H +#include <sys/endian.h> +#endif +#ifdef HAVE_ENDIAN_H +#include <endian.h> +#endif + #ifdef __cplusplus extern "C" { #endif @@ -45,6 +52,35 @@ extern int set_cloexec(int fd); extern float htonf(float); extern float ntohf(float); +/* force type for be64toh/htobe64 to be uint64_t, *without* a direct cast + * + * this is a workaround for false-positive printfrr warnings from FRR's + * frr-format GCC plugin that would be triggered from + * { printfrr("%"PRIu64, (uint64_t)be64toh(...)); } + * + * the key element here is that "(uint64_t)expr" causes the warning, while + * "({ uint64_t x = expr; x; })" does not. (The cast is the trigger, a + * variable of the same type works correctly.) + */ + +/* zap system definitions... */ +#ifdef be64toh +#undef be64toh +#endif +#ifdef htobe64 +#undef htobe64 +#endif + +#if BYTE_ORDER == LITTLE_ENDIAN +#define be64toh(x) ({ uint64_t r = __builtin_bswap64(x); r; }) +#define htobe64(x) ({ uint64_t r = __builtin_bswap64(x); r; }) +#elif BYTE_ORDER == BIG_ENDIAN +#define be64toh(x) ({ uint64_t r = (x); r; }) +#define htobe64(x) ({ uint64_t r = (x); r; }) +#else +#error nobody expects the endianish inquisition. check OS endian.h headers. +#endif + /** * Helper function that returns a random long value. The main purpose of * this function is to hide a `random()` call that gets flagged by coverity diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 97d70189ff..e8c678ad71 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -953,12 +953,6 @@ DEFPY(ecmp_nexthops, ecmp_nexthops_cmd, nhg_hooks.add_nexthop(nhgc, nh); } - if (intf) { - struct interface *ifp = if_lookup_by_name_all_vrf(intf); - - if (ifp) - ifp->configured = true; - } return CMD_SUCCESS; } @@ -1041,7 +1035,6 @@ void nexthop_group_write_nexthop(struct vty *vty, const struct nexthop *nh) void nexthop_group_json_nexthop(json_object *j, const struct nexthop *nh) { - char buf[100]; struct vrf *vrf; json_object *json_backups = NULL; int i; @@ -1052,26 +1045,18 @@ void nexthop_group_json_nexthop(json_object *j, const struct nexthop *nh) ifindex2ifname(nh->ifindex, nh->vrf_id)); break; case NEXTHOP_TYPE_IPV4: - json_object_string_add( - j, "nexthop", - inet_ntop(AF_INET, &nh->gate.ipv4, buf, sizeof(buf))); + json_object_string_addf(j, "nexthop", "%pI4", &nh->gate.ipv4); break; case NEXTHOP_TYPE_IPV4_IFINDEX: - json_object_string_add( - j, "nexthop", - inet_ntop(AF_INET, &nh->gate.ipv4, buf, sizeof(buf))); + json_object_string_addf(j, "nexthop", "%pI4", &nh->gate.ipv4); json_object_string_add(j, "vrfId", ifindex2ifname(nh->ifindex, nh->vrf_id)); break; case NEXTHOP_TYPE_IPV6: - json_object_string_add( - j, "nexthop", - inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf))); + json_object_string_addf(j, "nexthop", "%pI6", &nh->gate.ipv6); break; case NEXTHOP_TYPE_IPV6_IFINDEX: - json_object_string_add( - j, "nexthop", - inet_ntop(AF_INET6, &nh->gate.ipv6, buf, sizeof(buf))); + json_object_string_addf(j, "nexthop", "%pI6", &nh->gate.ipv6); json_object_string_add(j, "vrfId", ifindex2ifname(nh->ifindex, nh->vrf_id)); break; @@ -1265,7 +1250,6 @@ void nexthop_group_interface_state_change(struct interface *ifp, if (ifp->ifindex != nhop.ifindex) continue; - ifp->configured = true; nh = nexthop_new(); memcpy(nh, &nhop, sizeof(nhop)); diff --git a/lib/northbound.c b/lib/northbound.c index 6edd5184ef..49adea6d53 100644 --- a/lib/northbound.c +++ b/lib/northbound.c @@ -830,8 +830,7 @@ int nb_candidate_validate(struct nb_context *context, struct nb_config_cbs changes; int ret; - if (nb_candidate_validate_yang(candidate, errmsg, sizeof(errmsg_len)) - != NB_OK) + if (nb_candidate_validate_yang(candidate, errmsg, errmsg_len) != NB_OK) return NB_ERR_VALIDATION; RB_INIT(nb_config_cbs, &changes); diff --git a/lib/northbound.h b/lib/northbound.h index bf04dbda17..a330bd1a30 100644 --- a/lib/northbound.h +++ b/lib/northbound.h @@ -488,7 +488,8 @@ struct nb_callbacks { * >0 when the CLI command for the dnode2 should be printed first * 0 when there is no difference */ - int (*cli_cmp)(struct lyd_node *dnode1, struct lyd_node *dnode2); + int (*cli_cmp)(const struct lyd_node *dnode1, + const struct lyd_node *dnode2); /* * Optional callback to show the CLI command associated to the given @@ -510,7 +511,7 @@ struct nb_callbacks { * nodes, in which case it might be desirable to hide one or more * parts of the command when this parameter is set to false. */ - void (*cli_show)(struct vty *vty, struct lyd_node *dnode, + void (*cli_show)(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); /* @@ -523,7 +524,7 @@ struct nb_callbacks { * libyang data node that should be shown in the form of a CLI * command. */ - void (*cli_show_end)(struct vty *vty, struct lyd_node *dnode); + void (*cli_show_end)(struct vty *vty, const struct lyd_node *dnode); }; struct nb_dependency_callbacks { diff --git a/lib/northbound_cli.c b/lib/northbound_cli.c index 6676c0b072..70c71b18c4 100644 --- a/lib/northbound_cli.c +++ b/lib/northbound_cli.c @@ -550,14 +550,16 @@ void nb_cli_show_config_prepare(struct nb_config *config, bool with_defaults) LYD_VALIDATE_NO_STATE, NULL); } -static int lyd_node_cmp(struct lyd_node **dnode1, struct lyd_node **dnode2) +static int lyd_node_cmp(const struct lyd_node **dnode1, + const struct lyd_node **dnode2) { struct nb_node *nb_node = (*dnode1)->schema->priv; return nb_node->cbs.cli_cmp(*dnode1, *dnode2); } -static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root, +static void show_dnode_children_cmds(struct vty *vty, + const struct lyd_node *root, bool with_defaults) { struct nb_node *nb_node, *sort_node = NULL; @@ -616,7 +618,7 @@ static void show_dnode_children_cmds(struct vty *vty, struct lyd_node *root, } } -void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *root, +void nb_cli_show_dnode_cmds(struct vty *vty, const struct lyd_node *root, bool with_defaults) { struct nb_node *nb_node; diff --git a/lib/northbound_cli.h b/lib/northbound_cli.h index 28f81f8b39..e472425447 100644 --- a/lib/northbound_cli.h +++ b/lib/northbound_cli.h @@ -127,7 +127,8 @@ extern int nb_cli_rpc(struct vty *vty, const char *xpath, struct list *input, * show_defaults * Specify whether to display default configuration values or not. */ -extern void nb_cli_show_dnode_cmds(struct vty *vty, struct lyd_node *dnode, +extern void nb_cli_show_dnode_cmds(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); /* diff --git a/lib/northbound_confd.c b/lib/northbound_confd.c index e62a83cee2..e1c8983fca 100644 --- a/lib/northbound_confd.c +++ b/lib/northbound_confd.c @@ -491,6 +491,47 @@ static void *thread_cdb_trigger_subscriptions(void *data) return NULL; } +static int frr_confd_subscribe(const struct lysc_node *snode, void *arg) +{ + struct yang_module *module = arg; + struct nb_node *nb_node; + int *spoint; + int ret; + + switch (snode->nodetype) { + case LYS_CONTAINER: + case LYS_LEAF: + case LYS_LEAFLIST: + case LYS_LIST: + break; + default: + return YANG_ITER_CONTINUE; + } + + if (CHECK_FLAG(snode->flags, LYS_CONFIG_R)) + return YANG_ITER_CONTINUE; + + nb_node = snode->priv; + if (!nb_node) + return YANG_ITER_CONTINUE; + + DEBUGD(&nb_dbg_client_confd, "%s: subscribing to '%s'", __func__, + nb_node->xpath); + + spoint = XMALLOC(MTYPE_CONFD, sizeof(*spoint)); + ret = cdb_subscribe2(cdb_sub_sock, CDB_SUB_RUNNING_TWOPHASE, + CDB_SUB_WANT_ABORT_ON_ABORT, 3, spoint, + module->confd_hash, nb_node->xpath); + if (ret != CONFD_OK) { + flog_err_confd("cdb_subscribe2"); + XFREE(MTYPE_CONFD, spoint); + return YANG_ITER_CONTINUE; + } + + listnode_add(confd_spoints, spoint); + return YANG_ITER_CONTINUE; +} + static int frr_confd_init_cdb(void) { struct yang_module *module; @@ -514,8 +555,6 @@ static int frr_confd_init_cdb(void) /* Subscribe to all loaded YANG data modules. */ confd_spoints = list_new(); RB_FOREACH (module, yang_modules, &yang_modules) { - struct lysc_node *snode; - module->confd_hash = confd_str2hash(module->info->ns); if (module->confd_hash == 0) { flog_err( @@ -530,42 +569,8 @@ static int frr_confd_init_cdb(void) * entire YANG module. So we have to find the top level * nodes ourselves and subscribe to their paths. */ - LY_LIST_FOR (module->info->data, snode) { - struct nb_node *nb_node; - int *spoint; - int ret; - - switch (snode->nodetype) { - case LYS_CONTAINER: - case LYS_LEAF: - case LYS_LEAFLIST: - case LYS_LIST: - break; - default: - continue; - } - - if (CHECK_FLAG(snode->flags, LYS_CONFIG_R)) - continue; - - nb_node = snode->priv; - if (!nb_node) - continue; - - DEBUGD(&nb_dbg_client_confd, "%s: subscribing to '%s'", - __func__, nb_node->xpath); - - spoint = XMALLOC(MTYPE_CONFD, sizeof(*spoint)); - ret = cdb_subscribe2( - cdb_sub_sock, CDB_SUB_RUNNING_TWOPHASE, - CDB_SUB_WANT_ABORT_ON_ABORT, 3, spoint, - module->confd_hash, nb_node->xpath); - if (ret != CONFD_OK) { - flog_err_confd("cdb_subscribe2"); - XFREE(MTYPE_CONFD, spoint); - } - listnode_add(confd_spoints, spoint); - } + yang_snodes_iterate(module->info, frr_confd_subscribe, 0, + module); } if (cdb_subscribe_done(cdb_sub_sock) != CONFD_OK) { @@ -705,7 +710,7 @@ static int frr_confd_data_get_next(struct confd_trans_ctx *tctx, confd_data_reply_next_key(tctx, v, keys.num, (long)nb_next); } else { - char pointer_str[16]; + char pointer_str[32]; /* * ConfD 6.6 user guide, chapter 6.11 (Operational data @@ -843,7 +848,7 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx, const void *nb_next; #define CONFD_OBJECTS_PER_TIME 100 struct confd_next_object objects[CONFD_OBJECTS_PER_TIME + 1]; - char pseudo_keys[CONFD_OBJECTS_PER_TIME][16]; + char pseudo_keys[CONFD_OBJECTS_PER_TIME][32]; int nobjects = 0; frr_confd_get_xpath(kp, xpath, sizeof(xpath)); @@ -868,7 +873,7 @@ static int frr_confd_data_get_next_object(struct confd_trans_ctx *tctx, memset(objects, 0, sizeof(objects)); for (int j = 0; j < CONFD_OBJECTS_PER_TIME; j++) { struct confd_next_object *object; - struct lysc_node *child; + const struct lysc_node *child; struct yang_data *data; size_t nvalues = 0; @@ -1189,6 +1194,8 @@ static int frr_confd_dp_ctl_read(struct thread *thread) thread_add_read(master, frr_confd_dp_ctl_read, dctx, fd, &t_dp_ctl); frr_confd_dp_read(dctx, fd); + + return 0; } static int frr_confd_dp_worker_read(struct thread *thread) @@ -1199,6 +1206,8 @@ static int frr_confd_dp_worker_read(struct thread *thread) thread_add_read(master, frr_confd_dp_worker_read, dctx, fd, &t_dp_worker); frr_confd_dp_read(dctx, fd); + + return 0; } static int frr_confd_subscribe_state(const struct lysc_node *snode, void *arg) @@ -50,7 +50,7 @@ struct pbr_filter { #define PBR_FILTER_SRC_PORT_RANGE (1 << 6) #define PBR_FILTER_DST_PORT_RANGE (1 << 7) #define PBR_FILTER_DSFIELD (1 << 8) -#define PBR_FILTER_IP_PROTOCOL (1 << 9) +#define PBR_FILTER_IP_PROTOCOL (1 << 9) #define PBR_DSFIELD_DSCP (0xfc) /* Upper 6 bits of DS field: DSCP */ #define PBR_DSFIELD_ECN (0x03) /* Lower 2 bits of DS field: BCN */ @@ -83,6 +83,13 @@ struct pbr_filter { * the user criteria may directly point to a table too. */ struct pbr_action { + /* VLAN */ + uint8_t pcp; + uint16_t vlan_id; + uint16_t vlan_flags; + + uint32_t queue_id; + uint32_t table; }; diff --git a/lib/plist.c b/lib/plist.c index 2f9f06f43b..d6a63c1b0c 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -1010,7 +1010,6 @@ static void vty_show_prefix_entry(struct vty *vty, json_object *json, afi_t afi, if (json) { json_object *json_entry; - char buf[BUFSIZ]; json_entry = json_object_new_object(); json_object_array_add(json_entries, json_entry); @@ -1021,10 +1020,9 @@ static void vty_show_prefix_entry(struct vty *vty, json_object *json, afi_t afi, json_object_string_add( json_entry, "type", prefix_list_type_str(pentry)); - json_object_string_add( - json_entry, "prefix", - prefix2str(&pentry->prefix, buf, - sizeof(buf))); + json_object_string_addf(json_entry, "prefix", + "%pFX", + &pentry->prefix); if (pentry->ge) json_object_int_add( @@ -1127,14 +1125,7 @@ static int vty_show_prefix_list(struct vty *vty, afi_t afi, const char *name, master, dtype, seqnum); } - 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; + return vty_json(vty, json); } static int vty_show_prefix_list_prefix(struct vty *vty, afi_t afi, @@ -1489,9 +1480,9 @@ int prefix_bgp_orf_set(char *name, afi_t afi, struct orf_prefix *orfp, struct prefix_list_entry *pentry; /* ge and le value check */ - if (orfp->ge && orfp->ge <= orfp->p.prefixlen) + if (orfp->ge && orfp->ge < orfp->p.prefixlen) return CMD_WARNING_CONFIG_FAILED; - if (orfp->le && orfp->le <= orfp->p.prefixlen) + if (orfp->le && orfp->le < orfp->p.prefixlen) return CMD_WARNING_CONFIG_FAILED; if (orfp->le && orfp->ge > orfp->le) return CMD_WARNING_CONFIG_FAILED; @@ -1592,9 +1583,7 @@ int prefix_bgp_show_prefix_list(struct vty *vty, afi_t afi, char *name, json_object_object_add(json, "ipv6PrefixList", json_prefix); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { vty_out(vty, "ip%s prefix-list %s: %d entries\n", afi == AFI_IP ? "" : "v6", plist->name, plist->count); @@ -1668,6 +1657,8 @@ static const struct cmd_variable_handler plist_var_handlers[] = { {/* "prefix-list WORD" */ .varname = "prefix_list", .completions = plist_autocomplete}, + {.tokenname = "PREFIXLIST_NAME", + .completions = plist_autocomplete}, {.completions = NULL}}; diff --git a/lib/prefix.c b/lib/prefix.c index ef7d2e59da..df753fe10b 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -113,7 +113,7 @@ const char *family2str(int family) return "?"; } -/* Address Famiy Identifier to Address Family converter. */ +/* Address Family Identifier to Address Family converter. */ int afi2family(afi_t afi) { if (afi == AFI_IP) diff --git a/lib/resolver.c b/lib/resolver.c index 4aba909f25..29138bbc8d 100644 --- a/lib/resolver.c +++ b/lib/resolver.c @@ -14,12 +14,14 @@ #include <ares.h> #include <ares_version.h> -#include "vector.h" +#include "typesafe.h" +#include "jhash.h" #include "thread.h" #include "lib_errors.h" #include "resolver.h" #include "command.h" #include "xref.h" +#include "vrf.h" XREF_SETUP(); @@ -27,13 +29,78 @@ struct resolver_state { ares_channel channel; struct thread_master *master; struct thread *timeout; - vector read_threads, write_threads; }; static struct resolver_state state; static bool resolver_debug; -#define THREAD_RUNNING ((struct thread *)-1) +/* a FD doesn't necessarily map 1:1 to a request; we could be talking to + * multiple caches simultaneously, to see which responds fastest. + * Theoretically we could also be using the same fd for multiple lookups, + * but the c-ares API guarantees an n:1 mapping for fd => channel. + * + * Either way c-ares makes that decision and we just need to deal with + * whatever FDs it gives us. + */ + +DEFINE_MTYPE_STATIC(LIB, ARES_FD, "c-ares (DNS) file descriptor information"); +PREDECL_HASH(resolver_fds); + +struct resolver_fd { + struct resolver_fds_item itm; + + int fd; + struct resolver_state *state; + struct thread *t_read, *t_write; +}; + +static int resolver_fd_cmp(const struct resolver_fd *a, + const struct resolver_fd *b) +{ + return numcmp(a->fd, b->fd); +} + +static uint32_t resolver_fd_hash(const struct resolver_fd *item) +{ + return jhash_1word(item->fd, 0xacd04c9e); +} + +DECLARE_HASH(resolver_fds, struct resolver_fd, itm, resolver_fd_cmp, + resolver_fd_hash); + +static struct resolver_fds_head resfds[1] = {INIT_HASH(resfds[0])}; + +static struct resolver_fd *resolver_fd_get(int fd, + struct resolver_state *newstate) +{ + struct resolver_fd ref = {.fd = fd}, *res; + + res = resolver_fds_find(resfds, &ref); + if (!res && newstate) { + res = XCALLOC(MTYPE_ARES_FD, sizeof(*res)); + res->fd = fd; + res->state = newstate; + resolver_fds_add(resfds, res); + + if (resolver_debug) + zlog_debug("c-ares registered FD %d", fd); + } + return res; +} + +static void resolver_fd_drop_maybe(struct resolver_fd *resfd) +{ + if (resfd->t_read || resfd->t_write) + return; + + if (resolver_debug) + zlog_debug("c-ares unregistered FD %d", resfd->fd); + + resolver_fds_del(resfds, resfd); + XFREE(MTYPE_ARES_FD, resfd); +} + +/* end of FD housekeeping */ static void resolver_update_timeouts(struct resolver_state *r); @@ -41,9 +108,7 @@ static int resolver_cb_timeout(struct thread *t) { struct resolver_state *r = THREAD_ARG(t); - r->timeout = THREAD_RUNNING; ares_process(r->channel, NULL, NULL); - r->timeout = NULL; resolver_update_timeouts(r); return 0; @@ -51,17 +116,16 @@ static int resolver_cb_timeout(struct thread *t) static int resolver_cb_socket_readable(struct thread *t) { - struct resolver_state *r = THREAD_ARG(t); - int fd = THREAD_FD(t); - struct thread **t_ptr; - - vector_set_index(r->read_threads, fd, THREAD_RUNNING); - ares_process_fd(r->channel, fd, ARES_SOCKET_BAD); - if (vector_lookup(r->read_threads, fd) == THREAD_RUNNING) { - t_ptr = (struct thread **)vector_get_index(r->read_threads, fd); - thread_add_read(r->master, resolver_cb_socket_readable, r, fd, - t_ptr); - } + struct resolver_fd *resfd = THREAD_ARG(t); + struct resolver_state *r = resfd->state; + + thread_add_read(r->master, resolver_cb_socket_readable, resfd, + resfd->fd, &resfd->t_read); + /* ^ ordering important: + * ares_process_fd may transitively call THREAD_OFF(resfd->t_read) + * combined with resolver_fd_drop_maybe, so resfd may be free'd after! + */ + ares_process_fd(r->channel, resfd->fd, ARES_SOCKET_BAD); resolver_update_timeouts(r); return 0; @@ -69,17 +133,16 @@ static int resolver_cb_socket_readable(struct thread *t) static int resolver_cb_socket_writable(struct thread *t) { - struct resolver_state *r = THREAD_ARG(t); - int fd = THREAD_FD(t); - struct thread **t_ptr; - - vector_set_index(r->write_threads, fd, THREAD_RUNNING); - ares_process_fd(r->channel, ARES_SOCKET_BAD, fd); - if (vector_lookup(r->write_threads, fd) == THREAD_RUNNING) { - t_ptr = (struct thread **)vector_get_index(r->write_threads, fd); - thread_add_write(r->master, resolver_cb_socket_writable, r, fd, - t_ptr); - } + struct resolver_fd *resfd = THREAD_ARG(t); + struct resolver_state *r = resfd->state; + + thread_add_write(r->master, resolver_cb_socket_writable, resfd, + resfd->fd, &resfd->t_write); + /* ^ ordering important: + * ares_process_fd may transitively call THREAD_OFF(resfd->t_write) + * combined with resolver_fd_drop_maybe, so resfd may be free'd after! + */ + ares_process_fd(r->channel, ARES_SOCKET_BAD, resfd->fd); resolver_update_timeouts(r); return 0; @@ -89,13 +152,11 @@ static void resolver_update_timeouts(struct resolver_state *r) { struct timeval *tv, tvbuf; - if (r->timeout == THREAD_RUNNING) - return; - THREAD_OFF(r->timeout); tv = ares_timeout(r->channel, NULL, &tvbuf); if (tv) { unsigned int timeoutms = tv->tv_sec * 1000 + tv->tv_usec / 1000; + thread_add_timer_msec(r->master, resolver_cb_timeout, r, timeoutms, &r->timeout); } @@ -105,43 +166,27 @@ static void ares_socket_cb(void *data, ares_socket_t fd, int readable, int writable) { struct resolver_state *r = (struct resolver_state *)data; - struct thread *t, **t_ptr; - - if (readable) { - t = vector_lookup(r->read_threads, fd); - if (!t) { - t_ptr = (struct thread **)vector_get_index( - r->read_threads, fd); - thread_add_read(r->master, resolver_cb_socket_readable, - r, fd, t_ptr); - } - } else { - t = vector_lookup(r->read_threads, fd); - if (t) { - if (t != THREAD_RUNNING) { - THREAD_OFF(t); - } - vector_unset(r->read_threads, fd); - } - } + struct resolver_fd *resfd; - if (writable) { - t = vector_lookup(r->write_threads, fd); - if (!t) { - t_ptr = (struct thread **)vector_get_index( - r->write_threads, fd); - thread_add_read(r->master, resolver_cb_socket_writable, - r, fd, t_ptr); - } - } else { - t = vector_lookup(r->write_threads, fd); - if (t) { - if (t != THREAD_RUNNING) { - THREAD_OFF(t); - } - vector_unset(r->write_threads, fd); - } - } + resfd = resolver_fd_get(fd, (readable || writable) ? r : NULL); + if (!resfd) + return; + + assert(resfd->state == r); + + if (!readable) + THREAD_OFF(resfd->t_read); + else if (!resfd->t_read) + thread_add_read(r->master, resolver_cb_socket_readable, resfd, + fd, &resfd->t_read); + + if (!writable) + THREAD_OFF(resfd->t_write); + else if (!resfd->t_write) + thread_add_write(r->master, resolver_cb_socket_writable, resfd, + fd, &resfd->t_write); + + resolver_fd_drop_maybe(resfd); } @@ -200,7 +245,7 @@ static int resolver_cb_literal(struct thread *t) return 0; } -void resolver_resolve(struct resolver_query *query, int af, +void resolver_resolve(struct resolver_query *query, int af, vrf_id_t vrf_id, const char *hostname, void (*callback)(struct resolver_query *, const char *, int, union sockunion *)) @@ -235,7 +280,18 @@ void resolver_resolve(struct resolver_query *query, int af, if (resolver_debug) zlog_debug("[%p] Resolving '%s'", query, hostname); + ret = vrf_switch_to_netns(vrf_id); + if (ret < 0) { + flog_err_sys(EC_LIB_SOCKET, "%s: Can't switch to VRF %u (%s)", + __func__, vrf_id, safe_strerror(errno)); + return; + } ares_gethostbyname(state.channel, hostname, af, ares_address_cb, query); + ret = vrf_switchback_to_initial(); + if (ret < 0) + flog_err_sys(EC_LIB_SOCKET, + "%s: Can't switchback from VRF %u (%s)", __func__, + vrf_id, safe_strerror(errno)); resolver_update_timeouts(&state); } @@ -271,8 +327,6 @@ void resolver_init(struct thread_master *tm) struct ares_options ares_opts; state.master = tm; - state.read_threads = vector_init(1); - state.write_threads = vector_init(1); ares_opts = (struct ares_options){ .sock_state_cb = &ares_socket_cb, diff --git a/lib/resolver.h b/lib/resolver.h index 5f922dcb57..988449693c 100644 --- a/lib/resolver.h +++ b/lib/resolver.h @@ -27,10 +27,10 @@ struct resolver_query { }; void resolver_init(struct thread_master *tm); -void resolver_resolve(struct resolver_query *query, int af, - const char *hostname, void (*cb)(struct resolver_query *, - const char *, int, - union sockunion *)); +void resolver_resolve(struct resolver_query *query, int af, vrf_id_t vrf_id, + const char *hostname, + void (*cb)(struct resolver_query *, const char *, int, + union sockunion *)); #ifdef __cplusplus } diff --git a/lib/route_opaque.h b/lib/route_opaque.h index 7c4e9a16e1..c5e7d6a327 100644 --- a/lib/route_opaque.h +++ b/lib/route_opaque.h @@ -36,6 +36,12 @@ struct bgp_zebra_opaque { /* Show at least 10 large-communities AA:BB:CC */ char lcommunity[LCOMMUNITY_SIZE * 30]; + + /* 32 bytes seems enough because of + * bgp_path_selection_confed_as_path which is + * `Confederation based AS Path`. + */ + char selection_reason[BGP_MAX_SELECTION_REASON_STR_BUF]; }; static_assert(sizeof(struct bgp_zebra_opaque) <= ZAPI_MESSAGE_OPAQUE_LENGTH, diff --git a/lib/routemap.c b/lib/routemap.c index 5c60b7d1c6..7f733c8114 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -34,6 +34,7 @@ #include "lib_errors.h" #include "table.h" #include "json.h" +#include "jhash.h" DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map"); DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name"); @@ -47,6 +48,27 @@ DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data"); DEFINE_QOBJ_TYPE(route_map_index); DEFINE_QOBJ_TYPE(route_map); +static int rmap_cmd_name_cmp(const struct route_map_rule_cmd_proxy *a, + const struct route_map_rule_cmd_proxy *b) +{ + return strcmp(a->cmd->str, b->cmd->str); +} + +static uint32_t rmap_cmd_name_hash(const struct route_map_rule_cmd_proxy *item) +{ + return jhash(item->cmd->str, strlen(item->cmd->str), 0xbfd69320); +} + +DECLARE_HASH(rmap_cmd_name, struct route_map_rule_cmd_proxy, itm, + rmap_cmd_name_cmp, rmap_cmd_name_hash); + +static struct rmap_cmd_name_head rmap_match_cmds[1] = { + INIT_HASH(rmap_match_cmds[0]), +}; +static struct rmap_cmd_name_head rmap_set_cmds[1] = { + INIT_HASH(rmap_set_cmds[0]), +}; + #define IPv4_PREFIX_LIST "ip address prefix-list" #define IPv6_PREFIX_LIST "ipv6 address prefix-list" @@ -61,12 +83,6 @@ struct route_map_pentry_dep { route_map_event_t event; }; -/* Vector for route match rules. */ -static vector route_match_vec; - -/* Vector for route set rules. */ -static vector route_set_vec; - static void route_map_pfx_tbl_update(route_map_event_t event, struct route_map_index *index, afi_t afi, const char *plist_name); @@ -159,6 +175,22 @@ void route_map_no_match_ip_next_hop_hook(int (*func)( rmap_match_set_hook.no_match_ip_next_hop = func; } +/* match ipv6 next-hop */ +void route_map_match_ipv6_next_hop_hook(int (*func)( + struct route_map_index *index, const char *command, const char *arg, + route_map_event_t type, char *errmsg, size_t errmsg_len)) +{ + rmap_match_set_hook.match_ipv6_next_hop = func; +} + +/* no match ipv6 next-hop */ +void route_map_no_match_ipv6_next_hop_hook(int (*func)( + struct route_map_index *index, const char *command, const char *arg, + route_map_event_t type, char *errmsg, size_t errmsg_len)) +{ + rmap_match_set_hook.no_match_ipv6_next_hop = func; +} + /* match ip next hop prefix list */ void route_map_match_ip_next_hop_prefix_list_hook(int (*func)( struct route_map_index *index, const char *command, @@ -250,6 +282,22 @@ void route_map_no_match_ipv6_next_hop_type_hook(int (*func)( rmap_match_set_hook.no_match_ipv6_next_hop_type = func; } +/* match ipv6 next-hop prefix-list */ +void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func)( + struct route_map_index *index, const char *command, const char *arg, + route_map_event_t type, char *errmsg, size_t errmsg_len)) +{ + rmap_match_set_hook.match_ipv6_next_hop_prefix_list = func; +} + +/* no match ipv6 next-hop prefix-list */ +void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func)( + struct route_map_index *index, const char *command, const char *arg, + route_map_event_t type, char *errmsg, size_t errmsg_len)) +{ + rmap_match_set_hook.no_match_ipv6_next_hop_prefix_list = func; +} + /* match metric */ void route_map_match_metric_hook(int (*func)( struct route_map_index *index, const char *command, @@ -1026,14 +1074,7 @@ static int vty_show_route_map(struct vty *vty, const char *name, bool use_json) list_delete(&maplist); } - if (use_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } - - return CMD_SUCCESS; + return vty_json(vty, json); } /* Unused route map details */ @@ -1231,40 +1272,40 @@ static struct route_map_rule *route_map_rule_new(void) } /* Install rule command to the match list. */ -void route_map_install_match(const struct route_map_rule_cmd *cmd) +void _route_map_install_match(struct route_map_rule_cmd_proxy *proxy) { - vector_set(route_match_vec, (void *)cmd); + rmap_cmd_name_add(rmap_match_cmds, proxy); } /* Install rule command to the set list. */ -void route_map_install_set(const struct route_map_rule_cmd *cmd) +void _route_map_install_set(struct route_map_rule_cmd_proxy *proxy) { - vector_set(route_set_vec, (void *)cmd); + rmap_cmd_name_add(rmap_set_cmds, proxy); } /* Lookup rule command from match list. */ static const struct route_map_rule_cmd *route_map_lookup_match(const char *name) { - unsigned int i; - const struct route_map_rule_cmd *rule; + struct route_map_rule_cmd refcmd = {.str = name}; + struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd}; + struct route_map_rule_cmd_proxy *res; - for (i = 0; i < vector_active(route_match_vec); i++) - if ((rule = vector_slot(route_match_vec, i)) != NULL) - if (strcmp(rule->str, name) == 0) - return rule; + res = rmap_cmd_name_find(rmap_match_cmds, &ref); + if (res) + return res->cmd; return NULL; } /* Lookup rule command from set list. */ static const struct route_map_rule_cmd *route_map_lookup_set(const char *name) { - unsigned int i; - const struct route_map_rule_cmd *rule; + struct route_map_rule_cmd refcmd = {.str = name}; + struct route_map_rule_cmd_proxy ref = {.cmd = &refcmd}; + struct route_map_rule_cmd_proxy *res; - for (i = 0; i < vector_active(route_set_vec); i++) - if ((rule = vector_slot(route_set_vec, i)) != NULL) - if (strcmp(rule->str, name) == 0) - return rule; + res = rmap_cmd_name_find(rmap_set_cmds, &ref); + if (res) + return res->cmd; return NULL; } @@ -2480,7 +2521,7 @@ void route_map_notify_pentry_dependencies(const char *affected_name, do whatever the exit policy (EXIT, NEXT or GOTO) tells. on-match next - If this clause is matched, then the set statements are executed and then we drop through to the next clause - on-match goto n - If this clause is matched, then the set statments + on-match goto n - If this clause is matched, then the set statements are executed and then we goto the nth clause, or the first clause greater than this. In order to ensure route-maps *always* exit, you cannot jump backwards. @@ -3161,11 +3202,21 @@ void route_map_rule_tag_free(void *rule) void route_map_finish(void) { int i; + struct route_map_rule_cmd_proxy *proxy; + + /* these 2 hash tables have INIT_HASH initializers, so the "default" + * state is "initialized & empty" => fini() followed by init() to + * return to that same state + */ + while ((proxy = rmap_cmd_name_pop(rmap_match_cmds))) + (void)proxy; + rmap_cmd_name_fini(rmap_match_cmds); + rmap_cmd_name_init(rmap_match_cmds); - vector_free(route_match_vec); - route_match_vec = NULL; - vector_free(route_set_vec); - route_set_vec = NULL; + while ((proxy = rmap_cmd_name_pop(rmap_set_cmds))) + (void)proxy; + rmap_cmd_name_fini(rmap_set_cmds); + rmap_cmd_name_init(rmap_set_cmds); /* * All protocols are setting these to NULL @@ -3309,9 +3360,6 @@ void route_map_init(void) { int i; - /* Make vector for match and set. */ - route_match_vec = vector_init(1); - route_set_vec = vector_init(1); route_map_master_hash = hash_create_size(8, route_map_hash_key_make, route_map_hash_cmp, "Route Map Master Hash"); diff --git a/lib/routemap.h b/lib/routemap.h index 2c8eb24537..6c4916898a 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -21,6 +21,7 @@ #ifndef _ZEBRA_ROUTEMAP_H #define _ZEBRA_ROUTEMAP_H +#include "typesafe.h" #include "prefix.h" #include "memory.h" #include "qobj.h" @@ -243,12 +244,16 @@ DECLARE_QOBJ_TYPE(route_map); (strmatch(C, "frr-route-map:ipv6-address-list")) #define IS_MATCH_IPv4_NEXTHOP_LIST(C) \ (strmatch(C, "frr-route-map:ipv4-next-hop-list")) +#define IS_MATCH_IPv6_NEXTHOP_LIST(C) \ + (strmatch(C, "frr-route-map:ipv6-next-hop-list")) #define IS_MATCH_IPv4_PREFIX_LIST(C) \ (strmatch(C, "frr-route-map:ipv4-prefix-list")) #define IS_MATCH_IPv6_PREFIX_LIST(C) \ (strmatch(C, "frr-route-map:ipv6-prefix-list")) #define IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(C) \ (strmatch(C, "frr-route-map:ipv4-next-hop-prefix-list")) +#define IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(C) \ + (strmatch(C, "frr-route-map:ipv6-next-hop-prefix-list")) #define IS_MATCH_IPv4_NEXTHOP_TYPE(C) \ (strmatch(C, "frr-route-map:ipv4-next-hop-type")) #define IS_MATCH_IPv6_NEXTHOP_TYPE(C) \ @@ -422,8 +427,37 @@ extern enum rmap_compile_rets route_map_delete_set(struct route_map_index *index, const char *set_name, const char *set_arg); +/* struct route_map_rule_cmd is kept const in order to not have writable + * function pointers (which is a security benefit.) Hence, below struct is + * used as proxy for hashing these for by-name lookup. + */ + +PREDECL_HASH(rmap_cmd_name); + +struct route_map_rule_cmd_proxy { + struct rmap_cmd_name_item itm; + const struct route_map_rule_cmd *cmd; +}; + +/* ... and just automatically create a proxy struct for each call location + * to route_map_install_{match,set} to avoid unnecessarily added boilerplate + * for each route-map user + */ + +#define route_map_install_match(c) \ + do { \ + static struct route_map_rule_cmd_proxy proxy = {.cmd = c}; \ + _route_map_install_match(&proxy); \ + } while (0) + +#define route_map_install_set(c) \ + do { \ + static struct route_map_rule_cmd_proxy proxy = {.cmd = c}; \ + _route_map_install_set(&proxy); \ + } while (0) + /* Install rule command to the match list. */ -extern void route_map_install_match(const struct route_map_rule_cmd *cmd); +extern void _route_map_install_match(struct route_map_rule_cmd_proxy *proxy); /* * Install rule command to the set list. @@ -434,7 +468,7 @@ extern void route_map_install_match(const struct route_map_rule_cmd *cmd); * in the apply command). See 'set metric' command * as it is handled in ripd/ripngd and ospfd. */ -extern void route_map_install_set(const struct route_map_rule_cmd *cmd); +extern void _route_map_install_set(struct route_map_rule_cmd_proxy *proxy); /* Lookup route map by name. */ extern struct route_map *route_map_lookup_by_name(const char *name); @@ -525,9 +559,16 @@ extern void route_map_match_ip_next_hop_hook(int (*func)( char *errmsg, size_t errmsg_len)); /* no match ip next hop */ extern void route_map_no_match_ip_next_hop_hook(int (*func)( - struct route_map_index *index, const char *command, - const char *arg, route_map_event_t type, - char *errmsg, size_t errmsg_len)); + struct route_map_index *index, const char *command, const char *arg, + route_map_event_t type, char *errmsg, size_t errmsg_len)); +/* match ipv6 next hop */ +extern void route_map_match_ipv6_next_hop_hook(int (*func)( + struct route_map_index *index, const char *command, const char *arg, + route_map_event_t type, char *errmsg, size_t errmsg_len)); +/* no match ipv6 next hop */ +extern void route_map_no_match_ipv6_next_hop_hook(int (*func)( + struct route_map_index *index, const char *command, const char *arg, + route_map_event_t type, char *errmsg, size_t errmsg_len)); /* match ip next hop prefix list */ extern void route_map_match_ip_next_hop_prefix_list_hook(int (*func)( struct route_map_index *index, const char *command, @@ -578,6 +619,14 @@ extern void route_map_no_match_ipv6_next_hop_type_hook(int (*func)( struct route_map_index *index, const char *command, const char *arg, route_map_event_t type, char *errmsg, size_t errmsg_len)); +/* match ipv6 next-hop prefix-list */ +extern void route_map_match_ipv6_next_hop_prefix_list_hook(int (*func)( + struct route_map_index *index, const char *command, const char *arg, + route_map_event_t type, char *errmsg, size_t errmsg_len)); +/* no match ipv6 next-hop prefix-list */ +extern void route_map_no_match_ipv6_next_hop_prefix_list_hook(int (*func)( + struct route_map_index *index, const char *command, const char *arg, + route_map_event_t type, char *errmsg, size_t errmsg_len)); /* match metric */ extern void route_map_match_metric_hook(int (*func)( struct route_map_index *index, const char *command, @@ -713,6 +762,33 @@ struct route_map_match_set_hooks { route_map_event_t type, char *errmsg, size_t errmsg_len); + /* match ipv6 next hop */ + int (*match_ipv6_next_hop)(struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type, char *errmsg, + size_t errmsg_len); + + /* no match ipv6 next hop */ + int (*no_match_ipv6_next_hop)(struct route_map_index *index, + const char *command, const char *arg, + route_map_event_t type, char *errmsg, + size_t errmsg_len); + + /* match ipv6 next hop prefix-list */ + int (*match_ipv6_next_hop_prefix_list)(struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type, + char *errmsg, size_t errmsg_len); + + /* no match ipv6 next-hop prefix-list */ + int (*no_match_ipv6_next_hop_prefix_list)(struct route_map_index *index, + const char *command, + const char *arg, + route_map_event_t type, + char *errmsg, + size_t errmsg_len); + /* match ip next hop prefix list */ int (*match_ip_next_hop_prefix_list)(struct route_map_index *index, const char *command, @@ -908,25 +984,28 @@ void routemap_hook_context_free(struct routemap_hook_context *rhc); extern const struct frr_yang_module_info frr_route_map_info; /* routemap_cli.c */ -extern int route_map_instance_cmp(struct lyd_node *dnode1, - struct lyd_node *dnode2); -extern void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, +extern int route_map_instance_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2); +extern void route_map_instance_show(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); extern void route_map_instance_show_end(struct vty *vty, - struct lyd_node *dnode); -extern void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, + const struct lyd_node *dnode); +extern void route_map_condition_show(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -extern void route_map_action_show(struct vty *vty, struct lyd_node *dnode, +extern void route_map_action_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -extern void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode, +extern void route_map_exit_policy_show(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -extern void route_map_call_show(struct vty *vty, struct lyd_node *dnode, +extern void route_map_call_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); extern void route_map_description_show(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); extern void route_map_optimization_disabled_show(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); extern void route_map_cli_init(void); diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index cadad15fa7..2685bd2d79 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -41,7 +41,7 @@ DEFPY_YANG_NOSH( route_map, route_map_cmd, - "route-map WORD$name <deny|permit>$action (1-65535)$sequence", + "route-map RMAP_NAME$name <deny|permit>$action (1-65535)$sequence", ROUTE_MAP_CMD_STR ROUTE_MAP_OP_CMD_STR ROUTE_MAP_SEQUENCE_CMD_STR) @@ -71,7 +71,7 @@ DEFPY_YANG_NOSH( DEFPY_YANG( no_route_map_all, no_route_map_all_cmd, - "no route-map WORD$name", + "no route-map RMAP_NAME$name", NO_STR ROUTE_MAP_CMD_STR) { @@ -86,7 +86,7 @@ DEFPY_YANG( DEFPY_YANG( no_route_map, no_route_map_cmd, - "no route-map WORD$name <deny|permit>$action (1-65535)$sequence", + "no route-map RMAP_NAME$name <deny|permit>$action (1-65535)$sequence", NO_STR ROUTE_MAP_CMD_STR ROUTE_MAP_OP_CMD_STR @@ -103,7 +103,8 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -int route_map_instance_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +int route_map_instance_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { uint16_t seq1 = yang_dnode_get_uint16(dnode1, "./sequence"); uint16_t seq2 = yang_dnode_get_uint16(dnode2, "./sequence"); @@ -111,7 +112,7 @@ int route_map_instance_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) return seq1 - seq2; } -void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, +void route_map_instance_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *name = yang_dnode_get_string(dnode, "../name"); @@ -122,7 +123,7 @@ void route_map_instance_show(struct vty *vty, struct lyd_node *dnode, } -void route_map_instance_show_end(struct vty *vty, struct lyd_node *dnode) +void route_map_instance_show_end(struct vty *vty, const struct lyd_node *dnode) { vty_out(vty, "exit\n"); vty_out(vty, "!\n"); @@ -165,12 +166,10 @@ DEFPY_YANG( DEFPY_YANG( match_ip_address, match_ip_address_cmd, - "match ip address <(1-199)|(1300-2699)|WORD>$name", + "match ip address ACCESSLIST4_NAME$name", MATCH_STR IP_STR "Match address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n") { const char *xpath = @@ -187,13 +186,11 @@ DEFPY_YANG( DEFPY_YANG( no_match_ip_address, no_match_ip_address_cmd, - "no match ip address [<(1-199)|(1300-2699)|WORD>]", + "no match ip address [ACCESSLIST4_NAME]", NO_STR MATCH_STR IP_STR "Match address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n") { const char *xpath = @@ -207,7 +204,7 @@ DEFPY_YANG( DEFPY_YANG( match_ip_address_prefix_list, match_ip_address_prefix_list_cmd, - "match ip address prefix-list WORD$name", + "match ip address prefix-list PREFIXLIST_NAME$name", MATCH_STR IP_STR "Match address of route\n" @@ -228,7 +225,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ip_address_prefix_list, no_match_ip_address_prefix_list_cmd, - "no match ip address prefix-list [WORD]", + "no match ip address prefix-list [PREFIXLIST_NAME]", NO_STR MATCH_STR IP_STR @@ -246,12 +243,10 @@ DEFPY_YANG( DEFPY_YANG( match_ip_next_hop, match_ip_next_hop_cmd, - "match ip next-hop <(1-199)|(1300-2699)|WORD>$name", + "match ip next-hop ACCESSLIST4_NAME$name", MATCH_STR IP_STR "Match next-hop address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n") { const char *xpath = @@ -268,13 +263,11 @@ DEFPY_YANG( DEFPY_YANG( no_match_ip_next_hop, no_match_ip_next_hop_cmd, - "no match ip next-hop [<(1-199)|(1300-2699)|WORD>]", + "no match ip next-hop [ACCESSLIST4_NAME]", NO_STR MATCH_STR IP_STR "Match address of route\n" - "IP access-list number\n" - "IP access-list number (expanded range)\n" "IP Access-list name\n") { const char *xpath = @@ -288,7 +281,7 @@ DEFPY_YANG( DEFPY_YANG( match_ip_next_hop_prefix_list, match_ip_next_hop_prefix_list_cmd, - "match ip next-hop prefix-list WORD$name", + "match ip next-hop prefix-list PREFIXLIST_NAME$name", MATCH_STR IP_STR "Match next-hop address of route\n" @@ -310,7 +303,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ip_next_hop_prefix_list, no_match_ip_next_hop_prefix_list_cmd, - "no match ip next-hop prefix-list [WORD]", + "no match ip next-hop prefix-list [PREFIXLIST_NAME]", NO_STR MATCH_STR IP_STR @@ -365,7 +358,7 @@ DEFPY_YANG( DEFPY_YANG( match_ipv6_address, match_ipv6_address_cmd, - "match ipv6 address WORD$name", + "match ipv6 address ACCESSLIST6_NAME$name", MATCH_STR IPV6_STR "Match IPv6 address of route\n" @@ -385,7 +378,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ipv6_address, no_match_ipv6_address_cmd, - "no match ipv6 address [WORD]", + "no match ipv6 address [ACCESSLIST6_NAME]", NO_STR MATCH_STR IPV6_STR @@ -402,7 +395,7 @@ DEFPY_YANG( DEFPY_YANG( match_ipv6_address_prefix_list, match_ipv6_address_prefix_list_cmd, - "match ipv6 address prefix-list WORD$name", + "match ipv6 address prefix-list PREFIXLIST_NAME$name", MATCH_STR IPV6_STR "Match address of route\n" @@ -424,7 +417,7 @@ DEFPY_YANG( DEFPY_YANG( no_match_ipv6_address_prefix_list, no_match_ipv6_address_prefix_list_cmd, - "no match ipv6 address prefix-list [WORD]", + "no match ipv6 address prefix-list [PREFIXLIST_NAME]", NO_STR MATCH_STR IPV6_STR @@ -546,31 +539,29 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, +void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *condition = yang_dnode_get_string(dnode, "./condition"); - struct lyd_node *ln; + const struct lyd_node *ln; const char *acl; if (IS_MATCH_INTERFACE(condition)) { vty_out(vty, " match interface %s\n", yang_dnode_get_string( dnode, "./rmap-match-condition/interface")); - } else if (IS_MATCH_IPv4_ADDRESS_LIST(condition) - || IS_MATCH_IPv4_NEXTHOP_LIST(condition)) { - acl = NULL; - if ((ln = yang_dnode_get(dnode, - "./rmap-match-condition/list-name")) - != NULL) - acl = yang_dnode_get_string(ln, NULL); - - assert(acl); - - if (IS_MATCH_IPv4_ADDRESS_LIST(condition)) - vty_out(vty, " match ip address %s\n", acl); - else - vty_out(vty, " match ip next-hop %s\n", acl); + } else if (IS_MATCH_IPv4_ADDRESS_LIST(condition)) { + vty_out(vty, " match ip address %s\n", + yang_dnode_get_string( + dnode, "./rmap-match-condition/list-name")); + } else if (IS_MATCH_IPv4_NEXTHOP_LIST(condition)) { + vty_out(vty, " match ip next-hop %s\n", + yang_dnode_get_string( + dnode, "./rmap-match-condition/list-name")); + } else if (IS_MATCH_IPv6_NEXTHOP_LIST(condition)) { + vty_out(vty, " match ipv6 next-hop %s\n", + yang_dnode_get_string( + dnode, "./rmap-match-condition/list-name")); } else if (IS_MATCH_IPv4_PREFIX_LIST(condition)) { vty_out(vty, " match ip address prefix-list %s\n", yang_dnode_get_string( @@ -579,6 +570,10 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, vty_out(vty, " match ip next-hop prefix-list %s\n", yang_dnode_get_string( dnode, "./rmap-match-condition/list-name")); + } else if (IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(condition)) { + vty_out(vty, " match ipv6 next-hop prefix-list %s\n", + yang_dnode_get_string( + dnode, "./rmap-match-condition/list-name")); } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) { vty_out(vty, " match ipv6 address %s\n", yang_dnode_get_string( @@ -719,91 +714,47 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode, dnode, "./rmap-match-condition/frr-bgp-route-map:list-name")); } else if (IS_MATCH_ROUTE_SRC(condition)) { - acl = NULL; - if ((ln = yang_dnode_get( - dnode, - "./rmap-match-condition/frr-bgp-route-map:list-name")) - != NULL) - acl = yang_dnode_get_string(ln, NULL); - - assert(acl); - - vty_out(vty, " match ip route-source %s\n", acl); + vty_out(vty, " match ip route-source %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:list-name")); } else if (IS_MATCH_ROUTE_SRC_PL(condition)) { vty_out(vty, " match ip route-source prefix-list %s\n", yang_dnode_get_string( dnode, "./rmap-match-condition/frr-bgp-route-map:list-name")); - } else if (IS_MATCH_ROUTE_SRC(condition)) { - acl = NULL; - if ((ln = yang_dnode_get( - dnode, - "./rmap-match-condition/frr-bgp-route-map:list-name")) - != NULL) - acl = yang_dnode_get_string(ln, NULL); - - assert(acl); - - vty_out(vty, " match ip route-source %s\n", acl); } else if (IS_MATCH_COMMUNITY(condition)) { - acl = NULL; - if ((ln = yang_dnode_get( - dnode, - "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name")) - != NULL) { - acl = yang_dnode_get_string(ln, NULL); - - if (true - == yang_dnode_get_bool( - dnode, - "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) - vty_out(vty, - " match community %s exact-match\n", - acl); - else - vty_out(vty, " match community %s\n", acl); - } - - assert(acl); + vty_out(vty, " match community %s", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name")); + if (yang_dnode_get_bool( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) + vty_out(vty, " exact-match"); + vty_out(vty, "\n"); } else if (IS_MATCH_LCOMMUNITY(condition)) { - acl = NULL; - if ((ln = yang_dnode_get( - dnode, - "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name")) - != NULL) { - acl = yang_dnode_get_string(ln, NULL); - - if (true - == yang_dnode_get_bool( - dnode, - "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) - vty_out(vty, - " match large-community %s exact-match\n", - acl); - else - vty_out(vty, " match large-community %s\n", - acl); - } - - assert(acl); + vty_out(vty, " match large-community %s", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name")); + if (yang_dnode_get_bool( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name-exact-match")) + vty_out(vty, " exact-match"); + vty_out(vty, "\n"); } else if (IS_MATCH_EXTCOMMUNITY(condition)) { - acl = NULL; - if ((ln = yang_dnode_get( - dnode, - "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name")) - != NULL) - acl = yang_dnode_get_string(ln, NULL); - - assert(acl); - - vty_out(vty, " match extcommunity %s\n", acl); + vty_out(vty, " match extcommunity %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:comm-list/comm-list-name")); } else if (IS_MATCH_IPV4_NH(condition)) { - vty_out(vty, " match ip next-hop %s\n", + vty_out(vty, " match ip next-hop address %s\n", yang_dnode_get_string( dnode, "./rmap-match-condition/frr-bgp-route-map:ipv4-address")); } else if (IS_MATCH_IPV6_NH(condition)) { - vty_out(vty, " match ipv6 next-hop %s\n", + vty_out(vty, " match ipv6 next-hop address %s\n", yang_dnode_get_string( dnode, "./rmap-match-condition/frr-bgp-route-map:ipv6-address")); @@ -1021,11 +972,11 @@ DEFUN_YANG (no_set_srte_color, } -void route_map_action_show(struct vty *vty, struct lyd_node *dnode, +void route_map_action_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *action = yang_dnode_get_string(dnode, "./action"); - struct lyd_node *ln; + const struct lyd_node *ln; const char *acl; if (IS_SET_IPv4_NH(action)) { @@ -1363,7 +1314,7 @@ ALIAS_YANG( "Continue on a different entry within the route-map\n" "Route-map entry sequence number\n") -void route_map_exit_policy_show(struct vty *vty, struct lyd_node *dnode, +void route_map_exit_policy_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { int exit_policy = yang_dnode_get_enum(dnode, NULL); @@ -1405,7 +1356,7 @@ DEFPY_YANG( return nb_cli_apply_changes(vty, NULL); } -void route_map_call_show(struct vty *vty, struct lyd_node *dnode, +void route_map_call_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " call %s\n", yang_dnode_get_string(dnode, NULL)); @@ -1439,7 +1390,7 @@ DEFUN_YANG (no_rmap_description, return nb_cli_apply_changes(vty, NULL); } -void route_map_description_show(struct vty *vty, struct lyd_node *dnode, +void route_map_description_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " description %s\n", yang_dnode_get_string(dnode, NULL)); @@ -1447,7 +1398,7 @@ void route_map_description_show(struct vty *vty, struct lyd_node *dnode, DEFPY_YANG( route_map_optimization, route_map_optimization_cmd, - "[no] route-map WORD$name optimization", + "[no] route-map RMAP_NAME$name optimization", NO_STR ROUTE_MAP_CMD_STR "Configure route-map optimization\n") @@ -1468,7 +1419,7 @@ DEFPY_YANG( } void route_map_optimization_disabled_show(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { const char *name = yang_dnode_get_string(dnode, "../name"); @@ -1515,7 +1466,7 @@ DEFPY_HIDDEN( static int route_map_config_write(struct vty *vty) { - struct lyd_node *dnode; + const struct lyd_node *dnode; int written = 0; dnode = yang_dnode_get(running_config->dnode, diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 3473ca2aea..51b879959f 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -601,6 +601,16 @@ static int lib_route_map_entry_match_condition_list_name_modify( rhc->rhc_rmi, "ip next-hop", acl, RMAP_EVENT_FILTER_ADDED, args->errmsg, args->errmsg_len); + } else if (IS_MATCH_IPv6_NEXTHOP_LIST(condition)) { + if (rmap_match_set_hook.match_ipv6_next_hop == NULL) + return NB_OK; + rhc->rhc_mhook = rmap_match_set_hook.no_match_ipv6_next_hop; + rhc->rhc_rule = "ipv6 next-hop"; + rhc->rhc_event = RMAP_EVENT_FILTER_DELETED; + rv = rmap_match_set_hook.match_ipv6_next_hop( + rhc->rhc_rmi, "ipv6 next-hop", acl, + RMAP_EVENT_FILTER_ADDED, args->errmsg, + args->errmsg_len); } else if (IS_MATCH_IPv4_NEXTHOP_PREFIX_LIST(condition)) { if (rmap_match_set_hook.match_ip_next_hop_prefix_list == NULL) return NB_OK; @@ -612,6 +622,16 @@ static int lib_route_map_entry_match_condition_list_name_modify( rhc->rhc_rmi, "ip next-hop prefix-list", acl, RMAP_EVENT_PLIST_ADDED, args->errmsg, args->errmsg_len); + } else if (IS_MATCH_IPv6_NEXTHOP_PREFIX_LIST(condition)) { + if (rmap_match_set_hook.match_ipv6_next_hop_prefix_list == NULL) + return NB_OK; + rhc->rhc_mhook = + rmap_match_set_hook.no_match_ipv6_next_hop_prefix_list; + rhc->rhc_rule = "ipv6 next-hop prefix-list"; + rhc->rhc_event = RMAP_EVENT_PLIST_DELETED; + rv = rmap_match_set_hook.match_ipv6_next_hop_prefix_list( + rhc->rhc_rmi, "ipv6 next-hop prefix-list", acl, + RMAP_EVENT_PLIST_ADDED, args->errmsg, args->errmsg_len); } else if (IS_MATCH_IPv6_ADDRESS_LIST(condition)) { if (rmap_match_set_hook.match_ipv6_address == NULL) return NB_OK; diff --git a/lib/sbuf.h b/lib/sbuf.h index 9f0311006d..aaa2db0edb 100644 --- a/lib/sbuf.h +++ b/lib/sbuf.h @@ -35,7 +35,7 @@ extern "C" { * without any information about the previous parsing steps, is usually not very * helpful. * Using sbuf, the parser can log the whole parsing process into a buffer using - * a printf like API. When an error ocurrs, all the information about previous + * a printf like API. When an error occurs, all the information about previous * parsing steps is there in the log, without any need for backtracking, and can * be used to give a detailed and useful error description. * When parsing completes successfully without any error, the log can just be diff --git a/lib/sigevent.c b/lib/sigevent.c index be7297f264..00bc31f517 100644 --- a/lib/sigevent.c +++ b/lib/sigevent.c @@ -36,10 +36,10 @@ /* master signals descriptor struct */ -static struct quagga_sigevent_master_t { +static struct frr_sigevent_master_t { struct thread *t; - struct quagga_signal_t *signals; + struct frr_signal_t *signals; int sigc; volatile sig_atomic_t caught; @@ -48,10 +48,10 @@ static struct quagga_sigevent_master_t { /* Generic signal handler * Schedules signal event thread */ -static void quagga_signal_handler(int signo) +static void frr_signal_handler(int signo) { int i; - struct quagga_signal_t *sig; + struct frr_signal_t *sig; for (i = 0; i < sigmaster.sigc; i++) { sig = &(sigmaster.signals[i]); @@ -91,12 +91,12 @@ bool frr_sigevent_check(sigset_t *setp) } /* check if signals have been caught and run appropriate handlers */ -int quagga_sigevent_process(void) +int frr_sigevent_process(void) { - struct quagga_signal_t *sig; + struct frr_signal_t *sig; int i; #ifdef SIGEVENT_BLOCK_SIGNALS - /* shouldnt need to block signals, but potentially may be needed */ + /* shouldn't need to block signals, but potentially may be needed */ sigset_t newmask, oldmask; /* @@ -110,7 +110,7 @@ int quagga_sigevent_process(void) if ((sigprocmask(SIG_BLOCK, &newmask, &oldmask)) < 0) { flog_err_sys(EC_LIB_SYSTEM_CALL, - "quagga_signal_timer: couldnt block signals!"); + "frr_signal_timer: couldnt block signals!"); return -1; } #endif /* SIGEVENT_BLOCK_SIGNALS */ @@ -142,16 +142,16 @@ int quagga_sigevent_process(void) } #ifdef SIGEVENT_SCHEDULE_THREAD -/* timer thread to check signals. Shouldnt be needed */ -int quagga_signal_timer(struct thread *t) +/* timer thread to check signals. shouldn't be needed */ +int frr_signal_timer(struct thread *t) { - struct quagga_sigevent_master_t *sigm; + struct frr_sigevent_master_t *sigm; sigm = THREAD_ARG(t); sigm->t = NULL; - thread_add_timer(sigm->t->master, quagga_signal_timer, &sigmaster, - QUAGGA_SIGNAL_TIMER_INTERVAL, &sigm->t); - return quagga_sigevent_process(); + thread_add_timer(sigm->t->master, frr_signal_timer, &sigmaster, + FRR_SIGNAL_TIMER_INTERVAL, &sigm->t); + return frr_sigevent_process(); } #endif /* SIGEVENT_SCHEDULE_THREAD */ @@ -163,7 +163,7 @@ static int signal_set(int signo) struct sigaction sig; struct sigaction osig; - sig.sa_handler = &quagga_signal_handler; + sig.sa_handler = &frr_signal_handler; sigfillset(&sig.sa_mask); sig.sa_flags = 0; if (signo == SIGALRM) { @@ -348,11 +348,11 @@ static void trap_default_signals(void) } void signal_init(struct thread_master *m, int sigc, - struct quagga_signal_t signals[]) + struct frr_signal_t signals[]) { int i = 0; - struct quagga_signal_t *sig; + struct frr_signal_t *sig; /* First establish some default handlers that can be overridden by the application. */ @@ -370,7 +370,7 @@ void signal_init(struct thread_master *m, int sigc, #ifdef SIGEVENT_SCHEDULE_THREAD sigmaster.t = NULL; - thread_add_timer(m, quagga_signal_timer, &sigmaster, - QUAGGA_SIGNAL_TIMER_INTERVAL, &sigmaster.t); + thread_add_timer(m, frr_signal_timer, &sigmaster, + FRR_SIGNAL_TIMER_INTERVAL, &sigmaster.t); #endif /* SIGEVENT_SCHEDULE_THREAD */ } diff --git a/lib/sigevent.h b/lib/sigevent.h index 4a39b22889..dd1ee99587 100644 --- a/lib/sigevent.h +++ b/lib/sigevent.h @@ -20,8 +20,8 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -#ifndef _QUAGGA_SIGNAL_H -#define _QUAGGA_SIGNAL_H +#ifndef _FRR_SIGNAL_H +#define _FRR_SIGNAL_H #include <thread.h> @@ -29,9 +29,9 @@ extern "C" { #endif -#define QUAGGA_SIGNAL_TIMER_INTERVAL 2L +#define FRR_SIGNAL_TIMER_INTERVAL 2L -struct quagga_signal_t { +struct frr_signal_t { int signal; /* signal number */ void (*handler)(void); /* handler to call */ @@ -42,11 +42,11 @@ struct quagga_signal_t { * takes: * - pointer to valid struct thread_master * - number of elements in passed in signals array - * - array of quagga_signal_t's describing signals to handle + * - array of frr_signal_t's describing signals to handle * and handlers to use for each signal */ extern void signal_init(struct thread_master *m, int sigc, - struct quagga_signal_t *signals); + struct frr_signal_t *signals); /* @@ -58,10 +58,10 @@ extern void signal_init(struct thread_master *m, int sigc, bool frr_sigevent_check(sigset_t *setp); /* check whether there are signals to handle, process any found */ -extern int quagga_sigevent_process(void); +extern int frr_sigevent_process(void); #ifdef __cplusplus } #endif -#endif /* _QUAGGA_SIGNAL_H */ +#endif /* _FRR_SIGNAL_H */ diff --git a/lib/skiplist.c b/lib/skiplist.c index c5219f7381..81407826f2 100644 --- a/lib/skiplist.c +++ b/lib/skiplist.c @@ -21,7 +21,7 @@ */ /* - * Skip List impementation based on code from William Pugh. + * Skip List implementation based on code from William Pugh. * ftp://ftp.cs.umd.edu/pub/skipLists/ * * Skip Lists are a probabilistic alternative to balanced trees, as diff --git a/lib/skiplist.h b/lib/skiplist.h index 00950e13bb..165607820a 100644 --- a/lib/skiplist.h +++ b/lib/skiplist.h @@ -21,7 +21,7 @@ */ /* - * Skip List impementation based on code from William Pugh. + * Skip List implementation based on code from William Pugh. * ftp://ftp.cs.umd.edu/pub/skipLists/ */ diff --git a/lib/snmp.c b/lib/snmp.c index 23d3f38b31..8d8b3c950c 100644 --- a/lib/snmp.c +++ b/lib/snmp.c @@ -25,13 +25,11 @@ #include "smux.h" -#define min(A,B) ((A) < (B) ? (A) : (B)) - int oid_compare(const oid *o1, int o1_len, const oid *o2, int o2_len) { int i; - for (i = 0; i < min(o1_len, o2_len); i++) { + for (i = 0; i < MIN(o1_len, o2_len); i++) { if (o1[i] < o2[i]) return -1; else if (o1[i] > o2[i]) diff --git a/lib/sockopt.c b/lib/sockopt.c index 150736e00c..45f3c23330 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -122,7 +122,7 @@ int setsockopt_ipv6_pktinfo(int sock, int val) if (ret < 0) flog_err(EC_LIB_SOCKET, "can't setsockopt IPV6_PKTINFO : %s", safe_strerror(errno)); -#endif /* INIA_IPV6 */ +#endif /* IANA_IPV6 */ return ret; } @@ -595,7 +595,7 @@ int sockopt_tcp_signature_ext(int sock, union sockunion *su, uint16_t prefixlen, /* If this does not work, then all users of this sockopt will * need to - * differentiate between IPv4 and IPv6, and keep seperate + * differentiate between IPv4 and IPv6, and keep separate * sockets for * each. * diff --git a/lib/srv6.c b/lib/srv6.c index ccb94b2f76..6a658444c6 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -161,21 +161,59 @@ void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk) json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) { - char str[256]; json_object *jo_root = NULL; jo_root = json_object_new_object(); - prefix2str(&chunk->prefix, str, sizeof(str)); - json_object_string_add(jo_root, "prefix", str); + json_object_string_addf(jo_root, "prefix", "%pFX", &chunk->prefix); json_object_string_add(jo_root, "proto", zebra_route_string(chunk->proto)); return jo_root; } +json_object * +srv6_locator_chunk_detailed_json(const struct srv6_locator_chunk *chunk) +{ + json_object *jo_root = NULL; + + jo_root = json_object_new_object(); + + /* set prefix */ + json_object_string_addf(jo_root, "prefix", "%pFX", &chunk->prefix); + + /* set block_bits_length */ + json_object_int_add(jo_root, "blockBitsLength", + chunk->block_bits_length); + + /* set node_bits_length */ + json_object_int_add(jo_root, "nodeBitsLength", chunk->node_bits_length); + + /* set function_bits_length */ + json_object_int_add(jo_root, "functionBitsLength", + chunk->function_bits_length); + + /* set argument_bits_length */ + json_object_int_add(jo_root, "argumentBitsLength", + chunk->argument_bits_length); + + /* set keep */ + json_object_int_add(jo_root, "keep", chunk->keep); + + /* set proto */ + json_object_string_add(jo_root, "proto", + zebra_route_string(chunk->proto)); + + /* set instance */ + json_object_int_add(jo_root, "instance", chunk->instance); + + /* set session_id */ + json_object_int_add(jo_root, "sessionId", chunk->session_id); + + return jo_root; +} + json_object *srv6_locator_json(const struct srv6_locator *loc) { - char str[256]; struct listnode *node; struct srv6_locator_chunk *chunk; json_object *jo_root = NULL; @@ -188,8 +226,7 @@ json_object *srv6_locator_json(const struct srv6_locator *loc) json_object_string_add(jo_root, "name", loc->name); /* set prefix */ - prefix2str(&loc->prefix, str, sizeof(str)); - json_object_string_add(jo_root, "prefix", str); + json_object_string_addf(jo_root, "prefix", "%pFX", &loc->prefix); /* set function_bits_length */ json_object_int_add(jo_root, "functionBitsLength", @@ -209,3 +246,50 @@ json_object *srv6_locator_json(const struct srv6_locator *loc) return jo_root; } + +json_object *srv6_locator_detailed_json(const struct srv6_locator *loc) +{ + struct listnode *node; + struct srv6_locator_chunk *chunk; + json_object *jo_root = NULL; + json_object *jo_chunk = NULL; + json_object *jo_chunks = NULL; + + jo_root = json_object_new_object(); + + /* set name */ + json_object_string_add(jo_root, "name", loc->name); + + /* 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 algonum */ + json_object_int_add(jo_root, "algoNum", loc->algonum); + + /* set status_up */ + json_object_boolean_add(jo_root, "statusUp", loc->status_up); + + /* set chunks */ + jo_chunks = json_object_new_array(); + json_object_object_add(jo_root, "chunks", jo_chunks); + for (ALL_LIST_ELEMENTS_RO((struct list *)loc->chunks, node, chunk)) { + jo_chunk = srv6_locator_chunk_detailed_json(chunk); + json_object_array_add(jo_chunks, jo_chunk); + } + + return jo_root; +} diff --git a/lib/srv6.h b/lib/srv6.h index 715fc3723b..e0db30cd13 100644 --- a/lib/srv6.h +++ b/lib/srv6.h @@ -189,6 +189,9 @@ extern void srv6_locator_free(struct srv6_locator *locator); extern void srv6_locator_chunk_free(struct srv6_locator_chunk *chunk); 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); #ifdef __cplusplus } diff --git a/lib/subdir.am b/lib/subdir.am index dab5fb9e83..bb10d71ed1 100644 --- a/lib/subdir.am +++ b/lib/subdir.am @@ -3,7 +3,7 @@ # lib_LTLIBRARIES += lib/libfrr.la lib_libfrr_la_LDFLAGS = $(LIB_LDFLAGS) -version-info 0:0:0 -Xlinker -e_libfrr_version -lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST_LIBS) $(LIBM) +lib_libfrr_la_LIBADD = $(LIBCAP) $(UNWIND_LIBS) $(LIBYANG_LIBS) $(LUA_LIB) $(UST_LIBS) $(LIBCRYPT) $(LIBDL) $(LIBM) lib_libfrr_la_SOURCES = \ lib/agg_table.c \ @@ -130,7 +130,6 @@ nodist_lib_libfrr_la_SOURCES = \ yang/ietf/ietf-interfaces.yang.c \ yang/ietf/ietf-bgp-types.yang.c \ yang/frr-module-translator.yang.c \ - yang/frr-nexthop.yang.c \ # end vtysh_scan += \ diff --git a/lib/table.c b/lib/table.c index e6030ca4ca..523183bef2 100644 --- a/lib/table.c +++ b/lib/table.c @@ -393,7 +393,7 @@ void route_node_delete(struct route_node *node) route_node_delete(parent); } -/* Get fist node and lock it. This function is useful when one want +/* Get first node and lock it. This function is useful when one wants to lookup all the node exist in the routing table. */ struct route_node *route_top(struct route_table *table) { diff --git a/lib/thread.c b/lib/thread.c index 835aa38115..7b223ed6de 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -922,10 +922,10 @@ done: } /* Add new read thread. */ -struct thread *_thread_add_read_write(const struct xref_threadsched *xref, - struct thread_master *m, - int (*func)(struct thread *), - void *arg, int fd, struct thread **t_ptr) +void _thread_add_read_write(const struct xref_threadsched *xref, + struct thread_master *m, + int (*func)(struct thread *), void *arg, int fd, + struct thread **t_ptr) { int dir = xref->thread_type; struct thread *thread = NULL; @@ -1000,15 +1000,13 @@ struct thread *_thread_add_read_write(const struct xref_threadsched *xref, AWAKEN(m); } - - return thread; } -static struct thread * -_thread_add_timer_timeval(const struct xref_threadsched *xref, - struct thread_master *m, int (*func)(struct thread *), - void *arg, struct timeval *time_relative, - struct thread **t_ptr) +static void _thread_add_timer_timeval(const struct xref_threadsched *xref, + struct thread_master *m, + int (*func)(struct thread *), void *arg, + struct timeval *time_relative, + struct thread **t_ptr) { struct thread *thread; struct timeval t; @@ -1028,7 +1026,7 @@ _thread_add_timer_timeval(const struct xref_threadsched *xref, frr_with_mutex(&m->mtx) { if (t_ptr && *t_ptr) /* thread is already scheduled; don't reschedule */ - return NULL; + return; thread = thread_get(m, THREAD_TIMER, func, arg, xref); @@ -1048,16 +1046,13 @@ _thread_add_timer_timeval(const struct xref_threadsched *xref, if (thread_timer_list_first(&m->timer) == thread) AWAKEN(m); } - - return thread; } /* Add timer event thread. */ -struct thread *_thread_add_timer(const struct xref_threadsched *xref, - struct thread_master *m, - int (*func)(struct thread *), - void *arg, long timer, struct thread **t_ptr) +void _thread_add_timer(const struct xref_threadsched *xref, + struct thread_master *m, int (*func)(struct thread *), + void *arg, long timer, struct thread **t_ptr) { struct timeval trel; @@ -1066,15 +1061,14 @@ struct thread *_thread_add_timer(const struct xref_threadsched *xref, trel.tv_sec = timer; trel.tv_usec = 0; - return _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr); + _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr); } /* Add timer event thread with "millisecond" resolution */ -struct thread *_thread_add_timer_msec(const struct xref_threadsched *xref, - struct thread_master *m, - int (*func)(struct thread *), - void *arg, long timer, - struct thread **t_ptr) +void _thread_add_timer_msec(const struct xref_threadsched *xref, + struct thread_master *m, + int (*func)(struct thread *), void *arg, long timer, + struct thread **t_ptr) { struct timeval trel; @@ -1083,24 +1077,21 @@ struct thread *_thread_add_timer_msec(const struct xref_threadsched *xref, trel.tv_sec = timer / 1000; trel.tv_usec = 1000 * (timer % 1000); - return _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr); + _thread_add_timer_timeval(xref, m, func, arg, &trel, t_ptr); } /* Add timer event thread with "timeval" resolution */ -struct thread *_thread_add_timer_tv(const struct xref_threadsched *xref, - struct thread_master *m, - int (*func)(struct thread *), - void *arg, struct timeval *tv, - struct thread **t_ptr) +void _thread_add_timer_tv(const struct xref_threadsched *xref, + struct thread_master *m, int (*func)(struct thread *), + void *arg, struct timeval *tv, struct thread **t_ptr) { - return _thread_add_timer_timeval(xref, m, func, arg, tv, t_ptr); + _thread_add_timer_timeval(xref, m, func, arg, tv, t_ptr); } /* Add simple event thread. */ -struct thread *_thread_add_event(const struct xref_threadsched *xref, - struct thread_master *m, - int (*func)(struct thread *), - void *arg, int val, struct thread **t_ptr) +void _thread_add_event(const struct xref_threadsched *xref, + struct thread_master *m, int (*func)(struct thread *), + void *arg, int val, struct thread **t_ptr) { struct thread *thread = NULL; @@ -1128,8 +1119,6 @@ struct thread *_thread_add_event(const struct xref_threadsched *xref, AWAKEN(m); } - - return thread; } /* Thread cancellation ------------------------------------------------------ */ @@ -1706,7 +1695,7 @@ struct thread *thread_fetch(struct thread_master *m, struct thread *fetch) do { /* Handle signals if any */ if (m->handle_signals) - quagga_sigevent_process(); + frr_sigevent_process(); pthread_mutex_lock(&m->mtx); @@ -2059,3 +2048,11 @@ void debug_signals(const sigset_t *sigs) zlog_debug("%s: %s", __func__, buf); } + +bool thread_is_scheduled(struct thread *thread) +{ + if (thread == NULL) + return false; + + return true; +} diff --git a/lib/thread.h b/lib/thread.h index abd94ff4f0..39f21da11d 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -219,26 +219,30 @@ void thread_master_set_name(struct thread_master *master, const char *name); extern void thread_master_free(struct thread_master *); extern void thread_master_free_unused(struct thread_master *); -extern struct thread *_thread_add_read_write( - const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, int fd, struct thread **tref); - -extern struct thread *_thread_add_timer( - const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, long t, struct thread **tref); - -extern struct thread *_thread_add_timer_msec( - const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, long t, struct thread **tref); - -extern struct thread *_thread_add_timer_tv( - const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, struct timeval *tv, - struct thread **tref); - -extern struct thread *_thread_add_event( - const struct xref_threadsched *xref, struct thread_master *master, - int (*fn)(struct thread *), void *arg, int val, struct thread **tref); +extern void _thread_add_read_write(const struct xref_threadsched *xref, + struct thread_master *master, + int (*fn)(struct thread *), void *arg, + int fd, struct thread **tref); + +extern void _thread_add_timer(const struct xref_threadsched *xref, + struct thread_master *master, + int (*fn)(struct thread *), void *arg, long t, + struct thread **tref); + +extern void _thread_add_timer_msec(const struct xref_threadsched *xref, + struct thread_master *master, + int (*fn)(struct thread *), void *arg, + long t, struct thread **tref); + +extern void _thread_add_timer_tv(const struct xref_threadsched *xref, + struct thread_master *master, + int (*fn)(struct thread *), void *arg, + struct timeval *tv, struct thread **tref); + +extern void _thread_add_event(const struct xref_threadsched *xref, + struct thread_master *master, + int (*fn)(struct thread *), void *arg, int val, + struct thread **tref); extern void _thread_execute(const struct xref_threadsched *xref, struct thread_master *master, @@ -273,6 +277,7 @@ extern pthread_key_t thread_current; extern char *thread_timer_to_hhmmss(char *buf, int buf_size, struct thread *t_timer); +extern bool thread_is_scheduled(struct thread *thread); /* Debug signal mask */ void debug_signals(const sigset_t *sigs); diff --git a/lib/typerb.c b/lib/typerb.c index 092faa4cc9..e1346df191 100644 --- a/lib/typerb.c +++ b/lib/typerb.c @@ -45,6 +45,7 @@ #include "config.h" #endif +#include <string.h> #include "typerb.h" #define RB_BLACK 0 @@ -330,6 +331,7 @@ color: rbe_remove_color(rbt, parent, child); rbt->count--; + memset(old, 0, sizeof(*old)); return (old); } @@ -478,3 +480,11 @@ struct rb_entry *typed_rb_min(const struct rbt_tree *rbt) return parent; } + +bool typed_rb_member(const struct typed_rb_root *rbt, + const struct typed_rb_entry *rbe) +{ + while (rbe->rbt_parent) + rbe = rbe->rbt_parent; + return rbe == rbt->rbt_root; +} diff --git a/lib/typerb.h b/lib/typerb.h index cbed8d4893..75a1de77b3 100644 --- a/lib/typerb.h +++ b/lib/typerb.h @@ -20,6 +20,7 @@ #ifndef _FRR_TYPERB_H #define _FRR_TYPERB_H +#include <string.h> #include "typesafe.h" #ifdef __cplusplus @@ -62,6 +63,8 @@ const struct typed_rb_entry *typed_rb_find_lt(const struct typed_rb_root *rbt, const struct typed_rb_entry *b)); struct typed_rb_entry *typed_rb_min(const struct typed_rb_root *rbt); struct typed_rb_entry *typed_rb_next(const struct typed_rb_entry *rbe); +bool typed_rb_member(const struct typed_rb_root *rbt, + const struct typed_rb_entry *rbe); #define _PREDECL_RBTREE(prefix) \ struct prefix ## _head { struct typed_rb_root rr; }; \ @@ -142,6 +145,11 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->rr.count; \ } \ +macro_pure bool prefix ## _member(const struct prefix##_head *h, \ + const type *item) \ +{ \ + return typed_rb_member(&h->rr, &item->field.re); \ +} \ MACRO_REQUIRE_SEMICOLON() /* end */ #define PREDECL_RBTREE_UNIQ(prefix) \ diff --git a/lib/typesafe.c b/lib/typesafe.c index 76705fad0d..3b65a2d02a 100644 --- a/lib/typesafe.c +++ b/lib/typesafe.c @@ -20,6 +20,7 @@ #include <stdlib.h> #include <string.h> +#include <assert.h> #include "typesafe.h" #include "memory.h" @@ -29,6 +30,46 @@ DEFINE_MTYPE_STATIC(LIB, TYPEDHASH_BUCKET, "Typed-hash bucket"); DEFINE_MTYPE_STATIC(LIB, SKIPLIST_OFLOW, "Skiplist overflow"); DEFINE_MTYPE_STATIC(LIB, HEAP_ARRAY, "Typed-heap array"); +struct slist_item typesafe_slist_sentinel = { NULL }; + +bool typesafe_list_member(const struct slist_head *head, + const struct slist_item *item) +{ + struct slist_item *fromhead = head->first; + struct slist_item **fromnext = (struct slist_item **)&item->next; + + while (fromhead != _SLIST_LAST) { + if (fromhead == item || fromnext == head->last_next) + return true; + + fromhead = fromhead->next; + if (!*fromnext || *fromnext == _SLIST_LAST) + break; + fromnext = &(*fromnext)->next; + } + + return false; +} + +bool typesafe_dlist_member(const struct dlist_head *head, + const struct dlist_item *item) +{ + const struct dlist_item *fromhead = head->hitem.next; + const struct dlist_item *fromitem = item->next; + + if (!item->prev || !item->next) + return false; + + while (fromhead != &head->hitem && fromitem != item) { + if (fromitem == &head->hitem || fromhead == item) + return true; + fromhead = fromhead->next; + fromitem = fromitem->next; + } + + return false; +} + #if 0 static void hash_consistency_check(struct thash_head *head) { diff --git a/lib/typesafe.h b/lib/typesafe.h index ecac1a4381..b284397d98 100644 --- a/lib/typesafe.h +++ b/lib/typesafe.h @@ -20,7 +20,6 @@ #include <stddef.h> #include <stdint.h> #include <stdbool.h> -#include <assert.h> #include "compiler.h" #ifdef __cplusplus @@ -78,8 +77,34 @@ macro_inline type *prefix ## _find_gteq(struct prefix##_head *h, \ } \ /* ... */ +/* *_member via find - when there is no better membership check than find() */ +#define TYPESAFE_MEMBER_VIA_FIND(prefix, type) \ +macro_inline bool prefix ## _member(struct prefix##_head *h, \ + const type *item) \ +{ \ + return item == prefix ## _const_find(h, item); \ +} \ +/* ... */ + +/* *_member via find_gteq - same for non-unique containers */ +#define TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \ +macro_inline bool prefix ## _member(struct prefix##_head *h, \ + const type *item) \ +{ \ + const type *iter; \ + for (iter = prefix ## _const_find_gteq(h, item); iter; \ + iter = prefix ## _const_next(h, iter)) { \ + if (iter == item) \ + return true; \ + if (cmpfn(iter, item) > 0) \ + break; \ + } \ + return false; \ +} \ +/* ... */ + /* SWAP_ALL_SIMPLE = for containers where the items don't point back to the - * head *AND* the head doesn'T points to itself (= everything except LIST, + * head *AND* the head doesn't point to itself (= everything except LIST, * DLIST and SKIPLIST), just switch out the entire head */ #define TYPESAFE_SWAP_ALL_SIMPLE(prefix) \ @@ -106,6 +131,10 @@ struct slist_head { size_t count; }; +/* this replaces NULL as the value for ->next on the last item. */ +extern struct slist_item typesafe_slist_sentinel; +#define _SLIST_LAST &typesafe_slist_sentinel + static inline void typesafe_list_add(struct slist_head *head, struct slist_item **pos, struct slist_item *item) { @@ -116,6 +145,9 @@ static inline void typesafe_list_add(struct slist_head *head, head->count++; } +extern bool typesafe_list_member(const struct slist_head *head, + const struct slist_item *item); + /* use as: * * PREDECL_LIST(namelist); @@ -136,6 +168,7 @@ MACRO_REQUIRE_SEMICOLON() /* end */ macro_inline void prefix ## _init(struct prefix##_head *h) \ { \ memset(h, 0, sizeof(*h)); \ + h->sh.first = _SLIST_LAST; \ h->sh.last_next = &h->sh.first; \ } \ macro_inline void prefix ## _fini(struct prefix##_head *h) \ @@ -161,25 +194,27 @@ macro_inline void prefix ## _add_after(struct prefix##_head *h, \ macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ { \ struct slist_item **iter = &h->sh.first; \ - while (*iter && *iter != &item->field.si) \ + while (*iter != _SLIST_LAST && *iter != &item->field.si) \ iter = &(*iter)->next; \ - if (!*iter) \ + if (*iter == _SLIST_LAST) \ return NULL; \ h->sh.count--; \ *iter = item->field.si.next; \ - if (!item->field.si.next) \ + if (item->field.si.next == _SLIST_LAST) \ h->sh.last_next = iter; \ + item->field.si.next = NULL; \ return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ { \ struct slist_item *sitem = h->sh.first; \ - if (!sitem) \ + if (sitem == _SLIST_LAST) \ return NULL; \ h->sh.count--; \ h->sh.first = sitem->next; \ - if (h->sh.first == NULL) \ + if (h->sh.first == _SLIST_LAST) \ h->sh.last_next = &h->sh.first; \ + sitem->next = NULL; \ return container_of(sitem, type, field.si); \ } \ macro_inline void prefix ## _swap_all(struct prefix##_head *a, \ @@ -195,13 +230,17 @@ macro_inline void prefix ## _swap_all(struct prefix##_head *a, \ } \ macro_pure const type *prefix ## _const_first(const struct prefix##_head *h) \ { \ - return container_of_null(h->sh.first, type, field.si); \ + if (h->sh.first != _SLIST_LAST) \ + return container_of(h->sh.first, type, field.si); \ + return NULL; \ } \ macro_pure const type *prefix ## _const_next(const struct prefix##_head *h, \ const type *item) \ { \ const struct slist_item *sitem = &item->field.si; \ - return container_of_null(sitem->next, type, field.si); \ + if (sitem->next != _SLIST_LAST) \ + return container_of(sitem->next, type, field.si); \ + return NULL; \ } \ TYPESAFE_FIRST_NEXT(prefix, type) \ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ @@ -210,12 +249,23 @@ macro_pure type *prefix ## _next_safe(struct prefix##_head *h, type *item) \ if (!item) \ return NULL; \ sitem = &item->field.si; \ - return container_of_null(sitem->next, type, field.si); \ + if (sitem->next != _SLIST_LAST) \ + return container_of(sitem->next, type, field.si); \ + return NULL; \ } \ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->sh.count; \ } \ +macro_pure bool prefix ## _anywhere(const type *item) \ +{ \ + return item->field.si.next != NULL; \ +} \ +macro_pure bool prefix ## _member(const struct prefix##_head *h, \ + const type *item) \ +{ \ + return typesafe_list_member(&h->sh, &item->field.si); \ +} \ MACRO_REQUIRE_SEMICOLON() /* end */ /* don't use these structs directly */ @@ -267,6 +317,9 @@ static inline void typesafe_dlist_swap_all(struct dlist_head *a, } } +extern bool typesafe_dlist_member(const struct dlist_head *head, + const struct dlist_item *item); + /* double-linked list, for fast item deletion */ #define PREDECL_DLIST(prefix) \ @@ -321,6 +374,7 @@ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ ditem->prev->next = ditem->next; \ ditem->next->prev = ditem->prev; \ h->dh.count--; \ + ditem->prev = ditem->next = NULL; \ return container_of(ditem, type, field.di); \ } \ macro_inline void prefix ## _swap_all(struct prefix##_head *a, \ @@ -354,6 +408,16 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->dh.count; \ } \ +macro_pure bool prefix ## _anywhere(const type *item) \ +{ \ + const struct dlist_item *ditem = &item->field.di; \ + return ditem->next && ditem->prev; \ +} \ +macro_pure bool prefix ## _member(const struct prefix##_head *h, \ + const type *item) \ +{ \ + return typesafe_dlist_member(&h->dh, &item->field.di); \ +} \ MACRO_REQUIRE_SEMICOLON() /* end */ /* note: heap currently caps out at 4G items */ @@ -463,6 +527,14 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ +macro_pure bool prefix ## _member(const struct prefix##_head *h, \ + const type *item) \ +{ \ + uint32_t idx = item->field.hi.index; \ + if (idx >= h->hh.count) \ + return false; \ + return h->hh.array[idx] == &item->field.hi; \ +} \ MACRO_REQUIRE_SEMICOLON() /* end */ extern void typesafe_heap_resize(struct heap_head *head, bool grow); @@ -565,6 +637,7 @@ macro_inline type *prefix ## _del(struct prefix##_head *h, type *item) \ return NULL; \ h->sh.count--; \ *iter = item->field.si.next; \ + item->field.si.next = NULL; \ return item; \ } \ macro_inline type *prefix ## _pop(struct prefix##_head *h) \ @@ -618,6 +691,7 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \ return container_of(sitem, type, field.si); \ } \ TYPESAFE_FIND(prefix, type) \ +TYPESAFE_MEMBER_VIA_FIND(prefix, type) \ MACRO_REQUIRE_SEMICOLON() /* end */ #define DECLARE_SORTLIST_NONUNIQ(prefix, type, field, cmpfn) \ @@ -633,6 +707,7 @@ macro_inline int _ ## prefix ## _cmp(const type *a, const type *b) \ return 0; \ } \ _DECLARE_SORTLIST(prefix, type, field, cmpfn, _ ## prefix ## _cmp); \ +TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \ MACRO_REQUIRE_SEMICOLON() /* end */ @@ -799,6 +874,19 @@ macro_pure size_t prefix ## _count(const struct prefix##_head *h) \ { \ return h->hh.count; \ } \ +macro_pure bool prefix ## _member(const struct prefix##_head *h, \ + const type *item) \ +{ \ + uint32_t hval = item->field.hi.hashval, hbits = HASH_KEY(h->hh, hval); \ + const struct thash_item *hitem = h->hh.entries[hbits]; \ + while (hitem && hitem->hashval < hval) \ + hitem = hitem->next; \ + for (hitem = h->hh.entries[hbits]; hitem && hitem->hashval <= hval; \ + hitem = hitem->next) \ + if (hitem == &item->field.hi) \ + return true; \ + return false; \ +} \ MACRO_REQUIRE_SEMICOLON() /* end */ /* skiplist, sorted. @@ -937,6 +1025,7 @@ macro_inline const type *prefix ## _const_find(const struct prefix##_head *h, \ return container_of_null(sitem, type, field.si); \ } \ TYPESAFE_FIND(prefix, type) \ +TYPESAFE_MEMBER_VIA_FIND(prefix, type) \ \ _DECLARE_SKIPLIST(prefix, type, field, \ prefix ## __cmp, prefix ## __cmp); \ @@ -968,6 +1057,7 @@ macro_inline int prefix ## __cmp_uq(const struct sskip_item *a, \ \ _DECLARE_SKIPLIST(prefix, type, field, \ prefix ## __cmp, prefix ## __cmp_uq); \ +TYPESAFE_MEMBER_VIA_FIND_GTEQ(prefix, type, cmpfn) \ MACRO_REQUIRE_SEMICOLON() /* end */ diff --git a/lib/vector.c b/lib/vector.c index 4af564a82f..5497c24280 100644 --- a/lib/vector.c +++ b/lib/vector.c @@ -37,6 +37,7 @@ vector vector_init(unsigned int size) v->alloced = size; v->active = 0; + v->count = 0; v->index = XCALLOC(MTYPE_VECTOR_INDEX, sizeof(void *) * size); return v; } @@ -54,6 +55,7 @@ vector vector_copy(vector v) new->active = v->active; new->alloced = v->alloced; + new->count = v->count; size = sizeof(void *) * (v->alloced); new->index = XCALLOC(MTYPE_VECTOR_INDEX, size); @@ -84,6 +86,9 @@ int vector_empty_slot(vector v) { unsigned int i; + if (v->active == v->count) + return v->active; + if (v->active == 0) return 0; @@ -102,6 +107,10 @@ int vector_set(vector v, void *val) i = vector_empty_slot(v); vector_ensure(v, i); + if (v->index[i]) + v->count--; + if (val) + v->count++; v->index[i] = val; if (v->active <= i) @@ -115,6 +124,10 @@ int vector_set_index(vector v, unsigned int i, void *val) { vector_ensure(v, i); + if (v->index[i]) + v->count--; + if (val) + v->count++; v->index[i] = val; if (v->active <= i) @@ -123,17 +136,6 @@ int vector_set_index(vector v, unsigned int i, void *val) return i; } -/* Make a specified index slot active and return its address. */ -void **vector_get_index(vector v, unsigned int i) -{ - vector_ensure(v, i); - - if (v->active <= i) - v->active = i + 1; - - return &v->index[i]; -} - /* Look up vector. */ void *vector_lookup(vector v, unsigned int i) { @@ -155,6 +157,9 @@ void vector_unset(vector v, unsigned int i) if (i >= v->alloced) return; + if (v->index[i]) + v->count--; + v->index[i] = NULL; if (i + 1 == v->active) { @@ -169,6 +174,9 @@ void vector_remove(vector v, unsigned int ix) if (ix >= v->active) return; + if (v->index[ix]) + v->count--; + int n = (--v->active) - ix; memmove(&v->index[ix], &v->index[ix + 1], n * sizeof(void *)); @@ -192,6 +200,7 @@ void vector_unset_value(vector v, void *val) for (i = 0; i < v->active; i++) if (v->index[i] == val) { v->index[i] = NULL; + v->count--; break; } @@ -201,19 +210,6 @@ void vector_unset_value(vector v, void *val) while (i && v->index[--i] == NULL); } -/* Count the number of not emplty slot. */ -unsigned int vector_count(vector v) -{ - unsigned int i; - unsigned count = 0; - - for (i = 0; i < v->active; i++) - if (v->index[i] != NULL) - count++; - - return count; -} - void vector_to_array(vector v, void ***dest, int *argc) { *dest = XCALLOC(MTYPE_TMP, sizeof(void *) * v->active); diff --git a/lib/vector.h b/lib/vector.h index 845c8d8b04..71c497a1b7 100644 --- a/lib/vector.h +++ b/lib/vector.h @@ -32,6 +32,7 @@ extern "C" { struct _vector { unsigned int active; /* number of active slots */ unsigned int alloced; /* number of allocated slot */ + unsigned int count; void **index; /* index to data */ }; typedef struct _vector *vector; @@ -54,13 +55,16 @@ extern void vector_ensure(vector v, unsigned int num); extern int vector_empty_slot(vector v); extern int vector_set(vector v, void *val); extern int vector_set_index(vector v, unsigned int i, void *val); -extern void **vector_get_index(vector v, unsigned int i); extern void vector_unset(vector v, unsigned int i); extern void vector_unset_value(vector v, void *val); extern void vector_remove(vector v, unsigned int ix); extern void vector_compact(vector v); -extern unsigned int vector_count(vector v); +static inline unsigned int vector_count(vector v) +{ + return v->count; +} + extern void vector_free(vector v); extern vector vector_copy(vector v); @@ -21,9 +21,6 @@ #include <zebra.h> -/* for basename */ -#include <libgen.h> - #include "if.h" #include "vrf.h" #include "vrf_int.h" @@ -97,28 +94,6 @@ static int vrf_name_compare(const struct vrf *a, const struct vrf *b) return strcmp(a->name, b->name); } -/* if ns_id is different and not VRF_UNKNOWN, - * then update vrf identifier, and enable VRF - */ -static void vrf_update_vrf_id(ns_id_t ns_id, void *opaqueptr) -{ - ns_id_t vrf_id = (vrf_id_t)ns_id; - vrf_id_t old_vrf_id; - struct vrf *vrf = (struct vrf *)opaqueptr; - - if (!vrf) - return; - old_vrf_id = vrf->vrf_id; - if (vrf_id == vrf->vrf_id) - return; - if (vrf->vrf_id != VRF_UNKNOWN) - RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); - vrf->vrf_id = vrf_id; - RB_INSERT(vrf_id_head, &vrfs_by_id, vrf); - if (old_vrf_id == VRF_UNKNOWN) - vrf_enable(vrf); -} - int vrf_switch_to_netns(vrf_id_t vrf_id) { char *name; @@ -272,32 +247,27 @@ void vrf_delete(struct vrf *vrf) if (vrf_is_enabled(vrf)) vrf_disable(vrf); + if (vrf->vrf_id != VRF_UNKNOWN) { + RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); + vrf->vrf_id = VRF_UNKNOWN; + } + /* If the VRF is user configured, it'll stick around, just remove * the ID mapping. Interfaces assigned to this VRF should've been * removed already as part of the VRF going down. */ - if (vrf_is_user_cfged(vrf)) { - if (vrf->vrf_id != VRF_UNKNOWN) { - /* Delete any VRF interfaces - should be only - * the VRF itself, other interfaces should've - * been moved out of the VRF. - */ - if_terminate(vrf); - RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); - vrf->vrf_id = VRF_UNKNOWN; - } - vrf->ns_ctxt = NULL; + if (vrf_is_user_cfged(vrf)) + return; + + /* Do not delete the VRF if it has interfaces configured in it. */ + if (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) return; - } if (vrf_master.vrf_delete_hook) (*vrf_master.vrf_delete_hook)(vrf); QOBJ_UNREG(vrf); - if_terminate(vrf); - if (vrf->vrf_id != VRF_UNKNOWN) - RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); if (vrf->name[0] != '\0') RB_REMOVE(vrf_name_head, &vrfs_by_name, vrf); @@ -384,13 +354,6 @@ const char *vrf_id_to_name(vrf_id_t vrf_id) return VRF_LOGNAME(vrf); } -/* Get the data pointer of the specified VRF. If not found, create one. */ -void *vrf_info_get(vrf_id_t vrf_id) -{ - struct vrf *vrf = vrf_get(vrf_id, NULL); - return vrf->info; -} - /* Look up the data pointer of the specified VRF. */ void *vrf_info_lookup(vrf_id_t vrf_id) { @@ -571,6 +534,7 @@ static void vrf_terminate_single(struct vrf *vrf) { /* Clear configured flag and invoke delete. */ UNSET_FLAG(vrf->status, VRF_CONFIGURED); + if_terminate(vrf); vrf_delete(vrf); } @@ -598,7 +562,8 @@ void vrf_terminate(void) /* Finally terminate default VRF */ vrf = vrf_lookup_by_id(VRF_DEFAULT); - vrf_terminate_single(vrf); + if (vrf) + vrf_terminate_single(vrf); } int vrf_socket(int domain, int type, int protocol, vrf_id_t vrf_id, @@ -659,115 +624,6 @@ int vrf_configure_backend(enum vrf_backend_type backend) return 0; } -int vrf_handler_create(struct vty *vty, const char *vrfname, - struct vrf **vrf) -{ - struct vrf *vrfp; - char xpath_list[XPATH_MAXLEN]; - int ret; - - if (strlen(vrfname) > VRF_NAMSIZ) { - if (vty) - vty_out(vty, - "%% VRF name %s invalid: length exceeds %d bytes\n", - vrfname, VRF_NAMSIZ); - else - flog_warn( - EC_LIB_VRF_LENGTH, - "%% VRF name %s invalid: length exceeds %d bytes", - vrfname, VRF_NAMSIZ); - return CMD_WARNING_CONFIG_FAILED; - } - - if (vty) { - snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH, - vrfname); - - nb_cli_enqueue_change(vty, xpath_list, NB_OP_CREATE, NULL); - ret = nb_cli_apply_changes_clear_pending(vty, xpath_list); - if (ret == CMD_SUCCESS) { - VTY_PUSH_XPATH(VRF_NODE, xpath_list); - vrfp = vrf_lookup_by_name(vrfname); - if (vrfp) - VTY_PUSH_CONTEXT(VRF_NODE, vrfp); - } - } else { - vrfp = vrf_get(VRF_UNKNOWN, vrfname); - - if (vrf) - *vrf = vrfp; - } - return CMD_SUCCESS; -} - -int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, char *pathname, - ns_id_t ns_id, ns_id_t internal_ns_id, - ns_id_t rel_def_ns_id) -{ - struct ns *ns = NULL; - - if (!vrf) - return CMD_WARNING_CONFIG_FAILED; - if (vrf->vrf_id != VRF_UNKNOWN && vrf->ns_ctxt == NULL) { - if (vty) - vty_out(vty, - "VRF %u is already configured with VRF %s\n", - vrf->vrf_id, vrf->name); - else - zlog_info("VRF %u is already configured with VRF %s", - vrf->vrf_id, vrf->name); - return CMD_WARNING_CONFIG_FAILED; - } - if (vrf->ns_ctxt != NULL) { - ns = (struct ns *)vrf->ns_ctxt; - if (!strcmp(ns->name, pathname)) { - if (vty) - vty_out(vty, - "VRF %u already configured with NETNS %s\n", - vrf->vrf_id, ns->name); - else - zlog_info( - "VRF %u already configured with NETNS %s", - vrf->vrf_id, ns->name); - return CMD_WARNING_CONFIG_FAILED; - } - } - ns = ns_lookup_name(pathname); - if (ns && ns->vrf_ctxt) { - struct vrf *vrf2 = (struct vrf *)ns->vrf_ctxt; - - if (vrf2 == vrf) - return CMD_SUCCESS; - if (vty) - vty_out(vty, - "NS %s is already configured with VRF %u(%s)\n", - ns->name, vrf2->vrf_id, vrf2->name); - else - zlog_info("NS %s is already configured with VRF %u(%s)", - ns->name, vrf2->vrf_id, vrf2->name); - return CMD_WARNING_CONFIG_FAILED; - } - ns = ns_get_created(ns, pathname, ns_id); - ns->internal_ns_id = internal_ns_id; - ns->relative_default_ns = rel_def_ns_id; - ns->vrf_ctxt = (void *)vrf; - vrf->ns_ctxt = (void *)ns; - /* update VRF netns NAME */ - strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ); - - if (!ns_enable(ns, vrf_update_vrf_id)) { - if (vty) - vty_out(vty, "Can not associate NS %u with NETNS %s\n", - ns->ns_id, ns->name); - else - zlog_info("Can not associate NS %u with NETNS %s", - ns->ns_id, ns->name); - return CMD_WARNING_CONFIG_FAILED; - } - - return CMD_SUCCESS; -} - /* vrf CLI commands */ DEFUN_NOSH(vrf_exit, vrf_exit_cmd, @@ -786,8 +642,29 @@ DEFUN_YANG_NOSH (vrf, { int idx_name = 1; const char *vrfname = argv[idx_name]->arg; + char xpath_list[XPATH_MAXLEN]; + struct vrf *vrf; + int ret; - return vrf_handler_create(vty, vrfname, NULL); + if (strlen(vrfname) > VRF_NAMSIZ) { + vty_out(vty, + "%% VRF name %s invalid: length exceeds %d bytes\n", + vrfname, VRF_NAMSIZ); + return CMD_WARNING_CONFIG_FAILED; + } + + snprintf(xpath_list, sizeof(xpath_list), FRR_VRF_KEY_XPATH, vrfname); + + nb_cli_enqueue_change(vty, xpath_list, NB_OP_CREATE, NULL); + ret = nb_cli_apply_changes_clear_pending(vty, xpath_list); + if (ret == CMD_SUCCESS) { + VTY_PUSH_XPATH(VRF_NODE, xpath_list); + vrf = vrf_lookup_by_name(vrfname); + if (vrf) + VTY_PUSH_CONTEXT(VRF_NODE, vrf); + } + + return ret; } DEFUN_YANG (no_vrf, @@ -814,15 +691,10 @@ DEFUN_YANG (no_vrf, if (vrf_get_backend() == VRF_BACKEND_VRF_LITE) { /* - * Remove the VRF interface config. Currently, we allow to - * remove only inactive VRFs, so we use VRF_DEFAULT_NAME here, - * because when the VRF is removed from kernel, the interface - * is moved to the default VRF. If we ever allow removing - * active VRFs, this code have to be updated accordingly. + * Remove the VRF interface config when removing the VRF. */ snprintf(xpath_list, sizeof(xpath_list), - "/frr-interface:lib/interface[name='%s'][vrf='%s']", - vrfname, VRF_DEFAULT_NAME); + "/frr-interface:lib/interface[name='%s']", vrfname); nb_cli_enqueue_change(vty, xpath_list, NB_OP_DESTROY, NULL); } @@ -176,8 +176,6 @@ static inline uint32_t vrf_interface_count(struct vrf *vrf) * Utilities to obtain the user data */ -/* Get the data pointer of the specified VRF. If not found, create one. */ -extern void *vrf_info_get(vrf_id_t); /* Look up the data pointer of the specified VRF. */ extern void *vrf_info_lookup(vrf_id_t); @@ -301,21 +299,6 @@ extern int vrf_configure_backend(enum vrf_backend_type backend); extern int vrf_get_backend(void); extern int vrf_is_backend_netns(void); - -/* API to create a VRF. either from vty - * or through discovery - */ -extern int vrf_handler_create(struct vty *vty, const char *name, - struct vrf **vrf); - -/* API to associate a VRF with a NETNS. - * called either from vty or through discovery - * should be called from zebra only - */ -extern int vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, - char *pathname, ns_id_t ext_ns_id, - ns_id_t ns_id, ns_id_t rel_def_ns_id); - /* used internally to enable or disable VRF. * Notify a change in the VRF ID of the VRF */ @@ -48,6 +48,7 @@ #include "lib_errors.h" #include "northbound_cli.h" #include "printfrr.h" +#include "json.h" #include <arpa/telnet.h> #include <termios.h> @@ -57,9 +58,12 @@ #endif DEFINE_MTYPE_STATIC(LIB, VTY, "VTY"); +DEFINE_MTYPE_STATIC(LIB, VTY_SERV, "VTY server"); DEFINE_MTYPE_STATIC(LIB, VTY_OUT_BUF, "VTY output buffer"); DEFINE_MTYPE_STATIC(LIB, VTY_HIST, "VTY history"); +DECLARE_DLIST(vtys, struct vty, itm); + /* Vty events */ enum event { VTY_SERV, @@ -73,17 +77,31 @@ enum event { #endif /* VTYSH */ }; -static void vty_event_serv(enum event event, int sock); +PREDECL_DLIST(vtyservs); + +struct vty_serv { + struct vtyservs_item itm; + + int sock; + bool vtysh; + + struct thread *t_accept; +}; + +DECLARE_DLIST(vtyservs, struct vty_serv, itm); + +static void vty_event_serv(enum event event, struct vty_serv *); static void vty_event(enum event, struct vty *); /* Extern host structure from command.c */ extern struct host host; -/* Vector which store each vty structure. */ -static vector vtyvec; +/* active listeners */ +static struct vtyservs_head vty_servs[1] = {INIT_DLIST(vty_servs[0])}; -/* Vector for vtysh connections. */ -static vector vtyshvec; +/* active connections */ +static struct vtys_head vty_sessions[1] = {INIT_DLIST(vty_sessions[0])}; +static struct vtys_head vtysh_sessions[1] = {INIT_DLIST(vtysh_sessions[0])}; /* Vty timeout value. */ static unsigned long vty_timeout_val = VTY_TIMEOUT_DEFAULT; @@ -94,9 +112,6 @@ static char *vty_accesslist_name = NULL; /* Vty access-calss for IPv6. */ static char *vty_ipv6_accesslist_name = NULL; -/* VTY server thread. */ -static vector Vvty_serv_thread; - /* Current directory. */ static char vty_cwd[MAXPATHLEN]; @@ -266,70 +281,28 @@ done: return len; } -static int vty_log_out(struct vty *vty, const char *level, - const char *proto_str, const char *msg, - struct timestamp_control *ctl) +int vty_json(struct vty *vty, struct json_object *json) { - int ret; - int len; - char buf[1024]; + const char *text; - if (!ctl->already_rendered) { - ctl->len = quagga_timestamp(ctl->precision, ctl->buf, - sizeof(ctl->buf)); - ctl->already_rendered = 1; - } - if (ctl->len + 1 >= sizeof(buf)) - return -1; - memcpy(buf, ctl->buf, len = ctl->len); - buf[len++] = ' '; - buf[len] = '\0'; - - if (level) - ret = snprintf(buf + len, sizeof(buf) - len, "%s: %s: ", level, - proto_str); - else - ret = snprintf(buf + len, sizeof(buf) - len, "%s: ", proto_str); - if ((ret < 0) || ((size_t)(len += ret) >= sizeof(buf))) - return -1; + if (!json) + return CMD_SUCCESS; - if (((ret = snprintf(buf + len, sizeof(buf) - len, "%s", msg)) < 0) - || ((size_t)((len += ret) + 2) > sizeof(buf))) - return -1; + text = json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY | JSON_C_TO_STRING_NOSLASHESCAPE); + vty_out(vty, "%s\n", text); + json_object_free(json); - buf[len++] = '\r'; - buf[len++] = '\n'; - - if (write(vty->wfd, buf, len) < 0) { - if (ERRNO_IO_RETRY(errno)) - /* Kernel buffer is full, probably too much debugging - output, so just - drop the data and ignore. */ - return -1; - /* Fatal I/O error. */ - vty->monitor = - 0; /* disable monitoring to avoid infinite recursion */ - flog_err(EC_LIB_SOCKET, - "%s: write failed to vty client fd %d, closing: %s", - __func__, vty->fd, safe_strerror(errno)); - buffer_reset(vty->obuf); - buffer_reset(vty->lbuf); - /* cannot call vty_close, because a parent routine may still try - to access the vty struct */ - vty->status = VTY_CLOSE; - shutdown(vty->fd, SHUT_RDWR); - return -1; - } - return 0; + return CMD_SUCCESS; } /* Output current time to the vty. */ void vty_time_print(struct vty *vty, int cr) { - char buf[QUAGGA_TIMESTAMP_LEN]; + char buf[FRR_TIMESTAMP_LEN]; - if (quagga_timestamp(0, buf, sizeof(buf)) == 0) { - zlog_info("quagga_timestamp error"); + if (frr_timestamp(0, buf, sizeof(buf)) == 0) { + zlog_info("frr_timestamp error"); return; } if (cr) @@ -480,19 +453,12 @@ static int vty_command(struct vty *vty, char *buf) cp++; } if (cp != NULL && *cp != '\0') { - unsigned i; char vty_str[VTY_BUFSIZ]; char prompt_str[VTY_BUFSIZ]; /* format the base vty info */ - snprintf(vty_str, sizeof(vty_str), "vty[??]@%s", vty->address); - - for (i = 0; i < vector_active(vtyvec); i++) - if (vty == vector_slot(vtyvec, i)) { - snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s", - i, vty->address); - break; - } + snprintf(vty_str, sizeof(vty_str), "vty[%d]@%s", vty->fd, + vty->address); /* format the prompt */ snprintf(prompt_str, sizeof(prompt_str), cmd_prompt(vty->node), @@ -776,7 +742,7 @@ static void vty_end_config(struct vty *vty) vty->cp = 0; } -/* Delete a charcter at the current point. */ +/* Delete a character at the current point. */ static void vty_delete_char(struct vty *vty) { int i; @@ -1624,13 +1590,14 @@ static struct vty *vty_new_init(int vty_sock) memset(vty->xpath, 0, sizeof(vty->xpath)); vty->private_config = false; vty->candidate_config = vty_shared_candidate_config; - vector_set_index(vtyvec, vty_sock, vty); vty->status = VTY_NORMAL; vty->lines = -1; vty->iac = 0; vty->iac_sb_in_progress = 0; vty->sb_len = 0; + vtys_add_tail(vty_sessions, vty); + return vty; } @@ -1788,18 +1755,17 @@ struct vty *vty_stdio(void (*atclose)(int isexit)) /* Accept connection from the network. */ static int vty_accept(struct thread *thread) { + struct vty_serv *vtyserv = THREAD_ARG(thread); int vty_sock; union sockunion su; int ret; unsigned int on; - int accept_sock; + int accept_sock = vtyserv->sock; struct prefix p; struct access_list *acl = NULL; - accept_sock = THREAD_FD(thread); - /* We continue hearing vty socket. */ - vty_event_serv(VTY_SERV, accept_sock); + vty_event_serv(VTY_SERV, vtyserv); memset(&su, 0, sizeof(union sockunion)); @@ -1826,10 +1792,6 @@ static int vty_accept(struct thread *thread) && (access_list_apply(acl, &p) == FILTER_DENY)) { zlog_info("Vty connection refused from %pSU", &su); close(vty_sock); - - /* continue accepting connections */ - vty_event_serv(VTY_SERV, accept_sock); - return 0; } } @@ -1841,10 +1803,6 @@ static int vty_accept(struct thread *thread) && (access_list_apply(acl, &p) == FILTER_DENY)) { zlog_info("Vty connection refused from %pSU", &su); close(vty_sock); - - /* continue accepting connections */ - vty_event_serv(VTY_SERV, accept_sock); - return 0; } } @@ -1890,6 +1848,8 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port) ainfo_save = ainfo; do { + struct vty_serv *vtyserv; + if (ainfo->ai_family != AF_INET && ainfo->ai_family != AF_INET6) continue; @@ -1915,7 +1875,11 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port) continue; } - vty_event_serv(VTY_SERV, sock); + vtyserv = XCALLOC(MTYPE_VTY_SERV, sizeof(*vtyserv)); + vtyserv->sock = sock; + vtyservs_add_tail(vty_servs, vtyserv); + + vty_event_serv(VTY_SERV, vtyserv); } while ((ainfo = ainfo->ai_next) != NULL); freeaddrinfo(ainfo_save); @@ -1928,6 +1892,7 @@ static void vty_serv_sock_addrinfo(const char *hostname, unsigned short port) /* VTY shell UNIX domain socket. */ static void vty_serv_un(const char *path) { + struct vty_serv *vtyserv; int ret; int sock, len; struct sockaddr_un serv; @@ -1993,22 +1958,26 @@ static void vty_serv_un(const char *path) } } - vty_event_serv(VTYSH_SERV, sock); + vtyserv = XCALLOC(MTYPE_VTY_SERV, sizeof(*vtyserv)); + vtyserv->sock = sock; + vtyserv->vtysh = true; + vtyservs_add_tail(vty_servs, vtyserv); + + vty_event_serv(VTYSH_SERV, vtyserv); } /* #define VTYSH_DEBUG 1 */ static int vtysh_accept(struct thread *thread) { - int accept_sock; + struct vty_serv *vtyserv = THREAD_ARG(thread); + int accept_sock = vtyserv->sock; int sock; int client_len; struct sockaddr_un client; struct vty *vty; - accept_sock = THREAD_FD(thread); - - vty_event_serv(VTYSH_SERV, accept_sock); + vty_event_serv(VTYSH_SERV, vtyserv); memset(&client, 0, sizeof(struct sockaddr_un)); client_len = sizeof(struct sockaddr_un); @@ -2041,7 +2010,7 @@ static int vtysh_accept(struct thread *thread) vty->wfd = sock; vty->type = VTY_SHELL_SERV; vty->node = VIEW_NODE; - vector_set_index(vtyshvec, sock, vty); + vtys_add_tail(vtysh_sessions, vty); vty_event(VTYSH_READ, vty); @@ -2217,9 +2186,9 @@ void vty_close(struct vty *vty) /* Unset vector. */ if (vty->fd != -1) { if (vty->type == VTY_SHELL_SERV) - vector_unset(vtyshvec, vty->fd); + vtys_del(vtysh_sessions, vty); else - vector_unset(vtyvec, vty->fd); + vtys_del(vty_sessions, vty); } if (vty->wfd > 0 && vty->type == VTY_FILE) @@ -2282,7 +2251,7 @@ static void vty_read_file(struct nb_config *config, FILE *confp) vty = vty_new(); /* vty_close won't close stderr; if some config command prints - * something it'll end up there. (not ideal; it'd be beter if output + * something it'll end up there. (not ideal; it'd be better if output * from a file-load went to logging instead. Also note that if this * function is called after daemonizing, stderr will be /dev/null.) * @@ -2533,52 +2502,6 @@ tmp_free_and_out: return read_success; } -/* Small utility function which output log to the VTY. */ -void vty_log(const char *level, const char *proto_str, const char *msg, - struct timestamp_control *ctl) -{ - unsigned int i; - struct vty *vty; - - if (!vtyvec) - return; - - for (i = 0; i < vector_active(vtyvec); i++) - if ((vty = vector_slot(vtyvec, i)) != NULL) - if (vty->monitor) - vty_log_out(vty, level, proto_str, msg, ctl); -} - -/* Async-signal-safe version of vty_log for fixed strings. */ -void vty_log_fixed(char *buf, size_t len) -{ - unsigned int i; - struct iovec iov[2]; - char crlf[4] = "\r\n"; - - /* vty may not have been initialised */ - if (!vtyvec) - return; - - iov[0].iov_base = buf; - iov[0].iov_len = len; - iov[1].iov_base = crlf; - iov[1].iov_len = 2; - - for (i = 0; i < vector_active(vtyvec); i++) { - struct vty *vty; - if (((vty = vector_slot(vtyvec, i)) != NULL) && vty->monitor) - /* N.B. We don't care about the return code, since - process is - most likely just about to die anyway. */ - if (writev(vty->wfd, iov, 2) == -1) { - fprintf(stderr, "Failure to writev: %d\n", - errno); - exit(-1); - } - } -} - static void update_xpath(struct vty *vty, const char *oldpath, const char *newpath) { @@ -2597,21 +2520,11 @@ static void update_xpath(struct vty *vty, const char *oldpath, void vty_update_xpath(const char *oldpath, const char *newpath) { struct vty *vty; - unsigned int i; - - for (i = 0; i < vector_active(vtyshvec); i++) { - if ((vty = vector_slot(vtyshvec, i)) == NULL) - continue; + frr_each (vtys, vtysh_sessions, vty) update_xpath(vty, oldpath, newpath); - } - - for (i = 0; i < vector_active(vtyvec); i++) { - if ((vty = vector_slot(vtyvec, i)) == NULL) - continue; - + frr_each (vtys, vty_sessions, vty) update_xpath(vty, oldpath, newpath); - } } int vty_config_enter(struct vty *vty, bool private_config, bool exclusive) @@ -2695,21 +2608,17 @@ int vty_config_node_exit(struct vty *vty) /* Master of the threads. */ static struct thread_master *vty_master; -static void vty_event_serv(enum event event, int sock) +static void vty_event_serv(enum event event, struct vty_serv *vty_serv) { - struct thread *vty_serv_thread = NULL; - switch (event) { case VTY_SERV: - vty_serv_thread = thread_add_read(vty_master, vty_accept, - NULL, sock, NULL); - vector_set_index(Vvty_serv_thread, sock, vty_serv_thread); + thread_add_read(vty_master, vty_accept, vty_serv, + vty_serv->sock, &vty_serv->t_accept); break; #ifdef VTYSH case VTYSH_SERV: - vty_serv_thread = thread_add_read(vty_master, vtysh_accept, - NULL, sock, NULL); - vector_set_index(Vvty_serv_thread, sock, vty_serv_thread); + thread_add_read(vty_master, vtysh_accept, vty_serv, + vty_serv->sock, &vty_serv->t_accept); break; #endif /* VTYSH */ default: @@ -2761,13 +2670,11 @@ DEFUN_NOSH (config_who, "who", "Display who is on vty\n") { - unsigned int i; struct vty *v; - for (i = 0; i < vector_active(vtyvec); i++) - if ((v = vector_slot(vtyvec, i)) != NULL) - vty_out(vty, "%svty[%d] connected from %s.\n", - v->config ? "*" : " ", i, v->address); + frr_each (vtys, vty_sessions, v) + vty_out(vty, "%svty[%d] connected from %s.\n", + v->config ? "*" : " ", v->fd, v->address); return CMD_SUCCESS; } @@ -3080,25 +2987,14 @@ struct cmd_node vty_node = { /* Reset all VTY status. */ void vty_reset(void) { - unsigned int i; struct vty *vty; - struct thread *vty_serv_thread; - - for (i = 0; i < vector_active(vtyvec); i++) - if ((vty = vector_slot(vtyvec, i)) != NULL) { - buffer_reset(vty->lbuf); - buffer_reset(vty->obuf); - vty->status = VTY_CLOSE; - vty_close(vty); - } - for (i = 0; i < vector_active(Vvty_serv_thread); i++) - if ((vty_serv_thread = vector_slot(Vvty_serv_thread, i)) - != NULL) { - THREAD_OFF(vty_serv_thread); - vector_slot(Vvty_serv_thread, i) = NULL; - close(i); - } + frr_each_safe (vtys, vty_sessions, vty) { + buffer_reset(vty->lbuf); + buffer_reset(vty->obuf); + vty->status = VTY_CLOSE; + vty_close(vty); + } vty_timeout_val = VTY_TIMEOUT_DEFAULT; @@ -3118,7 +3014,7 @@ static void vty_save_cwd(void) * the whole world is coming down around us * Hence not worrying about it too much. */ - if (!chdir(SYSCONFDIR)) { + if (chdir(SYSCONFDIR)) { flog_err_sys(EC_LIB_SYSTEM_CALL, "Failure to chdir to %s, errno: %d", SYSCONFDIR, errno); @@ -3149,7 +3045,7 @@ int vty_shell_serv(struct vty *vty) void vty_init_vtysh(void) { - vtyvec = vector_init(VECTOR_MIN_SIZE); + /* currently nothing to do, but likely to have future use */ } /* Install vty's own commands like `who' command. */ @@ -3158,16 +3054,10 @@ void vty_init(struct thread_master *master_thread, bool do_command_logging) /* For further configuration read, preserve current directory. */ vty_save_cwd(); - vtyvec = vector_init(VECTOR_MIN_SIZE); - vtyshvec = vector_init(VECTOR_MIN_SIZE); - vty_master = master_thread; atexit(vty_stdio_atexit); - /* Initilize server thread vector. */ - Vvty_serv_thread = vector_init(VECTOR_MIN_SIZE); - /* Install bgp top node. */ install_node(&vty_node); @@ -3202,17 +3092,34 @@ void vty_init(struct thread_master *master_thread, bool do_command_logging) void vty_terminate(void) { + struct vty *vty; + struct vty_serv *vtyserv; + memset(vty_cwd, 0x00, sizeof(vty_cwd)); - if (vtyvec && Vvty_serv_thread) { - vty_reset(); - vector_free(vtyvec); - vector_free(Vvty_serv_thread); - vtyvec = NULL; - Vvty_serv_thread = NULL; + vty_reset(); + + /* default state of vty_sessions is initialized & empty. */ + vtys_fini(vty_sessions); + vtys_init(vty_sessions); + + /* vty_reset() doesn't close vtysh sessions */ + frr_each_safe (vtys, vtysh_sessions, vty) { + buffer_reset(vty->lbuf); + buffer_reset(vty->obuf); + vty->status = VTY_CLOSE; + vty_close(vty); } - if (vtyshvec) { - vector_free(vtyshvec); - vtyshvec = NULL; + + vtys_fini(vtysh_sessions); + vtys_init(vtysh_sessions); + + while ((vtyserv = vtyservs_pop(vty_servs))) { + THREAD_OFF(vtyserv->t_accept); + close(vtyserv->sock); + XFREE(MTYPE_VTY_SERV, vtyserv); } + + vtyservs_fini(vty_servs); + vtyservs_init(vty_servs); } @@ -39,6 +39,8 @@ extern "C" { #endif +struct json_object; + #define VTY_BUFSIZ 4096 #define VTY_MAXHIST 20 #define VTY_MAXDEPTH 8 @@ -56,8 +58,12 @@ struct vty_cfg_change { const char *value; }; +PREDECL_DLIST(vtys); + /* VTY struct. */ struct vty { + struct vtys_item itm; + /* File descripter of this vty. */ int fd; @@ -317,7 +323,11 @@ extern struct vty *vty_stdio(void (*atclose)(int isexit)); extern int vty_out(struct vty *, const char *, ...) PRINTFRR(2, 3); extern void vty_frame(struct vty *, const char *, ...) PRINTFRR(2, 3); extern void vty_endframe(struct vty *, const char *); -bool vty_set_include(struct vty *vty, const char *regexp); +extern bool vty_set_include(struct vty *vty, const char *regexp); +/* returns CMD_SUCCESS so you can do a one-line "return vty_json(...)" + * NULL check and json_object_free() is included. + */ +extern int vty_json(struct vty *vty, struct json_object *json); extern bool vty_read_config(struct nb_config *config, const char *config_file, char *config_default_dir); @@ -325,8 +335,6 @@ extern void vty_time_print(struct vty *, int); extern void vty_serv_sock(const char *, unsigned short, const char *); extern void vty_close(struct vty *); extern char *vty_get_cwd(void); -extern void vty_log(const char *level, const char *proto, const char *msg, - struct timestamp_control *); extern void vty_update_xpath(const char *oldpath, const char *newpath); extern int vty_config_enter(struct vty *vty, bool private_config, bool exclusive); @@ -341,10 +349,6 @@ extern void vty_stdio_suspend(void); extern void vty_stdio_resume(void); extern void vty_stdio_close(void); -/* Send a fixed-size message to all vty terminal monitors; this should be - an async-signal-safe function. */ -extern void vty_log_fixed(char *buf, size_t len); - #ifdef __cplusplus } #endif diff --git a/lib/vxlan.h b/lib/vxlan.h index 62963a6097..220fd8d232 100644 --- a/lib/vxlan.h +++ b/lib/vxlan.h @@ -26,7 +26,7 @@ extern "C" { #endif -/* EVPN MH DF election alogorithm */ +/* EVPN MH DF election algorithm */ #define EVPN_MH_DF_ALG_SERVICE_CARVING 0 #define EVPN_MH_DF_ALG_HRW 1 #define EVPN_MH_DF_ALG_PREF 2 diff --git a/lib/xref.c b/lib/xref.c index a41f91a228..0d3549d062 100644 --- a/lib/xref.c +++ b/lib/xref.c @@ -35,6 +35,8 @@ struct xref_block *xref_blocks; static struct xref_block **xref_block_last = &xref_blocks; +struct xrefdata_uid_head xrefdata_uid = INIT_RBTREE_UNIQ(xrefdata_uid); + static void base32(uint8_t **inpos, int *bitpos, char *out, size_t n_chars) { @@ -109,6 +111,8 @@ static void xref_add_one(const struct xref *xref) base32(&h, &bitpos, &xrefdata->uid[0], 5); xrefdata->uid[5] = '-'; base32(&h, &bitpos, &xrefdata->uid[6], 5); + + xrefdata_uid_add(&xrefdata_uid, xrefdata); } void xref_gcc_workaround(const struct xref *xref) diff --git a/lib/xref.h b/lib/xref.h index 6cff1a3769..0e3f00f690 100644 --- a/lib/xref.h +++ b/lib/xref.h @@ -22,6 +22,7 @@ #include <limits.h> #include <errno.h> #include "compiler.h" +#include "typesafe.h" #ifdef __cplusplus extern "C" { @@ -63,6 +64,8 @@ struct xref { /* type-specific bits appended by embedding this struct */ }; +PREDECL_RBTREE_UNIQ(xrefdata_uid); + struct xrefdata { /* pointer back to the const part; this will be initialized at * program startup by xref_block_add(). (Creating structs with @@ -88,8 +91,18 @@ struct xrefdata { uint32_t hashu32[2]; /* -- 32 bytes (on 64bit) -- */ + struct xrefdata_uid_item xui; }; +static inline int xrefdata_uid_cmp(const struct xrefdata *a, + const struct xrefdata *b) +{ + return strcmp(a->uid, b->uid); +} + +DECLARE_RBTREE_UNIQ(xrefdata_uid, struct xrefdata, xui, xrefdata_uid_cmp); +extern struct xrefdata_uid_head xrefdata_uid; + /* linker "magic" is used to create an array of pointers to struct xref. * the result is a contiguous block of pointers, each pointing to an xref * somewhere in the code. The linker gives us start and end pointers, we diff --git a/lib/yang.h b/lib/yang.h index d4517f969a..d625b24f6a 100644 --- a/lib/yang.h +++ b/lib/yang.h @@ -183,7 +183,7 @@ extern int yang_snodes_iterate_subtree(const struct lysc_node *snode, void *arg); /* - * Iterate over all libyang schema nodes from all loeaded modules of from the + * Iterate over all libyang schema nodes from all loaded modules of the * given YANG module. * * module diff --git a/lib/zclient.c b/lib/zclient.c index dde60a6c90..000dcaac8f 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -66,7 +66,8 @@ static int zclient_debug; /* Allocate zclient structure. */ struct zclient *zclient_new(struct thread_master *master, - struct zclient_options *opt) + struct zclient_options *opt, + zclient_handler *const *handlers, size_t n_handlers) { struct zclient *zclient; size_t stream_size = @@ -79,6 +80,9 @@ struct zclient *zclient_new(struct thread_master *master, zclient->wb = buffer_new(0); zclient->master = master; + zclient->handlers = handlers; + zclient->n_handlers = n_handlers; + zclient->receive_notify = opt->receive_notify; zclient->synchronous = opt->synchronous; @@ -450,7 +454,7 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient, p.prefix = *sid; api.vrf_id = VRF_DEFAULT; - api.type = ZEBRA_ROUTE_BGP; + api.type = zclient->redist_default; api.instance = 0; api.safi = SAFI_UNICAST; memcpy(&api.prefix, &p, sizeof(p)); @@ -765,15 +769,17 @@ static int zclient_connect(struct thread *t) enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command, const struct prefix *p, - bool exact_match, vrf_id_t vrf_id) + bool connected, + bool resolve_via_def, vrf_id_t vrf_id) { struct stream *s; s = zclient->obuf; stream_reset(s); zclient_create_header(s, command, vrf_id); - stream_putc(s, (exact_match) ? 1 : 0); - + stream_putc(s, (connected) ? 1 : 0); + stream_putc(s, (resolve_via_def) ? 1 : 0); + stream_putw(s, SAFI_UNICAST); stream_putw(s, PREFIX_FAMILY(p)); stream_putc(s, p->prefixlen); switch (PREFIX_FAMILY(p)) { @@ -1925,6 +1931,7 @@ bool zapi_nexthop_update_decode(struct stream *s, struct zapi_route *nhr) memset(nhr, 0, sizeof(*nhr)); STREAM_GETL(s, nhr->message); + STREAM_GETW(s, nhr->safi); STREAM_GETW(s, nhr->prefix.family); STREAM_GETC(s, nhr->prefix.prefixlen); switch (nhr->prefix.family) { @@ -2096,7 +2103,7 @@ stream_failure: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Harware Address Length | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - * | Hardware Address if HW lenght different from 0 | + * | Hardware Address if HW length different from 0 | * | ... max INTERFACE_HWADDR_MAX | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ * | Link_params? | Whether a link-params follows: 1 or 0. @@ -2106,7 +2113,7 @@ stream_failure: * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ */ -static int zclient_vrf_add(struct zclient *zclient, vrf_id_t vrf_id) +static int zclient_vrf_add(ZAPI_CALLBACK_ARGS) { struct vrf *vrf; char vrfname_tmp[VRF_NAMSIZ + 1] = {}; @@ -2138,7 +2145,7 @@ stream_failure: return -1; } -static void zclient_vrf_delete(struct zclient *zclient, vrf_id_t vrf_id) +static int zclient_vrf_delete(ZAPI_CALLBACK_ARGS) { struct vrf *vrf; @@ -2151,29 +2158,32 @@ static void zclient_vrf_delete(struct zclient *zclient, vrf_id_t vrf_id) * no point in attempting to delete it. */ if (!vrf) - return; + return 0; vrf_delete(vrf); + return 0; } -static int zclient_interface_add(struct zclient *zclient, vrf_id_t vrf_id) +static int zclient_interface_add(ZAPI_CALLBACK_ARGS) { struct interface *ifp; char ifname_tmp[INTERFACE_NAMSIZ + 1] = {}; struct stream *s = zclient->ibuf; + struct vrf *vrf; /* Read interface name. */ STREAM_GET(ifname_tmp, s, INTERFACE_NAMSIZ); /* Lookup/create interface by name. */ - if (!vrf_get(vrf_id, NULL)) { + vrf = vrf_lookup_by_id(vrf_id); + if (!vrf) { zlog_debug( "Rx'd interface add from Zebra, but VRF %u does not exist", vrf_id); return -1; } - ifp = if_get_by_name(ifname_tmp, vrf_id); + ifp = if_get_by_name(ifname_tmp, vrf_id, vrf->name); zebra_interface_if_set_value(s, ifp); @@ -2214,7 +2224,7 @@ stream_failure: return NULL; } -static void zclient_interface_delete(struct zclient *zclient, vrf_id_t vrf_id) +static int zclient_interface_delete(ZAPI_CALLBACK_ARGS) { struct interface *ifp; struct stream *s = zclient->ibuf; @@ -2222,13 +2232,13 @@ static void zclient_interface_delete(struct zclient *zclient, vrf_id_t vrf_id) ifp = zebra_interface_state_read(s, vrf_id); if (ifp == NULL) - return; + return 0; if_destroy_via_zapi(ifp); - return; + return 0; } -static void zclient_interface_up(struct zclient *zclient, vrf_id_t vrf_id) +static int zclient_interface_up(ZAPI_CALLBACK_ARGS) { struct interface *ifp; struct stream *s = zclient->ibuf; @@ -2236,12 +2246,13 @@ static void zclient_interface_up(struct zclient *zclient, vrf_id_t vrf_id) ifp = zebra_interface_state_read(s, vrf_id); if (!ifp) - return; + return 0; if_up_via_zapi(ifp); + return 0; } -static void zclient_interface_down(struct zclient *zclient, vrf_id_t vrf_id) +static int zclient_interface_down(ZAPI_CALLBACK_ARGS) { struct interface *ifp; struct stream *s = zclient->ibuf; @@ -2249,12 +2260,13 @@ static void zclient_interface_down(struct zclient *zclient, vrf_id_t vrf_id) ifp = zebra_interface_state_read(s, vrf_id); if (!ifp) - return; + return 0; if_down_via_zapi(ifp); + return 0; } -static void zclient_handle_error(ZAPI_CALLBACK_ARGS) +static int zclient_handle_error(ZAPI_CALLBACK_ARGS) { enum zebra_error_types error; struct stream *s = zclient->ibuf; @@ -2263,6 +2275,7 @@ static void zclient_handle_error(ZAPI_CALLBACK_ARGS) if (zclient->handle_error) (*zclient->handle_error)(error); + return 0; } static int link_params_set_value(struct stream *s, struct if_link_params *iflp) @@ -2435,7 +2448,7 @@ size_t zebra_interface_link_params_write(struct stream *s, } /* - * format of message for address additon is: + * format of message for address addition is: * 0 * 0 1 2 3 4 5 6 7 * +-+-+-+-+-+-+-+-+ @@ -2700,9 +2713,9 @@ static int zclient_read_sync_response(struct zclient *zclient, return 0; } /** - * Connect to label manager in a syncronous way + * Connect to label manager in a synchronous way * - * It first writes the request to zcient output buffer and then + * It first writes the request to zclient output buffer and then * immediately reads the answer from the input buffer. * * @param zclient Zclient used to connect to label manager (zebra) @@ -2795,7 +2808,7 @@ stream_failure: } /** - * Function to request a srv6-locator chunk in an Asyncronous way + * Function to request a srv6-locator chunk in an asynchronous way * * @param zclient Zclient used to connect to table manager (zebra) * @param locator_name Name of SRv6-locator @@ -2905,9 +2918,9 @@ enum zclient_send_status zclient_send_get_label_chunk(struct zclient *zclient, } /** - * Function to request a label chunk in a syncronous way + * Function to request a label chunk in a synchronous way * - * It first writes the request to zlcient output buffer and then + * It first writes the request to zclient output buffer and then * immediately reads the answer from the input buffer. * * @param zclient Zclient used to connect to label manager (zebra) @@ -3082,9 +3095,9 @@ int lm_release_label_chunk(struct zclient *zclient, uint32_t start, } /** - * Connect to table manager in a syncronous way + * Connect to table manager in a synchronous way * - * It first writes the request to zcient output buffer and then + * It first writes the request to zclient output buffer and then * immediately reads the answer from the input buffer. * * @param zclient Zclient used to connect to table manager (zebra) @@ -3141,7 +3154,7 @@ stream_failure: } /** - * Function to request a table chunk in a syncronous way + * Function to request a table chunk in a synchronous way * * It first writes the request to zclient output buffer and then * immediately reads the answer from the input buffer. @@ -3580,7 +3593,7 @@ stream_failure: return -1; } -static void zclient_capability_decode(ZAPI_CALLBACK_ARGS) +static int zclient_capability_decode(ZAPI_CALLBACK_ARGS) { struct zclient_capabilities cap; struct stream *s = zclient->ibuf; @@ -3607,7 +3620,7 @@ static void zclient_capability_decode(ZAPI_CALLBACK_ARGS) (*zclient->zebra_capabilities)(&cap); stream_failure: - return; + return 0; } enum zclient_send_status zclient_send_mlag_register(struct zclient *client, @@ -3646,24 +3659,6 @@ enum zclient_send_status zclient_send_mlag_data(struct zclient *client, return zclient_send_message(client); } -static void zclient_mlag_process_up(ZAPI_CALLBACK_ARGS) -{ - if (zclient->mlag_process_up) - (*zclient->mlag_process_up)(); -} - -static void zclient_mlag_process_down(ZAPI_CALLBACK_ARGS) -{ - if (zclient->mlag_process_down) - (*zclient->mlag_process_down)(); -} - -static void zclient_mlag_handle_msg(ZAPI_CALLBACK_ARGS) -{ - if (zclient->mlag_handle_msg) - (*zclient->mlag_handle_msg)(zclient->ibuf, length); -} - /* * Send an OPAQUE message, contents opaque to zebra. The message header * is a message subtype. @@ -3853,6 +3848,24 @@ stream_failure: return -1; } +static zclient_handler *const lib_handlers[] = { + /* fundamentals */ + [ZEBRA_CAPABILITIES] = zclient_capability_decode, + [ZEBRA_ERROR] = zclient_handle_error, + + /* VRF & interface code is shared in lib */ + [ZEBRA_VRF_ADD] = zclient_vrf_add, + [ZEBRA_VRF_DELETE] = zclient_vrf_delete, + [ZEBRA_INTERFACE_ADD] = zclient_interface_add, + [ZEBRA_INTERFACE_DELETE] = zclient_interface_delete, + [ZEBRA_INTERFACE_UP] = zclient_interface_up, + [ZEBRA_INTERFACE_DOWN] = zclient_interface_down, + + /* BFD */ + [ZEBRA_BFD_DEST_REPLAY] = zclient_bfd_session_replay, + [ZEBRA_INTERFACE_BFD_DEST_UPDATE] = zclient_bfd_session_update, +}; + /* Zebra client message read function. */ static int zclient_read(struct thread *thread) { @@ -3952,290 +3965,10 @@ static int zclient_read(struct thread *thread) zlog_debug("zclient %p command %s VRF %u", zclient, zserv_command_string(command), vrf_id); - switch (command) { - case ZEBRA_CAPABILITIES: - zclient_capability_decode(command, zclient, length, vrf_id); - break; - case ZEBRA_ROUTER_ID_UPDATE: - if (zclient->router_id_update) - (*zclient->router_id_update)(command, zclient, length, - vrf_id); - break; - case ZEBRA_VRF_ADD: - zclient_vrf_add(zclient, vrf_id); - break; - case ZEBRA_VRF_DELETE: - zclient_vrf_delete(zclient, vrf_id); - break; - case ZEBRA_INTERFACE_ADD: - zclient_interface_add(zclient, vrf_id); - break; - case ZEBRA_INTERFACE_DELETE: - zclient_interface_delete(zclient, vrf_id); - break; - case ZEBRA_INTERFACE_ADDRESS_ADD: - if (zclient->interface_address_add) - (*zclient->interface_address_add)(command, zclient, - length, vrf_id); - break; - case ZEBRA_INTERFACE_ADDRESS_DELETE: - if (zclient->interface_address_delete) - (*zclient->interface_address_delete)(command, zclient, - length, vrf_id); - break; - case ZEBRA_INTERFACE_BFD_DEST_UPDATE: - if (zclient->interface_bfd_dest_update) - (*zclient->interface_bfd_dest_update)(command, zclient, - length, vrf_id); - break; - case ZEBRA_INTERFACE_NBR_ADDRESS_ADD: - if (zclient->interface_nbr_address_add) - (*zclient->interface_nbr_address_add)(command, zclient, - length, vrf_id); - break; - case ZEBRA_INTERFACE_NBR_ADDRESS_DELETE: - if (zclient->interface_nbr_address_delete) - (*zclient->interface_nbr_address_delete)( - command, zclient, length, vrf_id); - break; - case ZEBRA_INTERFACE_UP: - zclient_interface_up(zclient, vrf_id); - break; - case ZEBRA_INTERFACE_DOWN: - zclient_interface_down(zclient, vrf_id); - break; - case ZEBRA_INTERFACE_VRF_UPDATE: - if (zclient->interface_vrf_update) - (*zclient->interface_vrf_update)(command, zclient, - length, vrf_id); - break; - case ZEBRA_NEXTHOP_UPDATE: - if (zclient_debug) - zlog_debug("zclient rcvd nexthop update"); - if (zclient->nexthop_update) - (*zclient->nexthop_update)(command, zclient, length, - vrf_id); - break; - case ZEBRA_IMPORT_CHECK_UPDATE: - if (zclient_debug) - zlog_debug("zclient rcvd import check update"); - if (zclient->import_check_update) - (*zclient->import_check_update)(command, zclient, - length, vrf_id); - break; - case ZEBRA_BFD_DEST_REPLAY: - if (zclient->bfd_dest_replay) - (*zclient->bfd_dest_replay)(command, zclient, length, - vrf_id); - break; - case ZEBRA_REDISTRIBUTE_ROUTE_ADD: - if (zclient->redistribute_route_add) - (*zclient->redistribute_route_add)(command, zclient, - length, vrf_id); - break; - case ZEBRA_REDISTRIBUTE_ROUTE_DEL: - if (zclient->redistribute_route_del) - (*zclient->redistribute_route_del)(command, zclient, - length, vrf_id); - break; - case ZEBRA_INTERFACE_LINK_PARAMS: - if (zclient->interface_link_params) - (*zclient->interface_link_params)(command, zclient, - length, vrf_id); - break; - case ZEBRA_FEC_UPDATE: - if (zclient_debug) - zlog_debug("zclient rcvd fec update"); - if (zclient->fec_update) - (*zclient->fec_update)(command, zclient, length); - break; - case ZEBRA_LOCAL_ES_ADD: - if (zclient->local_es_add) - (*zclient->local_es_add)(command, zclient, length, - vrf_id); - break; - case ZEBRA_LOCAL_ES_DEL: - if (zclient->local_es_del) - (*zclient->local_es_del)(command, zclient, length, - vrf_id); - break; - case ZEBRA_LOCAL_ES_EVI_ADD: - if (zclient->local_es_evi_add) - (*zclient->local_es_evi_add)(command, zclient, length, - vrf_id); - break; - case ZEBRA_LOCAL_ES_EVI_DEL: - if (zclient->local_es_evi_del) - (*zclient->local_es_evi_del)(command, zclient, length, - vrf_id); - break; - case ZEBRA_VNI_ADD: - if (zclient->local_vni_add) - (*zclient->local_vni_add)(command, zclient, length, - vrf_id); - break; - case ZEBRA_VNI_DEL: - if (zclient->local_vni_del) - (*zclient->local_vni_del)(command, zclient, length, - vrf_id); - break; - case ZEBRA_L3VNI_ADD: - if (zclient->local_l3vni_add) - (*zclient->local_l3vni_add)(command, zclient, length, - vrf_id); - break; - case ZEBRA_L3VNI_DEL: - if (zclient->local_l3vni_del) - (*zclient->local_l3vni_del)(command, zclient, length, - vrf_id); - break; - case ZEBRA_MACIP_ADD: - if (zclient->local_macip_add) - (*zclient->local_macip_add)(command, zclient, length, - vrf_id); - break; - case ZEBRA_MACIP_DEL: - if (zclient->local_macip_del) - (*zclient->local_macip_del)(command, zclient, length, - vrf_id); - break; - case ZEBRA_IP_PREFIX_ROUTE_ADD: - if (zclient->local_ip_prefix_add) - (*zclient->local_ip_prefix_add)(command, zclient, - length, vrf_id); - break; - case ZEBRA_IP_PREFIX_ROUTE_DEL: - if (zclient->local_ip_prefix_del) - (*zclient->local_ip_prefix_del)(command, zclient, - length, vrf_id); - break; - case ZEBRA_PW_STATUS_UPDATE: - if (zclient->pw_status_update) - (*zclient->pw_status_update)(command, zclient, length, - vrf_id); - break; - case ZEBRA_ROUTE_NOTIFY_OWNER: - if (zclient->route_notify_owner) - (*zclient->route_notify_owner)(command, zclient, length, - vrf_id); - break; - case ZEBRA_RULE_NOTIFY_OWNER: - if (zclient->rule_notify_owner) - (*zclient->rule_notify_owner)(command, zclient, length, - vrf_id); - break; - case ZEBRA_NHG_NOTIFY_OWNER: - if (zclient->nhg_notify_owner) - (*zclient->nhg_notify_owner)(command, zclient, length, - vrf_id); - break; - case ZEBRA_GET_LABEL_CHUNK: - if (zclient->label_chunk) - (*zclient->label_chunk)(command, zclient, length, - vrf_id); - break; - case ZEBRA_IPSET_NOTIFY_OWNER: - if (zclient->ipset_notify_owner) - (*zclient->ipset_notify_owner)(command, zclient, length, - vrf_id); - break; - case ZEBRA_IPSET_ENTRY_NOTIFY_OWNER: - if (zclient->ipset_entry_notify_owner) - (*zclient->ipset_entry_notify_owner)(command, - zclient, length, - vrf_id); - break; - case ZEBRA_IPTABLE_NOTIFY_OWNER: - if (zclient->iptable_notify_owner) - (*zclient->iptable_notify_owner)(command, - zclient, length, - vrf_id); - break; - case ZEBRA_VXLAN_SG_ADD: - if (zclient->vxlan_sg_add) - (*zclient->vxlan_sg_add)(command, zclient, length, - vrf_id); - break; - case ZEBRA_VXLAN_SG_DEL: - if (zclient->vxlan_sg_del) - (*zclient->vxlan_sg_del)(command, zclient, length, - vrf_id); - break; - case ZEBRA_MLAG_PROCESS_UP: - zclient_mlag_process_up(command, zclient, length, vrf_id); - break; - case ZEBRA_MLAG_PROCESS_DOWN: - zclient_mlag_process_down(command, zclient, length, vrf_id); - break; - case ZEBRA_MLAG_FORWARD_MSG: - zclient_mlag_handle_msg(command, zclient, length, vrf_id); - break; - case ZEBRA_SRV6_LOCATOR_ADD: - if (zclient->srv6_locator_add) - (*zclient->srv6_locator_add)(command, zclient, length, - vrf_id); - break; - case ZEBRA_SRV6_LOCATOR_DELETE: - if (zclient->srv6_locator_delete) - (*zclient->srv6_locator_delete)(command, zclient, - length, vrf_id); - break; - case ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK: - if (zclient->process_srv6_locator_chunk) - (*zclient->process_srv6_locator_chunk)(command, zclient, - length, vrf_id); - break; - case ZEBRA_ERROR: - zclient_handle_error(command, zclient, length, vrf_id); - break; - case ZEBRA_OPAQUE_MESSAGE: - if (zclient->opaque_msg_handler) - (*zclient->opaque_msg_handler)(command, zclient, length, - vrf_id); - break; - case ZEBRA_OPAQUE_REGISTER: - if (zclient->opaque_register_handler) - (*zclient->opaque_register_handler)(command, zclient, - length, vrf_id); - break; - case ZEBRA_OPAQUE_UNREGISTER: - if (zclient->opaque_unregister_handler) - (*zclient->opaque_unregister_handler)(command, zclient, - length, vrf_id); - break; - case ZEBRA_SR_POLICY_NOTIFY_STATUS: - if (zclient->sr_policy_notify_status) - (*zclient->sr_policy_notify_status)(command, zclient, - length, vrf_id); - break; - case ZEBRA_CLIENT_CLOSE_NOTIFY: - if (zclient->zebra_client_close_notify) - (*zclient->zebra_client_close_notify)(command, zclient, - length, vrf_id); - break; - case ZEBRA_NHRP_NEIGH_ADDED: - if (zclient->neighbor_added) - (*zclient->neighbor_added)(command, zclient, length, - vrf_id); - break; - case ZEBRA_NHRP_NEIGH_REMOVED: - if (zclient->neighbor_removed) - (*zclient->neighbor_removed)(command, zclient, length, - vrf_id); - break; - case ZEBRA_NHRP_NEIGH_GET: - if (zclient->neighbor_get) - (*zclient->neighbor_get)(command, zclient, length, - vrf_id); - break; - case ZEBRA_GRE_UPDATE: - if (zclient->gre_update) - (*zclient->gre_update)(command, zclient, - length, vrf_id); - break; - default: - break; - } + if (command < array_size(lib_handlers) && lib_handlers[command]) + lib_handlers[command](command, zclient, length, vrf_id); + if (command < zclient->n_handlers && zclient->handlers[command]) + zclient->handlers[command](command, zclient, length, vrf_id); if (zclient->sock < 0) /* Connection was closed during packet processing. */ @@ -4339,11 +4072,12 @@ enum zclient_send_status zclient_interface_set_master(struct zclient *client, s = client->obuf; stream_reset(s); - zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, master->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_SET_MASTER, + master->vrf->vrf_id); - stream_putl(s, master->vrf_id); + stream_putl(s, master->vrf->vrf_id); stream_putl(s, master->ifindex); - stream_putl(s, slave->vrf_id); + stream_putl(s, slave->vrf->vrf_id); stream_putl(s, slave->ifindex); stream_putw_at(s, 0, stream_get_endp(s)); @@ -4430,7 +4164,7 @@ zclient_send_neigh_discovery_req(struct zclient *zclient, s = zclient->obuf; stream_reset(s); - zclient_create_header(s, ZEBRA_NEIGH_DISCOVER, ifp->vrf_id); + zclient_create_header(s, ZEBRA_NEIGH_DISCOVER, ifp->vrf->vrf_id); stream_putl(s, ifp->ifindex); stream_putc(s, p->family); @@ -4520,7 +4254,7 @@ int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in, { int ret = 0; - zclient_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf->vrf_id); stream_putc(s, sockunion_family(in)); stream_write(s, sockunion_get_addr(in), sockunion_get_addrlen(in)); if (out && sockunion_family(out) != AF_UNSPEC) { @@ -4564,9 +4298,7 @@ int zclient_send_zebra_gre_request(struct zclient *client, } s = client->obuf; stream_reset(s); - zclient_create_header(s, - ZEBRA_GRE_GET, - ifp->vrf_id); + zclient_create_header(s, ZEBRA_GRE_GET, ifp->vrf->vrf_id); stream_putl(s, ifp->ifindex); stream_putw_at(s, 0, stream_get_endp(s)); zclient_send_message(client); diff --git a/lib/zclient.h b/lib/zclient.h index f9438d5db7..ca62b1afeb 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -21,6 +21,8 @@ #ifndef _ZEBRA_ZCLIENT_H #define _ZEBRA_ZCLIENT_H +struct zclient; + /* For struct zapi_route. */ #include "prefix.h" #include "ipaddr.h" @@ -126,9 +128,6 @@ typedef enum { ZEBRA_INTERFACE_NBR_ADDRESS_ADD, ZEBRA_INTERFACE_NBR_ADDRESS_DELETE, ZEBRA_INTERFACE_BFD_DEST_UPDATE, - ZEBRA_IMPORT_ROUTE_REGISTER, - ZEBRA_IMPORT_ROUTE_UNREGISTER, - ZEBRA_IMPORT_CHECK_UPDATE, ZEBRA_BFD_DEST_REGISTER, ZEBRA_BFD_DEST_DEREGISTER, ZEBRA_BFD_DEST_UPDATE, @@ -287,12 +286,20 @@ struct zapi_cap { vrf_id_t vrf_id; }; +/* clang-format off */ +#define ZAPI_CALLBACK_ARGS \ + int cmd, struct zclient *zclient, uint16_t length, vrf_id_t vrf_id + +/* function-type typedef (pointer not included) */ +typedef int (zclient_handler)(ZAPI_CALLBACK_ARGS); +/* clang-format on */ + /* Structure for the zebra client. */ struct zclient { /* The thread master we schedule ourselves on */ struct thread_master *master; - /* Priviledges to change socket values */ + /* Privileges to change socket values */ struct zebra_privs_t *privs; /* Do we care about failure events for route install? */ @@ -301,6 +308,9 @@ struct zclient { /* Is this a synchronous client? */ bool synchronous; + /* BFD enabled with bfd_protocol_integration_init() */ + bool bfd_integration; + /* Session id (optional) to support clients with multiple sessions */ uint32_t session_id; @@ -332,16 +342,15 @@ struct zclient { struct redist_proto mi_redist[AFI_MAX][ZEBRA_ROUTE_MAX]; vrf_bitmap_t redist[AFI_MAX][ZEBRA_ROUTE_MAX]; - /* Redistribute defauilt. */ + /* Redistribute default. */ vrf_bitmap_t default_information[AFI_MAX]; -#define ZAPI_CALLBACK_ARGS \ - int cmd, struct zclient *zclient, uint16_t length, vrf_id_t vrf_id - /* Pointer to the callback functions. */ void (*zebra_connected)(struct zclient *); void (*zebra_capabilities)(struct zclient_capabilities *cap); + int (*handle_error)(enum zebra_error_types error); + /* * When the zclient attempts to write the stream data to * it's named pipe to/from zebra, we may have a situation @@ -353,62 +362,15 @@ struct zclient { * more data. */ void (*zebra_buffer_write_ready)(void); - int (*router_id_update)(ZAPI_CALLBACK_ARGS); - int (*interface_address_add)(ZAPI_CALLBACK_ARGS); - int (*interface_address_delete)(ZAPI_CALLBACK_ARGS); - int (*interface_link_params)(ZAPI_CALLBACK_ARGS); - int (*interface_bfd_dest_update)(ZAPI_CALLBACK_ARGS); - int (*interface_nbr_address_add)(ZAPI_CALLBACK_ARGS); - int (*interface_nbr_address_delete)(ZAPI_CALLBACK_ARGS); - int (*interface_vrf_update)(ZAPI_CALLBACK_ARGS); - int (*nexthop_update)(ZAPI_CALLBACK_ARGS); - int (*import_check_update)(ZAPI_CALLBACK_ARGS); - int (*bfd_dest_replay)(ZAPI_CALLBACK_ARGS); - int (*redistribute_route_add)(ZAPI_CALLBACK_ARGS); - int (*redistribute_route_del)(ZAPI_CALLBACK_ARGS); - int (*fec_update)(int, struct zclient *, uint16_t); - int (*local_es_add)(ZAPI_CALLBACK_ARGS); - int (*local_es_del)(ZAPI_CALLBACK_ARGS); - int (*local_es_evi_add)(ZAPI_CALLBACK_ARGS); - int (*local_es_evi_del)(ZAPI_CALLBACK_ARGS); - int (*local_vni_add)(ZAPI_CALLBACK_ARGS); - int (*local_vni_del)(ZAPI_CALLBACK_ARGS); - int (*local_l3vni_add)(ZAPI_CALLBACK_ARGS); - int (*local_l3vni_del)(ZAPI_CALLBACK_ARGS); - void (*local_ip_prefix_add)(ZAPI_CALLBACK_ARGS); - void (*local_ip_prefix_del)(ZAPI_CALLBACK_ARGS); - int (*local_macip_add)(ZAPI_CALLBACK_ARGS); - int (*local_macip_del)(ZAPI_CALLBACK_ARGS); - int (*pw_status_update)(ZAPI_CALLBACK_ARGS); - int (*route_notify_owner)(ZAPI_CALLBACK_ARGS); - int (*rule_notify_owner)(ZAPI_CALLBACK_ARGS); - void (*label_chunk)(ZAPI_CALLBACK_ARGS); - int (*ipset_notify_owner)(ZAPI_CALLBACK_ARGS); - int (*ipset_entry_notify_owner)(ZAPI_CALLBACK_ARGS); - int (*iptable_notify_owner)(ZAPI_CALLBACK_ARGS); - int (*vxlan_sg_add)(ZAPI_CALLBACK_ARGS); - int (*vxlan_sg_del)(ZAPI_CALLBACK_ARGS); - int (*mlag_process_up)(void); - int (*mlag_process_down)(void); - int (*mlag_handle_msg)(struct stream *msg, int len); - int (*nhg_notify_owner)(ZAPI_CALLBACK_ARGS); - int (*srv6_locator_add)(ZAPI_CALLBACK_ARGS); - int (*srv6_locator_delete)(ZAPI_CALLBACK_ARGS); - int (*srv6_function_add)(ZAPI_CALLBACK_ARGS); - int (*srv6_function_delete)(ZAPI_CALLBACK_ARGS); - void (*process_srv6_locator_chunk)(ZAPI_CALLBACK_ARGS); - int (*handle_error)(enum zebra_error_types error); - int (*opaque_msg_handler)(ZAPI_CALLBACK_ARGS); - int (*opaque_register_handler)(ZAPI_CALLBACK_ARGS); - int (*opaque_unregister_handler)(ZAPI_CALLBACK_ARGS); - int (*sr_policy_notify_status)(ZAPI_CALLBACK_ARGS); - int (*zebra_client_close_notify)(ZAPI_CALLBACK_ARGS); - void (*neighbor_added)(ZAPI_CALLBACK_ARGS); - void (*neighbor_removed)(ZAPI_CALLBACK_ARGS); - void (*neighbor_get)(ZAPI_CALLBACK_ARGS); - void (*gre_update)(ZAPI_CALLBACK_ARGS); + + zclient_handler *const *handlers; + size_t n_handlers; }; +/* lib handlers added in bfd.c */ +extern int zclient_bfd_session_replay(ZAPI_CALLBACK_ARGS); +extern int zclient_bfd_session_update(ZAPI_CALLBACK_ARGS); + /* Zebra API message flag. */ #define ZAPI_MESSAGE_NEXTHOP 0x01 #define ZAPI_MESSAGE_DISTANCE 0x02 @@ -897,7 +859,9 @@ int zclient_neigh_ip_encode(struct stream *s, uint16_t cmd, union sockunion *in, extern uint32_t zclient_get_nhg_start(uint32_t proto); extern struct zclient *zclient_new(struct thread_master *m, - struct zclient_options *opt); + struct zclient_options *opt, + zclient_handler *const *handlers, + size_t n_handlers); extern void zclient_init(struct zclient *, int, unsigned short, struct zebra_privs_t *privs); @@ -1107,7 +1071,7 @@ extern enum zclient_send_status zclient_route_send(uint8_t, struct zclient *, struct zapi_route *); extern enum zclient_send_status zclient_send_rnh(struct zclient *zclient, int command, const struct prefix *p, - bool exact_match, vrf_id_t vrf_id); + bool connected, bool resolve_via_default, vrf_id_t vrf_id); int zapi_nexthop_encode(struct stream *s, const struct zapi_nexthop *api_nh, uint32_t api_flags, uint32_t api_message); extern int zapi_route_encode(uint8_t, struct stream *, struct zapi_route *); diff --git a/lib/zebra.h b/lib/zebra.h index 6a02dcb922..c9794352c7 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -383,6 +383,9 @@ typedef uint32_t route_tag_t; #define ROUTE_TAG_MAX UINT32_MAX #define ROUTE_TAG_PRI PRIu32 +/* Name of hook calls */ +#define ZEBRA_ON_RIB_PROCESS_HOOK_CALL "on_rib_process_dplane_results" + #ifdef __cplusplus } #endif diff --git a/lib/zlog.c b/lib/zlog.c index 6fd52cae62..1b0751559d 100644 --- a/lib/zlog.c +++ b/lib/zlog.c @@ -47,12 +47,19 @@ #include <mach/mach_traps.h> #endif +#ifdef HAVE_LIBUNWIND +#define UNW_LOCAL_ONLY +#include <libunwind.h> +#include <dlfcn.h> +#endif + #include "memory.h" #include "atomlist.h" #include "printfrr.h" #include "frrcu.h" #include "zlog.h" #include "libfrr_trace.h" +#include "thread.h" DEFINE_MTYPE_STATIC(LIB, LOG_MESSAGE, "log message"); DEFINE_MTYPE_STATIC(LIB, LOG_TLSBUF, "log thread-local buffer"); @@ -508,6 +515,87 @@ static void vzlog_tls(struct zlog_tls *zlog_tls, const struct xref_logmsg *xref, XFREE(MTYPE_LOG_MESSAGE, msg->text); } +static void zlog_backtrace_msg(const struct xref_logmsg *xref, int prio) +{ + struct thread *tc = pthread_getspecific(thread_current); + const char *uid = xref->xref.xrefdata->uid; + bool found_thread = false; + + zlog(prio, "| (%s) message in thread %jd, at %s(), %s:%d", uid, + zlog_gettid(), xref->xref.func, xref->xref.file, xref->xref.line); + +#ifdef HAVE_LIBUNWIND + const char *threadfunc = tc ? tc->xref->funcname : NULL; + bool found_caller = false; + unw_cursor_t cursor; + unw_context_t uc; + unw_word_t ip, off, sp; + Dl_info dlinfo; + + unw_getcontext(&uc); + + unw_init_local(&cursor, &uc); + while (unw_step(&cursor) > 0) { + char buf[96], name[128] = "?"; + bool is_thread = false; + + unw_get_reg(&cursor, UNW_REG_IP, &ip); + unw_get_reg(&cursor, UNW_REG_SP, &sp); + + if (unw_is_signal_frame(&cursor)) + zlog(prio, "| (%s) ---- signal ----", uid); + + if (!unw_get_proc_name(&cursor, buf, sizeof(buf), &off)) { + if (!strcmp(buf, xref->xref.func)) + found_caller = true; + if (threadfunc && !strcmp(buf, threadfunc)) + found_thread = is_thread = true; + + snprintf(name, sizeof(name), "%s+%#lx", buf, (long)off); + } + + if (!found_caller) + continue; + + if (dladdr((void *)ip, &dlinfo)) + zlog(prio, "| (%s) %-36s %16lx+%08lx %16lx %s", uid, + name, (long)dlinfo.dli_fbase, + (long)ip - (long)dlinfo.dli_fbase, (long)sp, + dlinfo.dli_fname); + else + zlog(prio, "| (%s) %-36s %16lx %16lx", uid, name, + (long)ip, (long)sp); + + if (is_thread) + zlog(prio, "| (%s) ^- scheduled from %s(), %s:%u", uid, + tc->xref->xref.func, tc->xref->xref.file, + tc->xref->xref.line); + } +#elif defined(HAVE_GLIBC_BACKTRACE) + void *frames[64]; + char **names = NULL; + int n_frames, i; + + n_frames = backtrace(frames, array_size(frames)); + if (n_frames < 0) + n_frames = 0; + if (n_frames) + names = backtrace_symbols(frames, n_frames); + + for (i = 0; i < n_frames; i++) { + void *retaddr = frames[i]; + char *loc = names[i]; + + zlog(prio, "| (%s) %16lx %-36s", uid, (long)retaddr, loc); + } + free(names); +#endif + if (!found_thread && tc) + zlog(prio, "| (%s) scheduled from %s(), %s:%u", uid, + tc->xref->xref.func, tc->xref->xref.file, + tc->xref->xref.line); +} + void vzlogx(const struct xref_logmsg *xref, int prio, const char *fmt, va_list ap) { @@ -545,6 +633,15 @@ void vzlogx(const struct xref_logmsg *xref, int prio, vzlog_tls(zlog_tls, xref, prio, fmt, ap); else vzlog_notls(xref, prio, fmt, ap); + + if (xref) { + struct xrefdata_logmsg *xrdl; + + xrdl = container_of(xref->xref.xrefdata, struct xrefdata_logmsg, + xrefdata); + if (xrdl->fl_print_bt) + zlog_backtrace_msg(xref, prio); + } } void zlog_sigsafe(const char *text, size_t len) diff --git a/lib/zlog.h b/lib/zlog.h index d9c8952ac5..6e84fe8923 100644 --- a/lib/zlog.h +++ b/lib/zlog.h @@ -54,10 +54,14 @@ struct xref_logmsg { const char *args; }; +/* whether flag was added in config mode or enable mode */ +#define LOGMSG_FLAG_EPHEMERAL (1 << 0) +#define LOGMSG_FLAG_PERSISTENT (1 << 1) + struct xrefdata_logmsg { struct xrefdata xrefdata; - /* nothing more here right now */ + uint8_t fl_print_bt; }; /* These functions are set up to write to stdout/stderr without explicit @@ -94,15 +98,19 @@ static inline void zlog_ref(const struct xref_logmsg *xref, #define _zlog_ecref(ec_, prio, msg, ...) \ do { \ - static struct xrefdata _xrefdata = { \ - .xref = NULL, \ - .uid = {}, \ - .hashstr = (msg), \ - .hashu32 = {(prio), (ec_)}, \ + static struct xrefdata_logmsg _xrefdata = { \ + .xrefdata = \ + { \ + .xref = NULL, \ + .uid = {}, \ + .hashstr = (msg), \ + .hashu32 = {(prio), (ec_)}, \ + }, \ }; \ static const struct xref_logmsg _xref __attribute__( \ (used)) = { \ - .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata, __func__), \ + .xref = XREF_INIT(XREFT_LOGMSG, &_xrefdata.xrefdata, \ + __func__), \ .fmtstring = (msg), \ .priority = (prio), \ .ec = (ec_), \ diff --git a/nhrpd/list.h b/nhrpd/list.h deleted file mode 100644 index a43687ac08..0000000000 --- a/nhrpd/list.h +++ /dev/null @@ -1,209 +0,0 @@ -/* Linux kernel style list handling function - * - * Written from scratch by Timo Teräs <timo.teras@iki.fi>, but modeled - * after the linux kernel code. - * - * This file is free software: you may copy, redistribute and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - */ - -#ifndef LIST_H -#define LIST_H - -#ifndef NULL -#define NULL 0L -#endif - -#ifndef offsetof -#ifdef __compiler_offsetof -#define offsetof(TYPE,MEMBER) __compiler_offsetof(TYPE,MEMBER) -#else -#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) -#endif -#endif - -#ifndef container_of -#define container_of(ptr, type, member) \ - ({ \ - const typeof(((type *)0)->member) *__mptr = (ptr); \ - (type *)((char *)__mptr - offsetof(type, member)); \ - }) -#endif - -struct hlist_head { - struct hlist_node *first; -}; - -struct hlist_node { - struct hlist_node *next; - struct hlist_node **pprev; -}; - -static inline int hlist_empty(const struct hlist_head *h) -{ - return !h->first; -} - -static inline int hlist_hashed(const struct hlist_node *n) -{ - return n->pprev != NULL; -} - -static inline void hlist_del(struct hlist_node *n) -{ - struct hlist_node *next = n->next; - struct hlist_node **pprev = n->pprev; - - *pprev = next; - if (next) - next->pprev = pprev; - - n->next = NULL; - n->pprev = NULL; -} - -static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h) -{ - struct hlist_node *first = h->first; - - n->next = first; - if (first) - first->pprev = &n->next; - n->pprev = &h->first; - h->first = n; -} - -static inline void hlist_add_after(struct hlist_node *n, - struct hlist_node *prev) -{ - n->next = prev->next; - n->pprev = &prev->next; - prev->next = n; -} - -static inline struct hlist_node **hlist_tail_ptr(struct hlist_head *h) -{ - struct hlist_node *n = h->first; - if (n == NULL) - return &h->first; - while (n->next != NULL) - n = n->next; - return &n->next; -} - -#define hlist_entry(ptr, type, member) container_of(ptr,type,member) - -#define hlist_for_each(pos, head) \ - for (pos = (head)->first; pos; pos = pos->next) - -#define hlist_for_each_safe(pos, n, head) \ - for (pos = (head)->first; pos && ({ \ - n = pos->next; \ - 1; \ - }); \ - pos = n) - -#define hlist_for_each_entry(tpos, pos, head, member) \ - for (pos = (head)->first; \ - pos && ({ \ - tpos = hlist_entry(pos, typeof(*tpos), member); \ - 1; \ - }); \ - pos = pos->next) - -#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \ - for (pos = (head)->first; \ - pos && ({ \ - n = pos->next; \ - 1; \ - }) \ - && ({ \ - tpos = hlist_entry(pos, typeof(*tpos), member); \ - 1; \ - }); \ - pos = n) - - -struct list_head { - struct list_head *next, *prev; -}; - -#define LIST_INITIALIZER(l) { .next = &l, .prev = &l } - -static inline void list_init(struct list_head *list) -{ - list->next = list; - list->prev = list; -} - -static inline void __list_add(struct list_head *new, struct list_head *prev, - struct list_head *next) -{ - next->prev = new; - new->next = next; - new->prev = prev; - prev->next = new; -} - -static inline void list_add(struct list_head *new, struct list_head *head) -{ - __list_add(new, head, head->next); -} - -static inline void list_add_tail(struct list_head *new, struct list_head *head) -{ - __list_add(new, head->prev, head); -} - -static inline void __list_del(struct list_head *prev, struct list_head *next) -{ - next->prev = prev; - prev->next = next; -} - -static inline void list_del(struct list_head *entry) -{ - __list_del(entry->prev, entry->next); - entry->next = NULL; - entry->prev = NULL; -} - -static inline int list_hashed(const struct list_head *n) -{ - return n->next != n && n->next != NULL; -} - -static inline int list_empty(const struct list_head *n) -{ - return !list_hashed(n); -} - -#define list_next(ptr, type, member) \ - (list_hashed(ptr) ? container_of((ptr)->next, type, member) : NULL) - -#define list_entry(ptr, type, member) container_of(ptr,type,member) - -#define list_for_each(pos, head) \ - for (pos = (head)->next; pos != (head); pos = pos->next) - -#define list_for_each_safe(pos, n, head) \ - for (pos = (head)->next, n = pos->next; pos != (head); \ - pos = n, n = pos->next) - -#define list_for_each_entry(pos, head, member) \ - for (pos = list_entry((head)->next, typeof(*pos), member); \ - &pos->member != (head); \ - pos = list_entry(pos->member.next, typeof(*pos), member)) - -#define list_for_each_entry_safe(pos, n, head, member) \ - for (pos = ((head)->next != head ? \ - list_entry((head)->next, typeof(*pos), member) : \ - NULL), \ - n = (pos ? \ - list_entry(pos->member.next, typeof(*pos), member) : NULL); \ - pos && (&pos->member != (head)); \ - pos = n, n = list_entry(n->member.next, typeof(*n), member)) - -#endif diff --git a/nhrpd/netlink_arp.c b/nhrpd/netlink_arp.c index 0a618056d5..3658cb16bb 100644 --- a/nhrpd/netlink_arp.c +++ b/nhrpd/netlink_arp.c @@ -147,7 +147,7 @@ void netlink_set_nflog_group(int nlgroup) } } -void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) +int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) { union sockunion addr = {}, lladdr = {}; struct interface *ifp; @@ -157,7 +157,7 @@ void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) zclient_neigh_ip_decode(zclient->ibuf, &api); if (api.ip_in.ipa_type == AF_UNSPEC) - return; + return 0; sockunion_family(&addr) = api.ip_in.ipa_type; memcpy((uint8_t *)sockunion_get_addr(&addr), &api.ip_in.ip.addr, family2addrsize(api.ip_in.ipa_type)); @@ -172,10 +172,10 @@ void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) ndm_state = api.ndm_state; if (!ifp) - return; + return 0; c = nhrp_cache_get(ifp, &addr, 0); if (!c) - return; + return 0; debugf(NHRP_DEBUG_KERNEL, "Netlink: %s %pSU dev %s lladdr %pSU nud 0x%x cache used %u type %u", (cmd == ZEBRA_NHRP_NEIGH_GET) @@ -200,4 +200,5 @@ void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS) : ZEBRA_NEIGH_STATE_FAILED; nhrp_cache_set_used(c, state == ZEBRA_NEIGH_STATE_REACHABLE); } + return 0; } diff --git a/nhrpd/nhrp_cache.c b/nhrpd/nhrp_cache.c index c358baecb2..3823464a73 100644 --- a/nhrpd/nhrp_cache.c +++ b/nhrpd/nhrp_cache.c @@ -315,7 +315,7 @@ static void nhrp_cache_peer_notifier(struct notifier_block *n, static void nhrp_cache_reset_new(struct nhrp_cache *c) { THREAD_OFF(c->t_auth); - if (list_hashed(&c->newpeer_notifier.notifier_entry)) + if (notifier_list_anywhere(&c->newpeer_notifier)) nhrp_peer_notify_del(c->new.peer, &c->newpeer_notifier); nhrp_peer_unref(c->new.peer); memset(&c->new, 0, sizeof(c->new)); @@ -574,5 +574,5 @@ void nhrp_cache_notify_add(struct nhrp_cache *c, struct notifier_block *n, void nhrp_cache_notify_del(struct nhrp_cache *c, struct notifier_block *n) { - notifier_del(n); + notifier_del(n, &c->notifier_list); } diff --git a/nhrpd/nhrp_interface.c b/nhrpd/nhrp_interface.c index 2db8997bad..1092ce13a1 100644 --- a/nhrpd/nhrp_interface.c +++ b/nhrpd/nhrp_interface.c @@ -79,8 +79,8 @@ static int nhrp_if_new_hook(struct interface *ifp) for (afi = 0; afi < AFI_MAX; afi++) { struct nhrp_afi_data *ad = &nifp->afi[afi]; ad->holdtime = NHRPD_DEFAULT_HOLDTIME; - list_init(&ad->nhslist_head); - list_init(&ad->mcastlist_head); + nhrp_nhslist_init(&ad->nhslist_head); + nhrp_mcastlist_init(&ad->mcastlist_head); } return 0; @@ -143,13 +143,13 @@ static void nhrp_interface_update_source(struct interface *ifp) { struct nhrp_interface *nifp = ifp->info; - if (!nifp->source || !nifp->nbmaifp || - ((ifindex_t)nifp->link_idx == nifp->nbmaifp->ifindex && - (nifp->link_vrf_id == nifp->nbmaifp->vrf_id))) + if (!nifp->source || !nifp->nbmaifp + || ((ifindex_t)nifp->link_idx == nifp->nbmaifp->ifindex + && (nifp->link_vrf_id == nifp->nbmaifp->vrf->vrf_id))) return; nifp->link_idx = nifp->nbmaifp->ifindex; - nifp->link_vrf_id = nifp->nbmaifp->vrf_id; + nifp->link_vrf_id = nifp->nbmaifp->vrf->vrf_id; debugf(NHRP_DEBUG_IF, "%s: bound device index changed to %d, vr %u", ifp->name, nifp->link_idx, nifp->link_vrf_id); nhrp_send_zebra_gre_source_set(ifp, nifp->link_idx, nifp->link_vrf_id); @@ -224,8 +224,12 @@ void nhrp_interface_update_nbma(struct interface *ifp, nbmanifp = nbmaifp->info; if (nbmaifp != nifp->nbmaifp) { - if (nifp->nbmaifp) - notifier_del(&nifp->nbmanifp_notifier); + if (nifp->nbmaifp) { + struct nhrp_interface *prev_nifp = nifp->nbmaifp->info; + + notifier_del(&nifp->nbmanifp_notifier, + &prev_nifp->notifier_list); + } nifp->nbmaifp = nbmaifp; if (nbmaifp) { notifier_add(&nifp->nbmanifp_notifier, @@ -410,7 +414,7 @@ static void interface_config_update_nhrp_map(struct nhrp_cache_config *cc, return; /* gre layer not ready */ - if (ifp->vrf_id == VRF_UNKNOWN) + if (ifp->vrf->vrf_id == VRF_UNKNOWN) return; c = nhrp_cache_get(ifp, &cc->remote_addr, ctx->enabled ? 1 : 0); @@ -509,12 +513,15 @@ void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn) { struct nhrp_interface *nifp = ifp->info; + notifier_add(n, &nifp->notifier_list, fn); } void nhrp_interface_notify_del(struct interface *ifp, struct notifier_block *n) { - notifier_del(n); + struct nhrp_interface *nifp = ifp->info; + + notifier_del(n, &nifp->notifier_list); } void nhrp_interface_set_protection(struct interface *ifp, const char *profile, diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index 73684046a8..d8f14a3fc0 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -55,8 +55,10 @@ struct zebra_privs_t nhrpd_privs = { #endif .caps_p = _caps_p, .cap_num_p = array_size(_caps_p), + .cap_num_i = 0 }; + static void parse_arguments(int argc, char **argv) { int opt; @@ -99,7 +101,7 @@ static void nhrp_request_stop(void) exit(0); } -static struct quagga_signal_t sighandlers[] = { +static struct frr_signal_t sighandlers[] = { { .signal = SIGUSR1, .handler = &nhrp_sigusr1, diff --git a/nhrpd/nhrp_multicast.c b/nhrpd/nhrp_multicast.c index 339b6dfabe..d8372ae8a8 100644 --- a/nhrpd/nhrp_multicast.c +++ b/nhrpd/nhrp_multicast.c @@ -219,7 +219,9 @@ void netlink_mcast_set_nflog_group(int nlgroup) static int nhrp_multicast_free(struct interface *ifp, struct nhrp_multicast *mcast) { - list_del(&mcast->list_entry); + struct nhrp_interface *nifp = ifp->info; + + nhrp_mcastlist_del(&nifp->afi[mcast->afi].mcastlist_head, mcast); XFREE(MTYPE_NHRP_MULTICAST, mcast); return 0; } @@ -230,8 +232,7 @@ int nhrp_multicast_add(struct interface *ifp, afi_t afi, struct nhrp_interface *nifp = ifp->info; struct nhrp_multicast *mcast; - list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry) - { + frr_each (nhrp_mcastlist, &nifp->afi[afi].mcastlist_head, mcast) { if (sockunion_same(&mcast->nbma_addr, nbma_addr)) return NHRP_ERR_ENTRY_EXISTS; } @@ -241,7 +242,7 @@ int nhrp_multicast_add(struct interface *ifp, afi_t afi, *mcast = (struct nhrp_multicast){ .afi = afi, .ifp = ifp, .nbma_addr = *nbma_addr, }; - list_add_tail(&mcast->list_entry, &nifp->afi[afi].mcastlist_head); + nhrp_mcastlist_add_tail(&nifp->afi[afi].mcastlist_head, mcast); debugf(NHRP_DEBUG_COMMON, "Adding multicast entry (%pSU)", nbma_addr); @@ -252,11 +253,9 @@ int nhrp_multicast_del(struct interface *ifp, afi_t afi, union sockunion *nbma_addr) { struct nhrp_interface *nifp = ifp->info; - struct nhrp_multicast *mcast, *tmp; + struct nhrp_multicast *mcast; - list_for_each_entry_safe(mcast, tmp, &nifp->afi[afi].mcastlist_head, - list_entry) - { + frr_each_safe (nhrp_mcastlist, &nifp->afi[afi].mcastlist_head, mcast) { if (!sockunion_same(&mcast->nbma_addr, nbma_addr)) continue; @@ -274,17 +273,15 @@ int nhrp_multicast_del(struct interface *ifp, afi_t afi, void nhrp_multicast_interface_del(struct interface *ifp) { struct nhrp_interface *nifp = ifp->info; - struct nhrp_multicast *mcast, *tmp; + struct nhrp_multicast *mcast; afi_t afi; for (afi = 0; afi < AFI_MAX; afi++) { - debugf(NHRP_DEBUG_COMMON, - "Cleaning up multicast entries (%d)", - !list_empty(&nifp->afi[afi].mcastlist_head)); + debugf(NHRP_DEBUG_COMMON, "Cleaning up multicast entries (%zu)", + nhrp_mcastlist_count(&nifp->afi[afi].mcastlist_head)); - list_for_each_entry_safe( - mcast, tmp, &nifp->afi[afi].mcastlist_head, list_entry) - { + frr_each_safe (nhrp_mcastlist, &nifp->afi[afi].mcastlist_head, + mcast) { nhrp_multicast_free(ifp, mcast); } } @@ -297,8 +294,7 @@ void nhrp_multicast_foreach(struct interface *ifp, afi_t afi, struct nhrp_interface *nifp = ifp->info; struct nhrp_multicast *mcast; - list_for_each_entry(mcast, &nifp->afi[afi].mcastlist_head, list_entry) - { + frr_each (nhrp_mcastlist, &nifp->afi[afi].mcastlist_head, mcast) { cb(mcast, ctx); } } diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index 5179f15ebf..3733910a63 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -254,7 +254,7 @@ static void nhrp_reg_delete(struct nhrp_registration *r) { nhrp_peer_notify_del(r->peer, &r->peer_notifier); nhrp_peer_unref(r->peer); - list_del(&r->reglist_entry); + nhrp_reglist_del(&r->nhs->reglist_head, r); THREAD_OFF(r->t_register); XFREE(MTYPE_NHRP_REGISTRATION, r); } @@ -264,10 +264,9 @@ nhrp_reg_by_nbma(struct nhrp_nhs *nhs, const union sockunion *nbma_addr) { struct nhrp_registration *r; - list_for_each_entry( - r, &nhs->reglist_head, - reglist_entry) if (sockunion_same(&r->peer->vc->remote.nbma, - nbma_addr)) return r; + frr_each (nhrp_reglist, &nhs->reglist_head, r) + if (sockunion_same(&r->peer->vc->remote.nbma, nbma_addr)) + return r; return NULL; } @@ -276,7 +275,7 @@ static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr, { struct nhrp_nhs *nhs = container_of(q, struct nhrp_nhs, dns_resolve); struct nhrp_interface *nifp = nhs->ifp->info; - struct nhrp_registration *reg, *regn; + struct nhrp_registration *reg; int i; if (n < 0) { @@ -289,8 +288,8 @@ static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr, thread_add_timer(master, nhrp_nhs_resolve, nhs, 2 * 60 * 60, &nhs->t_resolve); - list_for_each_entry(reg, &nhs->reglist_head, reglist_entry) reg->mark = - 1; + frr_each (nhrp_reglist, &nhs->reglist_head, reg) + reg->mark = 1; nhs->hub = 0; for (i = 0; i < n; i++) { @@ -309,27 +308,24 @@ static void nhrp_nhs_resolve_cb(struct resolver_query *q, const char *errstr, reg->peer = nhrp_peer_get(nhs->ifp, &addrs[i]); reg->nhs = nhs; reg->timeout = 1; - list_init(®->reglist_entry); - list_add_tail(®->reglist_entry, &nhs->reglist_head); + nhrp_reglist_add_tail(&nhs->reglist_head, reg); nhrp_peer_notify_add(reg->peer, ®->peer_notifier, nhrp_reg_peer_notify); thread_add_timer_msec(master, nhrp_reg_send_req, reg, 50, ®->t_register); } - list_for_each_entry_safe(reg, regn, &nhs->reglist_head, reglist_entry) - { + frr_each_safe (nhrp_reglist, &nhs->reglist_head, reg) if (reg->mark) nhrp_reg_delete(reg); - } } static int nhrp_nhs_resolve(struct thread *t) { struct nhrp_nhs *nhs = THREAD_ARG(t); - resolver_resolve(&nhs->dns_resolve, AF_INET, nhs->nbma_fqdn, - nhrp_nhs_resolve_cb); + resolver_resolve(&nhs->dns_resolve, AF_INET, VRF_DEFAULT, + nhs->nbma_fqdn, nhrp_nhs_resolve_cb); return 0; } @@ -344,8 +340,7 @@ int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, && sockunion_family(proto_addr) != afi2family(afi)) return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH; - list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry) - { + frr_each (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) { if (sockunion_family(&nhs->proto_addr) != AF_UNSPEC && sockunion_family(proto_addr) != AF_UNSPEC && sockunion_same(&nhs->proto_addr, proto_addr)) @@ -362,9 +357,9 @@ int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, .ifp = ifp, .proto_addr = *proto_addr, .nbma_fqdn = strdup(nbma_fqdn), - .reglist_head = LIST_INITIALIZER(nhs->reglist_head), + .reglist_head = INIT_DLIST(nhs->reglist_head), }; - list_add_tail(&nhs->nhslist_entry, &nifp->afi[afi].nhslist_head); + nhrp_nhslist_add_tail(&nifp->afi[afi].nhslist_head, nhs); thread_add_timer_msec(master, nhrp_nhs_resolve, nhs, 1000, &nhs->t_resolve); @@ -375,36 +370,34 @@ int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn) { struct nhrp_interface *nifp = ifp->info; - struct nhrp_nhs *nhs, *nnhs; + struct nhrp_nhs *nhs; int ret = NHRP_ERR_ENTRY_NOT_FOUND; if (sockunion_family(proto_addr) != AF_UNSPEC && sockunion_family(proto_addr) != afi2family(afi)) return NHRP_ERR_PROTOCOL_ADDRESS_MISMATCH; - list_for_each_entry_safe(nhs, nnhs, &nifp->afi[afi].nhslist_head, - nhslist_entry) - { + frr_each_safe (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) { if (!sockunion_same(&nhs->proto_addr, proto_addr)) continue; if (strcmp(nhs->nbma_fqdn, nbma_fqdn) != 0) continue; - nhrp_nhs_free(nhs); + nhrp_nhs_free(nifp, afi, nhs); ret = NHRP_OK; } return ret; } -int nhrp_nhs_free(struct nhrp_nhs *nhs) +int nhrp_nhs_free(struct nhrp_interface *nifp, afi_t afi, struct nhrp_nhs *nhs) { - struct nhrp_registration *r, *rn; + struct nhrp_registration *r; - list_for_each_entry_safe(r, rn, &nhs->reglist_head, reglist_entry) + frr_each_safe (nhrp_reglist, &nhs->reglist_head, r) nhrp_reg_delete(r); THREAD_OFF(nhs->t_resolve); - list_del(&nhs->nhslist_entry); + nhrp_nhslist_del(&nifp->afi[afi].nhslist_head, nhs); free((void *)nhs->nbma_fqdn); XFREE(MTYPE_NHRP_NHS, nhs); return 0; @@ -413,18 +406,15 @@ int nhrp_nhs_free(struct nhrp_nhs *nhs) void nhrp_nhs_interface_del(struct interface *ifp) { struct nhrp_interface *nifp = ifp->info; - struct nhrp_nhs *nhs, *tmp; + struct nhrp_nhs *nhs; afi_t afi; for (afi = 0; afi < AFI_MAX; afi++) { - debugf(NHRP_DEBUG_COMMON, "Cleaning up nhs entries (%d)", - !list_empty(&nifp->afi[afi].nhslist_head)); + debugf(NHRP_DEBUG_COMMON, "Cleaning up nhs entries (%zu)", + nhrp_nhslist_count(&nifp->afi[afi].nhslist_head)); - list_for_each_entry_safe(nhs, tmp, &nifp->afi[afi].nhslist_head, - nhslist_entry) - { - nhrp_nhs_free(nhs); - } + frr_each_safe (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) + nhrp_nhs_free(nifp, afi, nhs); } } @@ -433,15 +423,15 @@ void nhrp_nhs_terminate(void) struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); struct interface *ifp; struct nhrp_interface *nifp; - struct nhrp_nhs *nhs, *tmp; + struct nhrp_nhs *nhs; afi_t afi; FOR_ALL_INTERFACES (vrf, ifp) { nifp = ifp->info; for (afi = 0; afi < AFI_MAX; afi++) { - list_for_each_entry_safe( - nhs, tmp, &nifp->afi[afi].nhslist_head, - nhslist_entry) nhrp_nhs_free(nhs); + frr_each_safe (nhrp_nhslist, + &nifp->afi[afi].nhslist_head, nhs) + nhrp_nhs_free(nifp, afi, nhs); } } } @@ -455,11 +445,10 @@ void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, struct nhrp_nhs *nhs; struct nhrp_registration *reg; - list_for_each_entry(nhs, &nifp->afi[afi].nhslist_head, nhslist_entry) - { - if (!list_empty(&nhs->reglist_head)) { - list_for_each_entry(reg, &nhs->reglist_head, - reglist_entry) cb(nhs, reg, ctx); + frr_each (nhrp_nhslist, &nifp->afi[afi].nhslist_head, nhs) { + if (nhrp_reglist_count(&nhs->reglist_head)) { + frr_each (nhrp_reglist, &nhs->reglist_head, reg) + cb(nhs, reg, ctx); } else cb(nhs, 0, ctx); } @@ -472,19 +461,14 @@ int nhrp_nhs_match_ip(union sockunion *in_ip, struct nhrp_interface *nifp) struct nhrp_registration *reg; for (i = 0; i < AFI_MAX; i++) { - list_for_each_entry(nhs, &nifp->afi[i].nhslist_head, - nhslist_entry) - { - if (!list_empty(&nhs->reglist_head)) { - list_for_each_entry(reg, &nhs->reglist_head, - reglist_entry) - { - if (!sockunion_cmp( - in_ip, - ®->peer->vc->remote - .nbma)) - return 1; - } + frr_each (nhrp_nhslist, &nifp->afi[i].nhslist_head, nhs) { + if (!nhrp_reglist_count(&nhs->reglist_head)) + continue; + + frr_each (nhrp_reglist, &nhs->reglist_head, reg) { + if (!sockunion_cmp(in_ip, + ®->peer->vc->remote.nbma)) + return 1; } } } diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index 030f4c0ff3..51cae44bd1 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -359,7 +359,7 @@ void nhrp_peer_notify_add(struct nhrp_peer *p, struct notifier_block *n, void nhrp_peer_notify_del(struct nhrp_peer *p, struct notifier_block *n) { - notifier_del(n); + notifier_del(n, &p->notifier_list); nhrp_peer_check_delete(p); } diff --git a/nhrpd/nhrp_route.c b/nhrpd/nhrp_route.c index 12a2fc2fa0..698c6d0cdf 100644 --- a/nhrpd/nhrp_route.c +++ b/nhrpd/nhrp_route.c @@ -366,21 +366,25 @@ static void nhrp_zebra_connected(struct zclient *zclient) nhrp_zebra_register_neigh(VRF_DEFAULT, AFI_IP6, true); } +static zclient_handler *const nhrp_handlers[] = { + [ZEBRA_INTERFACE_ADDRESS_ADD] = nhrp_interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = nhrp_interface_address_delete, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = nhrp_route_read, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = nhrp_route_read, + [ZEBRA_NHRP_NEIGH_ADDED] = nhrp_neighbor_operation, + [ZEBRA_NHRP_NEIGH_REMOVED] = nhrp_neighbor_operation, + [ZEBRA_NHRP_NEIGH_GET] = nhrp_neighbor_operation, + [ZEBRA_GRE_UPDATE] = nhrp_gre_update, +}; + void nhrp_zebra_init(void) { zebra_rib[AFI_IP] = route_table_init(); zebra_rib[AFI_IP6] = route_table_init(); - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, nhrp_handlers, + array_size(nhrp_handlers)); zclient->zebra_connected = nhrp_zebra_connected; - zclient->interface_address_add = nhrp_interface_address_add; - zclient->interface_address_delete = nhrp_interface_address_delete; - zclient->redistribute_route_add = nhrp_route_read; - zclient->redistribute_route_del = nhrp_route_read; - zclient->neighbor_added = nhrp_neighbor_operation; - zclient->neighbor_removed = nhrp_neighbor_operation; - zclient->neighbor_get = nhrp_neighbor_operation; - zclient->gre_update = nhrp_gre_update; zclient_init(zclient, ZEBRA_ROUTE_NHRP, 0, &nhrpd_privs); } @@ -404,9 +408,7 @@ void nhrp_send_zebra_configure_arp(struct interface *ifp, int family) } s = zclient->obuf; stream_reset(s); - zclient_create_header(s, - ZEBRA_CONFIGURE_ARP, - ifp->vrf_id); + zclient_create_header(s, ZEBRA_CONFIGURE_ARP, ifp->vrf->vrf_id); stream_putc(s, family); stream_putl(s, ifp->ifindex); stream_putw_at(s, 0, stream_get_endp(s)); @@ -429,9 +431,7 @@ void nhrp_send_zebra_gre_source_set(struct interface *ifp, } s = zclient->obuf; stream_reset(s); - zclient_create_header(s, - ZEBRA_GRE_SOURCE_SET, - ifp->vrf_id); + zclient_create_header(s, ZEBRA_GRE_SOURCE_SET, ifp->vrf->vrf_id); stream_putl(s, ifp->ifindex); stream_putl(s, link_idx); stream_putl(s, link_vrf_id); @@ -476,7 +476,7 @@ void nhrp_zebra_terminate(void) route_table_finish(zebra_rib[AFI_IP6]); } -void nhrp_gre_update(ZAPI_CALLBACK_ARGS) +int nhrp_gre_update(ZAPI_CALLBACK_ARGS) { struct stream *s; struct nhrp_gre_info gre_info, *val; @@ -485,7 +485,7 @@ void nhrp_gre_update(ZAPI_CALLBACK_ARGS) /* result */ s = zclient->ibuf; if (vrf_id != VRF_DEFAULT) - return; + return 0; /* read GRE information */ STREAM_GETL(s, gre_info.ifindex); @@ -516,7 +516,9 @@ void nhrp_gre_update(ZAPI_CALLBACK_ARGS) ifp ? ifp->name : "<none>", gre_info.ifindex, vrf_id); if (ifp) nhrp_interface_update_nbma(ifp, val); - return; + return 0; + stream_failure: zlog_err("%s(): error reading response ..", __func__); + return -1; } diff --git a/nhrpd/nhrp_vc.c b/nhrpd/nhrp_vc.c index b3b657f3fa..4b45389dad 100644 --- a/nhrpd/nhrp_vc.c +++ b/nhrpd/nhrp_vc.c @@ -19,14 +19,18 @@ DEFINE_MTYPE_STATIC(NHRPD, NHRP_VC, "NHRP virtual connection"); +PREDECL_DLIST(childlist); + struct child_sa { uint32_t id; struct nhrp_vc *vc; - struct list_head childlist_entry; + struct childlist_item childlist_entry; }; +DECLARE_DLIST(childlist, struct child_sa, childlist_entry); + static struct hash *nhrp_vc_hash; -static struct list_head childlist_head[512]; +static struct childlist_head childlist_head[512]; static unsigned int nhrp_vc_key(const void *peer_data) { @@ -104,8 +108,7 @@ int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc) uint32_t child_hash = child_id % array_size(childlist_head); int abort_migration = 0; - list_for_each_entry(lsa, &childlist_head[child_hash], childlist_entry) - { + frr_each (childlist, &childlist_head[child_hash], lsa) { if (lsa->id == child_id) { sa = lsa; break; @@ -120,12 +123,9 @@ int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc) *sa = (struct child_sa){ .id = child_id, - .childlist_entry = - LIST_INITIALIZER(sa->childlist_entry), .vc = NULL, }; - list_add_tail(&sa->childlist_entry, - &childlist_head[child_hash]); + childlist_add_tail(&childlist_head[child_hash], sa); } if (sa->vc == vc) @@ -155,7 +155,7 @@ int nhrp_vc_ipsec_updown(uint32_t child_id, struct nhrp_vc *vc) /* Update */ sa->vc = vc; if (!vc) { - list_del(&sa->childlist_entry); + childlist_del(&childlist_head[child_hash], sa); XFREE(MTYPE_NHRP_VC, sa); } @@ -170,7 +170,7 @@ void nhrp_vc_notify_add(struct nhrp_vc *vc, struct notifier_block *n, void nhrp_vc_notify_del(struct nhrp_vc *vc, struct notifier_block *n) { - notifier_del(n); + notifier_del(n, &vc->notifier_list); nhrp_vc_check_delete(vc); } @@ -200,17 +200,16 @@ void nhrp_vc_init(void) nhrp_vc_hash = hash_create(nhrp_vc_key, nhrp_vc_cmp, "NHRP VC hash"); for (i = 0; i < array_size(childlist_head); i++) - list_init(&childlist_head[i]); + childlist_init(&childlist_head[i]); } void nhrp_vc_reset(void) { - struct child_sa *sa, *n; + struct child_sa *sa; size_t i; for (i = 0; i < array_size(childlist_head); i++) { - list_for_each_entry_safe(sa, n, &childlist_head[i], - childlist_entry) + frr_each_safe (childlist, &childlist_head[i], sa) nhrp_vc_ipsec_updown(sa->id, 0); } } diff --git a/nhrpd/nhrp_vty.c b/nhrpd/nhrp_vty.c index 50161dae2f..0dfabcf6ae 100644 --- a/nhrpd/nhrp_vty.c +++ b/nhrpd/nhrp_vty.c @@ -1200,9 +1200,7 @@ static int interface_config_write(struct vty *vty) nhrp_cache_config_foreach( ifp, interface_config_write_nhrp_map, &mapctx); - list_for_each_entry(nhs, &ad->nhslist_head, - nhslist_entry) - { + frr_each (nhrp_nhslist, &ad->nhslist_head, nhs) { vty_out(vty, " %s nhrp nhs ", aficmd); if (sockunion_family(&nhs->proto_addr) == AF_UNSPEC) @@ -1212,9 +1210,7 @@ static int interface_config_write(struct vty *vty) vty_out(vty, " nbma %s\n", nhs->nbma_fqdn); } - list_for_each_entry(mcast, &ad->mcastlist_head, - list_entry) - { + frr_each (nhrp_mcastlist, &ad->mcastlist_head, mcast) { vty_out(vty, " %s nhrp map multicast ", aficmd); if (sockunion_family(&mcast->nbma_addr) == AF_UNSPEC) diff --git a/nhrpd/nhrpd.h b/nhrpd/nhrpd.h index 17abb04762..753c6e9b22 100644 --- a/nhrpd/nhrpd.h +++ b/nhrpd/nhrpd.h @@ -10,8 +10,6 @@ #ifndef NHRPD_H #define NHRPD_H -#include "list.h" - #include "zbuf.h" #include "zclient.h" #include "debug.h" @@ -42,48 +40,53 @@ struct notifier_block; typedef void (*notifier_fn_t)(struct notifier_block *, unsigned long); +PREDECL_DLIST(notifier_list); + struct notifier_block { - struct list_head notifier_entry; + struct notifier_list_item notifier_entry; notifier_fn_t action; }; +DECLARE_DLIST(notifier_list, struct notifier_block, notifier_entry); + struct notifier_list { - struct list_head notifier_head; + struct notifier_list_head head; }; #define NOTIFIER_LIST_INITIALIZER(l) \ { \ - .notifier_head = LIST_INITIALIZER((l)->notifier_head) \ + .head = INIT_DLIST((l)->head) \ } static inline void notifier_init(struct notifier_list *l) { - list_init(&l->notifier_head); + notifier_list_init(&l->head); } static inline void notifier_add(struct notifier_block *n, struct notifier_list *l, notifier_fn_t action) { n->action = action; - list_add_tail(&n->notifier_entry, &l->notifier_head); + notifier_list_add_tail(&l->head, n); } -static inline void notifier_del(struct notifier_block *n) +static inline void notifier_del(struct notifier_block *n, + struct notifier_list *l) { - list_del(&n->notifier_entry); + notifier_list_del(&l->head, n); } static inline void notifier_call(struct notifier_list *l, int cmd) { - struct notifier_block *n, *nn; - list_for_each_entry_safe(n, nn, &l->notifier_head, notifier_entry) { + struct notifier_block *n; + + frr_each_safe (notifier_list, &l->head, n) n->action(n, cmd); - } } static inline int notifier_active(struct notifier_list *l) { - return !list_empty(&l->notifier_head); + return notifier_list_count(&l->head) > 0; } extern struct hash *nhrp_gre_list; @@ -263,9 +266,13 @@ struct nhrp_shortcut { struct notifier_block cache_notifier; }; +PREDECL_DLIST(nhrp_nhslist); +PREDECL_DLIST(nhrp_mcastlist); +PREDECL_DLIST(nhrp_reglist); + struct nhrp_nhs { struct interface *ifp; - struct list_head nhslist_entry; + struct nhrp_nhslist_item nhslist_entry; unsigned hub : 1; afi_t afi; @@ -274,18 +281,22 @@ struct nhrp_nhs { struct thread *t_resolve; struct resolver_query dns_resolve; - struct list_head reglist_head; + struct nhrp_reglist_head reglist_head; }; +DECLARE_DLIST(nhrp_nhslist, struct nhrp_nhs, nhslist_entry); + struct nhrp_multicast { struct interface *ifp; - struct list_head list_entry; + struct nhrp_mcastlist_item mcastlist_entry; afi_t afi; union sockunion nbma_addr; /* IP-address */ }; +DECLARE_DLIST(nhrp_mcastlist, struct nhrp_multicast, mcastlist_entry); + struct nhrp_registration { - struct list_head reglist_entry; + struct nhrp_reglist_item reglist_entry; struct thread *t_register; struct nhrp_nhs *nhs; struct nhrp_reqid reqid; @@ -296,6 +307,8 @@ struct nhrp_registration { struct notifier_block peer_notifier; }; +DECLARE_DLIST(nhrp_reglist, struct nhrp_registration, reglist_entry); + #define NHRP_IFF_SHORTCUT 0x0001 #define NHRP_IFF_REDIRECT 0x0002 #define NHRP_IFF_REG_NO_UNIQUE 0x0100 @@ -330,8 +343,8 @@ struct nhrp_interface { short configured_mtu; unsigned short mtu; unsigned int holdtime; - struct list_head nhslist_head; - struct list_head mcastlist_head; + struct nhrp_nhslist_head nhslist_head; + struct nhrp_mcastlist_head mcastlist_head; } afi[AFI_MAX]; }; @@ -363,8 +376,8 @@ int nhrp_interface_up(ZAPI_CALLBACK_ARGS); int nhrp_interface_down(ZAPI_CALLBACK_ARGS); int nhrp_interface_address_add(ZAPI_CALLBACK_ARGS); int nhrp_interface_address_delete(ZAPI_CALLBACK_ARGS); -void nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS); -void nhrp_gre_update(ZAPI_CALLBACK_ARGS); +int nhrp_neighbor_operation(ZAPI_CALLBACK_ARGS); +int nhrp_gre_update(ZAPI_CALLBACK_ARGS); void nhrp_interface_notify_add(struct interface *ifp, struct notifier_block *n, notifier_fn_t fn); @@ -381,7 +394,7 @@ int nhrp_nhs_add(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn); int nhrp_nhs_del(struct interface *ifp, afi_t afi, union sockunion *proto_addr, const char *nbma_fqdn); -int nhrp_nhs_free(struct nhrp_nhs *nhs); +int nhrp_nhs_free(struct nhrp_interface *nifp, afi_t afi, struct nhrp_nhs *nhs); void nhrp_nhs_terminate(void); void nhrp_nhs_foreach(struct interface *ifp, afi_t afi, void (*cb)(struct nhrp_nhs *, struct nhrp_registration *, diff --git a/nhrpd/subdir.am b/nhrpd/subdir.am index 9a186d6ed8..dc0c162c83 100644 --- a/nhrpd/subdir.am +++ b/nhrpd/subdir.am @@ -34,7 +34,6 @@ nhrpd_nhrpd_SOURCES = \ noinst_HEADERS += \ nhrpd/debug.h \ - nhrpd/list.h \ nhrpd/netlink.h \ nhrpd/nhrp_errors.h \ nhrpd/nhrp_protocol.h \ diff --git a/nhrpd/zbuf.c b/nhrpd/zbuf.c index e191a90f2d..9cc2b56245 100644 --- a/nhrpd/zbuf.c +++ b/nhrpd/zbuf.c @@ -164,35 +164,33 @@ void *zbuf_may_pull_until(struct zbuf *zb, const char *sep, struct zbuf *msg) void zbufq_init(struct zbuf_queue *zbq) { *zbq = (struct zbuf_queue){ - .queue_head = LIST_INITIALIZER(zbq->queue_head), + .queue_head = INIT_DLIST(zbq->queue_head), }; } void zbufq_reset(struct zbuf_queue *zbq) { - struct zbuf *buf, *bufn; + struct zbuf *buf; - list_for_each_entry_safe(buf, bufn, &zbq->queue_head, queue_list) - { - list_del(&buf->queue_list); + frr_each_safe (zbuf_queue, &zbq->queue_head, buf) { + zbuf_queue_del(&zbq->queue_head, buf); zbuf_free(buf); } } void zbufq_queue(struct zbuf_queue *zbq, struct zbuf *zb) { - list_add_tail(&zb->queue_list, &zbq->queue_head); + zbuf_queue_add_tail(&zbq->queue_head, zb); } int zbufq_write(struct zbuf_queue *zbq, int fd) { struct iovec iov[16]; - struct zbuf *zb, *zbn; + struct zbuf *zb; ssize_t r; size_t iovcnt = 0; - list_for_each_entry_safe(zb, zbn, &zbq->queue_head, queue_list) - { + frr_each_safe (zbuf_queue, &zbq->queue_head, zb) { iov[iovcnt++] = (struct iovec){ .iov_base = zb->head, .iov_len = zbuf_used(zb), }; @@ -204,15 +202,14 @@ int zbufq_write(struct zbuf_queue *zbq, int fd) if (r < 0) return r; - list_for_each_entry_safe(zb, zbn, &zbq->queue_head, queue_list) - { + frr_each_safe (zbuf_queue, &zbq->queue_head, zb) { if (r < (ssize_t)zbuf_used(zb)) { zb->head += r; return 1; } r -= zbuf_used(zb); - list_del(&zb->queue_list); + zbuf_queue_del(&zbq->queue_head, zb); zbuf_free(zb); } diff --git a/nhrpd/zbuf.h b/nhrpd/zbuf.h index 2741860bfd..d036b10460 100644 --- a/nhrpd/zbuf.h +++ b/nhrpd/zbuf.h @@ -15,18 +15,22 @@ #include <endian.h> #include <sys/types.h> -#include "list.h" +#include "typesafe.h" + +PREDECL_DLIST(zbuf_queue); struct zbuf { - struct list_head queue_list; + struct zbuf_queue_item queue_entry; unsigned allocated : 1; unsigned error : 1; uint8_t *buf, *end; uint8_t *head, *tail; }; +DECLARE_DLIST(zbuf_queue, struct zbuf, queue_entry); + struct zbuf_queue { - struct list_head queue_head; + struct zbuf_queue_head queue_head; }; struct zbuf *zbuf_alloc(size_t size); diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index f3e8127a80..663b9b7982 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -106,8 +106,7 @@ static int ospf6_abr_nexthops_belong_to_area(struct ospf6_route *route, return 0; } -static void ospf6_abr_delete_route(struct ospf6_route *range, - struct ospf6_route *summary, +static void ospf6_abr_delete_route(struct ospf6_route *summary, struct ospf6_route_table *summary_table, struct ospf6_lsa *old) { @@ -385,8 +384,8 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, zlog_debug( "The range is not active. withdraw"); - ospf6_abr_delete_route(route, summary, - summary_table, old); + ospf6_abr_delete_route(summary, summary_table, + old); } } else if (old) { ospf6_route_remove(summary, summary_table); @@ -395,12 +394,13 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, return 0; } - if ((route->type == OSPF6_DEST_TYPE_ROUTER) && IS_AREA_STUB(area)) { + if ((route->type == OSPF6_DEST_TYPE_ROUTER) + && (IS_AREA_STUB(area) || IS_AREA_NSSA(area))) { if (is_debug) zlog_debug( "Area has been stubbed, purge Inter-Router LSA"); - ospf6_abr_delete_route(route, summary, summary_table, old); + ospf6_abr_delete_route(summary, summary_table, old); return 0; } @@ -409,7 +409,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, if (is_debug) zlog_debug("Area has been stubbed, purge prefix LSA"); - ospf6_abr_delete_route(route, summary, summary_table, old); + ospf6_abr_delete_route(summary, summary_table, old); return 0; } @@ -444,8 +444,21 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, if (is_debug) zlog_debug( "This is the secondary path to the ASBR, ignore"); - ospf6_abr_delete_route(route, summary, summary_table, - old); + ospf6_abr_delete_route(summary, summary_table, old); + return 0; + } + + /* Do not generate if area is NSSA */ + route_area = + ospf6_area_lookup(route->path.area_id, area->ospf6); + assert(route_area); + + if (IS_AREA_NSSA(route_area)) { + if (is_debug) + zlog_debug( + "%s: The route comes from NSSA area, skip", + __func__); + ospf6_abr_delete_route(summary, summary_table, old); return 0; } @@ -475,8 +488,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, zlog_debug( "Suppressed by range %pFX of area %s", &range->prefix, route_area->name); - ospf6_abr_delete_route(route, summary, summary_table, - old); + ospf6_abr_delete_route(summary, summary_table, old); return 0; } } @@ -488,8 +500,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, if (is_debug) zlog_debug( "This is the range with DoNotAdvertise set. ignore"); - ospf6_abr_delete_route(route, summary, summary_table, - old); + ospf6_abr_delete_route(summary, summary_table, old); return 0; } @@ -497,8 +508,7 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, if (!CHECK_FLAG(route->flag, OSPF6_ROUTE_ACTIVE_SUMMARY)) { if (is_debug) zlog_debug("The range is not active. withdraw"); - ospf6_abr_delete_route(route, summary, summary_table, - old); + ospf6_abr_delete_route(summary, summary_table, old); return 0; } } @@ -608,10 +618,14 @@ void ospf6_abr_range_reset_cost(struct ospf6 *ospf6) struct ospf6_area *oa; struct ospf6_route *range; - for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) + for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) { for (range = ospf6_route_head(oa->range_table); range; range = ospf6_route_next(range)) OSPF6_ABR_RANGE_CLEAR_COST(range); + for (range = ospf6_route_head(oa->nssa_range_table); range; + range = ospf6_route_next(range)) + OSPF6_ABR_RANGE_CLEAR_COST(range); + } } static inline uint32_t ospf6_abr_range_compute_cost(struct ospf6_route *range, @@ -622,10 +636,19 @@ static inline uint32_t ospf6_abr_range_compute_cost(struct ospf6_route *range, for (ro = ospf6_route_match_head(&range->prefix, o->route_table); ro; ro = ospf6_route_match_next(&range->prefix, ro)) { - if (ro->path.area_id == range->path.area_id - && (ro->path.type == OSPF6_PATH_TYPE_INTRA) - && !CHECK_FLAG(ro->flag, OSPF6_ROUTE_REMOVE)) - cost = MAX(cost, ro->path.cost); + if (CHECK_FLAG(ro->flag, OSPF6_ROUTE_REMOVE)) + continue; + if (ro->path.area_id != range->path.area_id) + continue; + if (CHECK_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE) + && ro->path.type != OSPF6_PATH_TYPE_EXTERNAL1 + && ro->path.type != OSPF6_PATH_TYPE_EXTERNAL2) + continue; + if (!CHECK_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE) + && ro->path.type != OSPF6_PATH_TYPE_INTRA) + continue; + + cost = MAX(cost, ro->path.cost); } return cost; @@ -674,6 +697,8 @@ void ospf6_abr_range_update(struct ospf6_route *range, struct ospf6 *ospf6) int summary_orig = 0; assert(range->type == OSPF6_DEST_TYPE_RANGE); + oa = ospf6_area_lookup(range->path.area_id, ospf6); + assert(oa); /* update range's cost and active flag */ cost = ospf6_abr_range_compute_cost(range, ospf6); @@ -696,34 +721,49 @@ void ospf6_abr_range_update(struct ospf6_route *range, struct ospf6 *ospf6) * if there * were active ranges. */ + if (!ospf6_abr_range_summary_needs_update(range, cost)) + return; - if (ospf6_abr_range_summary_needs_update(range, cost)) { - if (IS_OSPF6_DEBUG_ABR) - zlog_debug("%s: range %pFX update", __func__, - &range->prefix); - for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) + if (IS_OSPF6_DEBUG_ABR) + zlog_debug("%s: range %pFX update", __func__, &range->prefix); + + if (CHECK_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE)) { + if (CHECK_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY) + && !CHECK_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE)) { + ospf6_nssa_lsa_originate(range, oa, true); + summary_orig = 1; + } else { + struct ospf6_lsa *lsa; + + lsa = ospf6_lsdb_lookup(range->path.origin.type, + range->path.origin.id, + ospf6->router_id, oa->lsdb); + if (lsa) + ospf6_lsa_premature_aging(lsa); + } + } else { + for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) { summary_orig += ospf6_abr_originate_summary_to_area(range, oa); + } + } - if (CHECK_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY) - && summary_orig) { - if (!CHECK_FLAG(range->flag, - OSPF6_ROUTE_BLACKHOLE_ADDED)) { - if (IS_OSPF6_DEBUG_ABR) - zlog_debug("Add discard route"); + if (CHECK_FLAG(range->flag, OSPF6_ROUTE_ACTIVE_SUMMARY) + && summary_orig) { + if (!CHECK_FLAG(range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) { + if (IS_OSPF6_DEBUG_ABR) + zlog_debug("Add discard route"); - ospf6_zebra_add_discard(range, ospf6); - } - } else { - /* Summary removed or no summary generated as no - * specifics exist */ - if (CHECK_FLAG(range->flag, - OSPF6_ROUTE_BLACKHOLE_ADDED)) { - if (IS_OSPF6_DEBUG_ABR) - zlog_debug("Delete discard route"); + ospf6_zebra_add_discard(range, ospf6); + } + } else { + /* Summary removed or no summary generated as no + * specifics exist */ + if (CHECK_FLAG(range->flag, OSPF6_ROUTE_BLACKHOLE_ADDED)) { + if (IS_OSPF6_DEBUG_ABR) + zlog_debug("Delete discard route"); - ospf6_zebra_delete_discard(range, ospf6); - } + ospf6_zebra_delete_discard(range, ospf6); } } } diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index 999266b8d1..7e8e34a221 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -306,7 +306,8 @@ struct ospf6_area *ospf6_area_create(uint32_t area_id, struct ospf6 *o, int df) oa->range_table = OSPF6_ROUTE_TABLE_CREATE(AREA, PREFIX_RANGES); oa->range_table->scope = oa; - bf_init(oa->range_table->idspace, 32); + oa->nssa_range_table = OSPF6_ROUTE_TABLE_CREATE(AREA, PREFIX_RANGES); + oa->nssa_range_table->scope = oa; oa->summary_prefix = OSPF6_ROUTE_TABLE_CREATE(AREA, SUMMARY_PREFIXES); oa->summary_prefix->scope = oa; oa->summary_router = OSPF6_ROUTE_TABLE_CREATE(AREA, SUMMARY_ROUTERS); @@ -361,6 +362,7 @@ void ospf6_area_delete(struct ospf6_area *oa) ospf6_route_table_delete(oa->route_table); ospf6_route_table_delete(oa->range_table); + ospf6_route_table_delete(oa->nssa_range_table); ospf6_route_table_delete(oa->summary_prefix); ospf6_route_table_delete(oa->summary_router); @@ -576,8 +578,6 @@ DEFUN (area_range, range->path.u.cost_config = cost; - zlog_debug("%s: for prefix %s, flag = %x", __func__, - argv[idx_ipv6_prefixlen]->arg, range->flag); if (range->rnode == NULL) { ospf6_route_add(range, oa->range_table); } @@ -694,6 +694,22 @@ void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6) vty_out(vty, " no-summary"); vty_out(vty, "\n"); } + for (range = ospf6_route_head(oa->nssa_range_table); range; + range = ospf6_route_next(range)) { + vty_out(vty, " area %s nssa range %pFX", oa->name, + &range->prefix); + + if (CHECK_FLAG(range->flag, + OSPF6_ROUTE_DO_NOT_ADVERTISE)) { + vty_out(vty, " not-advertise"); + } else { + if (range->path.u.cost_config + != OSPF_AREA_RANGE_COST_UNSPEC) + vty_out(vty, " cost %u", + range->path.u.cost_config); + } + vty_out(vty, "\n"); + } if (PREFIX_NAME_IN(oa)) vty_out(vty, " area %s filter-list prefix %s in\n", oa->name, PREFIX_NAME_IN(oa)); @@ -711,7 +727,7 @@ void ospf6_area_config_write(struct vty *vty, struct ospf6 *ospf6) DEFUN (area_filter_list, area_filter_list_cmd, - "area <A.B.C.D|(0-4294967295)> filter-list prefix WORD <in|out>", + "area <A.B.C.D|(0-4294967295)> filter-list prefix PREFIXLIST_NAME <in|out>", "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" "OSPF6 area ID as a decimal value\n" @@ -754,7 +770,7 @@ DEFUN (area_filter_list, DEFUN (no_area_filter_list, no_area_filter_list_cmd, - "no area <A.B.C.D|(0-4294967295)> filter-list prefix WORD <in|out>", + "no area <A.B.C.D|(0-4294967295)> filter-list prefix PREFIXLIST_NAME <in|out>", NO_STR "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" @@ -863,12 +879,12 @@ void ospf6_plist_update(struct prefix_list *plist) DEFUN (area_import_list, area_import_list_cmd, - "area <A.B.C.D|(0-4294967295)> import-list NAME", + "area <A.B.C.D|(0-4294967295)> import-list ACCESSLIST6_NAME", "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" "OSPF6 area ID as a decimal value\n" "Set the filter for networks from other areas announced to the specified one\n" - "Name of the acess-list\n") + "Name of the access-list\n") { int idx_ipv4 = 1; int idx_name = 3; @@ -895,7 +911,7 @@ DEFUN (area_import_list, DEFUN (no_area_import_list, no_area_import_list_cmd, - "no area <A.B.C.D|(0-4294967295)> import-list NAME", + "no area <A.B.C.D|(0-4294967295)> import-list ACCESSLIST6_NAME", NO_STR "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" @@ -924,12 +940,12 @@ DEFUN (no_area_import_list, DEFUN (area_export_list, area_export_list_cmd, - "area <A.B.C.D|(0-4294967295)> export-list NAME", + "area <A.B.C.D|(0-4294967295)> export-list ACCESSLIST6_NAME", "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" "OSPF6 area ID as a decimal value\n" "Set the filter for networks announced to other areas\n" - "Name of the acess-list\n") + "Name of the access-list\n") { int idx_ipv4 = 1; int idx_name = 3; @@ -958,7 +974,7 @@ DEFUN (area_export_list, DEFUN (no_area_export_list, no_area_export_list_cmd, - "no area <A.B.C.D|(0-4294967295)> export-list NAME", + "no area <A.B.C.D|(0-4294967295)> export-list ACCESSLIST6_NAME", NO_STR "OSPF6 area parameters\n" "OSPF6 area ID in IP address format\n" @@ -1029,12 +1045,8 @@ static int ipv6_ospf6_spf_tree_common(struct vty *vty, struct ospf6 *ospf6, } } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } diff --git a/ospf6d/ospf6_area.h b/ospf6d/ospf6_area.h index 77cbad8b9e..905fbac949 100644 --- a/ospf6d/ospf6_area.h +++ b/ospf6d/ospf6_area.h @@ -46,6 +46,7 @@ struct ospf6_area { /* Summary routes to be originated (includes Configured Address Ranges) */ struct ospf6_route_table *range_table; + struct ospf6_route_table *nssa_range_table; struct ospf6_route_table *summary_prefix; struct ospf6_route_table *summary_router; diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index 733f4ba1fb..99f30a4a06 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -204,7 +204,6 @@ int ospf6_orig_as_external_lsa(struct thread *thread) uint32_t type, adv_router; oi = (struct ospf6_interface *)THREAD_ARG(thread); - oi->thread_as_extern_lsa = NULL; if (oi->state == OSPF6_INTERFACE_DOWN) return 0; @@ -1091,8 +1090,6 @@ static int ospf6_asbr_routemap_update_timer(struct thread *thread) struct ospf6_redist *red; int type; - ospf6->t_distribute_update = NULL; - for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { red = ospf6_redist_lookup(ospf6, type, 0); @@ -1311,7 +1308,8 @@ static void ospf6_asbr_redistribute_set(struct ospf6 *ospf6, int type) { ospf6_zebra_redistribute(type, ospf6->vrf_id); - ospf6_asbr_status_update(ospf6, ++ospf6->redist_count); + ++ospf6->redist_count; + ospf6_asbr_status_update(ospf6, ospf6->redist_count); } static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6, @@ -1333,7 +1331,8 @@ static void ospf6_asbr_redistribute_unset(struct ospf6 *ospf6, } ospf6_asbr_routemap_unset(red); - ospf6_asbr_status_update(ospf6, --ospf6->redist_count); + --ospf6->redist_count; + ospf6_asbr_status_update(ospf6, ospf6->redist_count); } /* When an area is unstubified, flood all the external LSAs in the area */ @@ -1411,7 +1410,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct ospf6_route *route, *match; struct ospf6_external_info *info; struct prefix prefix_id; - struct route_node *node; char ibuf[16]; struct ospf6_redist *red; @@ -1498,13 +1496,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, else ospf6_route_add_nexthop(match, ifindex, NULL); - /* create/update binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = IPV4_MAX_BITLEN; - prefix_id.u.prefix4.s_addr = htonl(info->id); - node = route_node_get(ospf6->external_id_table, &prefix_id); - node->info = match; - if (IS_OSPF6_DEBUG_ASBR) { inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf)); @@ -1525,7 +1516,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, route = ospf6_route_create(ospf6); route->type = OSPF6_DEST_TYPE_NETWORK; prefix_copy(&route->prefix, prefix); - route->ospf6 = ospf6; info = (struct ospf6_external_info *)XCALLOC( MTYPE_OSPF6_EXTERNAL_INFO, sizeof(struct ospf6_external_info)); @@ -2045,10 +2035,12 @@ ospf6_routemap_rule_match_interface(void *rule, const struct prefix *prefix, void *object) { struct interface *ifp; + struct ospf6_route *route; struct ospf6_external_info *ei; - ei = ((struct ospf6_route *)object)->route_option; - ifp = if_lookup_by_name_all_vrf((char *)rule); + route = object; + ei = route->route_option; + ifp = if_lookup_by_name((char *)rule, route->ospf6->vrf_id); if (ifp != NULL && ei->ifindex == ifp->ifindex) return RMAP_MATCH; @@ -2553,10 +2545,7 @@ DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd, if (uj) { json_object_object_add(json, "routes", json_array_routes); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } if (!all_vrf) @@ -2787,7 +2776,6 @@ static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6, struct ospf6_external_aggr_rt *aggr) { struct prefix prefix_id; - struct route_node *node; struct ospf6_lsa *lsa = NULL; if (IS_OSPF6_DEBUG_AGGR) @@ -2796,13 +2784,6 @@ static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6, aggr->id = ospf6->external_id++; - /* create/update binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = 32; - prefix_id.u.prefix4.s_addr = htonl(aggr->id); - node = route_node_get(ospf6->external_id_table, &prefix_id); - node->info = aggr; - if (IS_OSPF6_DEBUG_AGGR) zlog_debug( "Advertise AS-External Id:%pI4 prefix %pFX metric %u", @@ -3014,8 +2995,6 @@ static void ospf6_aggr_handle_external_info(void *data) struct ospf6_lsa *lsa = NULL; struct ospf6_external_info *info; struct ospf6 *ospf6 = NULL; - struct prefix prefix_id; - struct route_node *node; rt->aggr_route = NULL; @@ -3055,13 +3034,6 @@ static void ospf6_aggr_handle_external_info(void *data) info->id = ospf6->external_id++; rt->path.origin.id = htonl(info->id); - /* create/update binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = 32; - prefix_id.u.prefix4.s_addr = htonl(info->id); - node = route_node_get(ospf6->external_id_table, &prefix_id); - node->info = rt; - (void)ospf6_originate_type5_type7_lsas(rt, ospf6); } @@ -3372,7 +3344,6 @@ static int ospf6_asbr_summary_process(struct thread *thread) struct ospf6 *ospf6 = THREAD_ARG(thread); int operation = 0; - ospf6->t_external_aggr = NULL; operation = ospf6->aggr_action; if (IS_OSPF6_DEBUG_AGGR) @@ -3643,7 +3614,6 @@ void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6, struct ospf6_external_aggr_rt *aggr; struct ospf6_external_info *info; struct prefix prefix_id; - struct route_node *node; if (!is_default_prefix(p)) { aggr = ospf6_external_aggr_match(ospf6, @@ -3679,14 +3649,6 @@ void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6, */ if (!info->id) { info->id = ospf6->external_id++; - - /* create/update binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = 32; - prefix_id.u.prefix4.s_addr = htonl(info->id); - node = route_node_get(ospf6->external_id_table, &prefix_id); - node->info = rt; - } else { prefix_id.family = AF_INET; prefix_id.prefixlen = 32; diff --git a/ospf6d/ospf6_bfd.c b/ospf6d/ospf6_bfd.c index fc1e718540..c124f17e34 100644 --- a/ospf6d/ospf6_bfd.c +++ b/ospf6d/ospf6_bfd.c @@ -143,7 +143,7 @@ void ospf6_bfd_info_nbr_create(struct ospf6_interface *oi, bfd_sess_set_ipv6_addrs(on->bfd_session, on->ospf6_if->linklocal_addr, &on->linklocal_addr); bfd_sess_set_interface(on->bfd_session, oi->interface->name); - bfd_sess_set_vrf(on->bfd_session, oi->interface->vrf_id); + bfd_sess_set_vrf(on->bfd_session, oi->interface->vrf->vrf_id); bfd_sess_set_profile(on->bfd_session, oi->bfd_config.profile); } diff --git a/ospf6d/ospf6_flood.c b/ospf6d/ospf6_flood.c index 150903a56a..5fed6dfe17 100644 --- a/ospf6d/ospf6_flood.c +++ b/ospf6d/ospf6_flood.c @@ -151,24 +151,6 @@ void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa, ospf6_lsa_originate(oi->area->ospf6, lsa); } -void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6, - uint32_t id) -{ - struct prefix prefix_id; - struct route_node *node; - - /* remove binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = 32; - prefix_id.u.prefix4.s_addr = id; - node = route_node_lookup(ospf6->external_id_table, &prefix_id); - assert(node); - node->info = NULL; - route_unlock_node(node); /* to free the lookup lock */ - route_unlock_node(node); /* to free the original lock */ - -} - void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa) { uint32_t id = lsa->header->id; @@ -177,8 +159,6 @@ void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa) ospf6_lsa_purge(lsa); - ospf6_remove_id_from_external_id_table(ospf6, id); - /* Delete the corresponding NSSA LSA */ for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, lnode, oa)) { lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_TYPE_7), id, @@ -266,10 +246,14 @@ void ospf6_decrement_retrans_count(struct ospf6_lsa *lsa) /* RFC2328 section 13.2 Installing LSAs in the database */ void ospf6_install_lsa(struct ospf6_lsa *lsa) { + struct ospf6 *ospf6; struct timeval now; struct ospf6_lsa *old; struct ospf6_area *area = NULL; + ospf6 = ospf6_get_by_lsdb(lsa); + assert(ospf6); + /* Remove the old instance from all neighbors' Link state retransmission list (RFC2328 13.2 last paragraph) */ old = ospf6_lsdb_lookup(lsa->header->type, lsa->header->id, @@ -330,20 +314,14 @@ void ospf6_install_lsa(struct ospf6_lsa *lsa) && !CHECK_FLAG(lsa->flag, OSPF6_LSA_DUPLICATE)) { /* check if it is new lsa ? or existing lsa got modified ?*/ - if (!old || OSPF6_LSA_IS_CHANGED(old, lsa)) { - struct ospf6 *ospf6; - - ospf6 = ospf6_get_by_lsdb(lsa); - - assert(ospf6); - + if (!old || OSPF6_LSA_IS_CHANGED(old, lsa)) ospf6_helper_handle_topo_chg(ospf6, lsa); - } } ospf6_lsdb_add(lsa, lsa->lsdb); - if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7) { + if (ntohs(lsa->header->type) == OSPF6_LSTYPE_TYPE_7 + && lsa->header->adv_router != ospf6->router_id) { area = OSPF6_AREA(lsa->lsdb->data); ospf6_translated_nssa_refresh(area, lsa, NULL); ospf6_schedule_abr_task(area->ospf6); diff --git a/ospf6d/ospf6_flood.h b/ospf6d/ospf6_flood.h index 775d0d289d..75f3c065bb 100644 --- a/ospf6d/ospf6_flood.h +++ b/ospf6d/ospf6_flood.h @@ -39,8 +39,6 @@ extern void ospf6_lsa_originate_area(struct ospf6_lsa *lsa, struct ospf6_area *oa); extern void ospf6_lsa_originate_interface(struct ospf6_lsa *lsa, struct ospf6_interface *oi); -void ospf6_remove_id_from_external_id_table(struct ospf6 *ospf6, - uint32_t id); void ospf6_external_lsa_purge(struct ospf6 *ospf6, struct ospf6_lsa *lsa); extern void ospf6_lsa_purge(struct ospf6_lsa *lsa); diff --git a/ospf6d/ospf6_gr.c b/ospf6d/ospf6_gr.c index 40893ed998..c3e6f62f06 100644 --- a/ospf6d/ospf6_gr.c +++ b/ospf6d/ospf6_gr.c @@ -58,7 +58,7 @@ static int ospf6_gr_lsa_originate(struct ospf6_interface *oi) char buffer[OSPF6_MAX_LSASIZE]; if (IS_OSPF6_DEBUG_ORIGINATE(LINK)) - zlog_debug("Originate Link-LSA for Interface %s", + zlog_debug("Originate Grace-LSA for Interface %s", oi->interface->name); /* prepare buffer */ diff --git a/ospf6d/ospf6_gr.h b/ospf6d/ospf6_gr.h index 6406e8efee..28798d8717 100644 --- a/ospf6d/ospf6_gr.h +++ b/ospf6d/ospf6_gr.h @@ -93,7 +93,7 @@ struct tlv_header { #define TLV_BODY_SIZE(tlvh) (ROUNDUP(ntohs((tlvh)->length), sizeof(uint32_t))) -#define TLV_SIZE(tlvh) (TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) +#define TLV_SIZE(tlvh) (uint32_t)(TLV_HDR_SIZE + TLV_BODY_SIZE(tlvh)) #define TLV_HDR_TOP(lsah) \ (struct tlv_header *)((char *)(lsah) + OSPF6_LSA_HEADER_SIZE) diff --git a/ospf6d/ospf6_gr_helper.c b/ospf6d/ospf6_gr_helper.c index ad8998b1ed..84ee35a3ed 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -157,8 +157,18 @@ static int ospf6_extract_grace_lsa_fields(struct ospf6_lsa *lsa, length = ntohs(lsah->length) - OSPF6_LSA_HEADER_SIZE; - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { + + /* Check TLV len against overall LSA */ + if (sum + TLV_SIZE(tlvh) > length) { + if (IS_DEBUG_OSPF6_GR) + zlog_debug( + "%s: Malformed packet: Invalid TLV len:%d", + __func__, TLV_SIZE(tlvh)); + return OSPF6_FAILURE; + } + switch (ntohs(tlvh->type)) { case GRACE_PERIOD_TYPE: gracePeriod = (struct grace_tlv_graceperiod *)tlvh; @@ -202,8 +212,6 @@ static int ospf6_handle_grace_timer_expiry(struct thread *thread) { struct ospf6_neighbor *nbr = THREAD_ARG(thread); - nbr->gr_helper_info.t_grace_timer = NULL; - ospf6_gr_helper_exit(nbr, OSPF6_GR_HELPER_GRACE_TIMEOUT); return OSPF6_SUCCESS; } @@ -1180,12 +1188,8 @@ DEFPY(show_ipv6_ospf6_gr_helper, show_ospf6_gr_helper_details(vty, ospf6, json, uj, detail); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -1237,8 +1241,20 @@ static int ospf6_grace_lsa_show_info(struct vty *vty, struct ospf6_lsa *lsa, zlog_debug(" TLV info:"); } - for (tlvh = TLV_HDR_TOP(lsah); sum < length; + for (tlvh = TLV_HDR_TOP(lsah); sum < length && tlvh; tlvh = TLV_HDR_NEXT(tlvh)) { + + /* Check TLV len */ + if (sum + TLV_SIZE(tlvh) > length) { + if (vty) + vty_out(vty, "%% Invalid TLV length: %d\n", + TLV_SIZE(tlvh)); + else if (IS_DEBUG_OSPF6_GR) + zlog_debug("%% Invalid TLV length: %d", + TLV_SIZE(tlvh)); + return OSPF6_FAILURE; + } + switch (ntohs(tlvh->type)) { case GRACE_PERIOD_TYPE: gracePeriod = (struct grace_tlv_graceperiod *)tlvh; diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index a3eb1445f1..a0c921f419 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -127,7 +127,7 @@ static uint8_t ospf6_default_iftype(struct interface *ifp) { if (if_is_pointopoint(ifp)) return OSPF_IFTYPE_POINTOPOINT; - else if (if_is_loopback_or_vrf(ifp)) + else if (if_is_loopback(ifp)) return OSPF_IFTYPE_LOOPBACK; else return OSPF_IFTYPE_BROADCAST; @@ -150,7 +150,7 @@ static uint32_t ospf6_interface_get_cost(struct ospf6_interface *oi) : OSPF6_INTERFACE_BANDWIDTH; } - ospf6 = ospf6_lookup_by_vrf_id(oi->interface->vrf_id); + ospf6 = oi->interface->vrf->info; refbw = ospf6 ? ospf6->ref_bandwidth : OSPF6_REFERENCE_BANDWIDTH; /* A specifed ip ospf cost overrides a calculated one. */ @@ -387,7 +387,7 @@ void ospf6_interface_state_update(struct interface *ifp) if (if_is_operative(ifp) && (ospf6_interface_get_linklocal_address(oi->interface) - || if_is_loopback_or_vrf(oi->interface))) + || if_is_loopback(oi->interface))) thread_execute(master, interface_up, oi, 0); else thread_execute(master, interface_down, oi, 0); @@ -675,7 +675,8 @@ uint8_t dr_election(struct ospf6_interface *oi) if (on->state < OSPF6_NEIGHBOR_TWOWAY) continue; /* Schedule AdjOK. */ - thread_add_event(master, adj_ok, on, 0, NULL); + thread_add_event(master, adj_ok, on, 0, + &on->thread_adj_ok); } } @@ -749,7 +750,7 @@ int interface_up(struct thread *thread) /* check interface has a link-local address */ if (!(ospf6_interface_get_linklocal_address(oi->interface) - || if_is_loopback_or_vrf(oi->interface))) { + || if_is_loopback(oi->interface))) { zlog_warn( "Interface %s has no link local address, can't execute [InterfaceUp]", oi->interface->name); @@ -818,7 +819,7 @@ int interface_up(struct thread *thread) /* Schedule Hello */ if (!CHECK_FLAG(oi->flag, OSPF6_INTERFACE_PASSIVE) - && !if_is_loopback_or_vrf(oi->interface)) { + && !if_is_loopback(oi->interface)) { thread_add_event(master, ospf6_hello_send, oi, 0, &oi->thread_send_hello); } @@ -1241,7 +1242,6 @@ struct in6_addr *ospf6_interface_get_global_address(struct interface *ifp) { struct listnode *n; struct connected *c; - struct in6_addr *l = (struct in6_addr *)NULL; /* for each connected address */ for (ALL_LIST_ELEMENTS_RO(ifp->connected, n, c)) { @@ -1250,9 +1250,10 @@ struct in6_addr *ospf6_interface_get_global_address(struct interface *ifp) continue; if (!IN6_IS_ADDR_LINKLOCAL(&c->address->u.prefix6)) - l = &c->address->u.prefix6; + return &c->address->u.prefix6; } - return l; + + return NULL; } @@ -1276,10 +1277,7 @@ static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id, if (ifp == NULL) { json_object_string_add(json, "noSuchInterface", argv[idx_ifname]->arg); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); json_object_free(json_int); return CMD_WARNING; } @@ -1293,10 +1291,7 @@ static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id, json_int); } } - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { if (argc == intf_idx) { ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id); @@ -1360,11 +1355,6 @@ static int ospf6_interface_show_traffic(struct vty *vty, struct ospf6_interface *oi = NULL; json_object *json_interface; - if (intf_ifp) - vrf = vrf_lookup_by_id(intf_ifp->vrf_id); - else - vrf = vrf_lookup_by_id(vrf_id); - if (!display_once && !use_json) { vty_out(vty, "\n"); vty_out(vty, "%-12s%-17s%-17s%-17s%-17s%-17s\n", "Interface", @@ -1378,6 +1368,7 @@ static int ospf6_interface_show_traffic(struct vty *vty, } if (intf_ifp == NULL) { + vrf = vrf_lookup_by_id(vrf_id); FOR_ALL_INTERFACES (vrf, ifp) { if (ifp->info) oi = (struct ospf6_interface *)ifp->info; @@ -1487,10 +1478,7 @@ static int ospf6_interface_show_traffic_common(struct vty *vty, int argc, "No Such Interface"); json_object_string_add(json, "interface", intf_name); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); return CMD_WARNING; } if (ifp->info == NULL) { @@ -1499,10 +1487,7 @@ static int ospf6_interface_show_traffic_common(struct vty *vty, int argc, "OSPF not enabled on this interface"); json_object_string_add(json, "interface", intf_name); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); return 0; } } else { @@ -1522,12 +1507,8 @@ static int ospf6_interface_show_traffic_common(struct vty *vty, int argc, ospf6_interface_show_traffic(vty, ifp, display_once, json, uj, vrf_id); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -1684,7 +1665,7 @@ void ospf6_interface_start(struct ospf6_interface *oi) if (oi->area) return; - ospf6 = ospf6_lookup_by_vrf_id(oi->interface->vrf_id); + ospf6 = oi->interface->vrf->info; if (!ospf6) return; @@ -2314,7 +2295,7 @@ DEFUN (no_ipv6_ospf6_passive, THREAD_OFF(oi->thread_sso); /* don't send hellos over loopback interface */ - if (!if_is_loopback_or_vrf(oi->interface)) + if (!if_is_loopback(oi->interface)) thread_add_event(master, ospf6_hello_send, oi, 0, &oi->thread_send_hello); @@ -2739,27 +2720,39 @@ void ospf6_interface_clear(struct interface *ifp) /* Clear interface */ DEFUN (clear_ipv6_ospf6_interface, clear_ipv6_ospf6_interface_cmd, - "clear ipv6 ospf6 interface [IFNAME]", + "clear ipv6 ospf6 [vrf NAME] interface [IFNAME]", CLEAR_STR IP6_STR OSPF6_STR + VRF_CMD_HELP_STR INTERFACE_STR IFNAME_STR ) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct vrf *vrf; + int idx_vrf = 3; int idx_ifname = 4; struct interface *ifp; + const char *vrf_name; - if (argc == 4) /* Clear all the ospfv3 interfaces. */ - { + if (argv_find(argv, argc, "vrf", &idx_vrf)) + vrf_name = argv[idx_vrf + 1]->arg; + else + vrf_name = VRF_DEFAULT_NAME; + vrf = vrf_lookup_by_name(vrf_name); + if (!vrf) { + vty_out(vty, "%% VRF %s not found\n", vrf_name); + return CMD_WARNING; + } + + if (!argv_find(argv, argc, "IFNAME", &idx_ifname)) { + /* Clear all the ospfv3 interfaces. */ FOR_ALL_INTERFACES (vrf, ifp) ospf6_interface_clear(ifp); - } else /* Interface name is specified. */ - { - if ((ifp = if_lookup_by_name(argv[idx_ifname]->arg, - VRF_DEFAULT)) - == NULL) { + } else { + /* Interface name is specified. */ + ifp = if_lookup_by_name_vrf(argv[idx_ifname]->arg, vrf); + if (!ifp) { vty_out(vty, "No such Interface: %s\n", argv[idx_ifname]->arg); return CMD_WARNING; diff --git a/ospf6d/ospf6_intra.c b/ospf6d/ospf6_intra.c index 2d82ff7ce8..6626b4bed5 100644 --- a/ospf6d/ospf6_intra.c +++ b/ospf6d/ospf6_intra.c @@ -142,19 +142,15 @@ static int ospf6_router_lsa_show(struct vty *vty, struct ospf6_lsa *lsa, json_object_string_add(json_loop, "type", name); json_object_int_add(json_loop, "metric", ntohs(lsdesc->metric)); - json_object_string_add(json_loop, "interfaceId", - inet_ntop(AF_INET, - &lsdesc->interface_id, - buf, sizeof(buf))); - json_object_string_add( - json_loop, "neighborInterfaceId", - inet_ntop(AF_INET, - &lsdesc->neighbor_interface_id, buf, - sizeof(buf))); - json_object_string_add( - json_loop, "neighborRouterId", - inet_ntop(AF_INET, &lsdesc->neighbor_router_id, - buf, sizeof(buf))); + json_object_string_addf( + json_loop, "interfaceId", "%pI4", + (in_addr_t *)&lsdesc->interface_id); + json_object_string_addf( + json_loop, "neighborInterfaceId", "%pI4", + (in_addr_t *)&lsdesc->neighbor_interface_id); + json_object_string_addf(json_loop, "neighborRouterId", + "%pI4", + &lsdesc->neighbor_router_id); json_object_array_add(json_arr, json_loop); } else { vty_out(vty, " Type: %s Metric: %d\n", name, @@ -248,7 +244,6 @@ int ospf6_router_lsa_originate(struct thread *thread) int count; oa = (struct ospf6_area *)THREAD_ARG(thread); - oa->thread_router_lsa = NULL; if (oa->ospf6->gr_info.restart_in_progress) { if (IS_DEBUG_OSPF6_GR) @@ -533,7 +528,6 @@ int ospf6_network_lsa_originate(struct thread *thread) uint16_t type; oi = (struct ospf6_interface *)THREAD_ARG(thread); - oi->thread_network_lsa = NULL; /* The interface must be enabled until here. A Network-LSA of a disabled interface (but was once enabled) should be flushed @@ -784,7 +778,6 @@ int ospf6_link_lsa_originate(struct thread *thread) struct ospf6_prefix *op; oi = (struct ospf6_interface *)THREAD_ARG(thread); - oi->thread_link_lsa = NULL; assert(oi->area); @@ -1030,7 +1023,6 @@ int ospf6_intra_prefix_lsa_originate_stub(struct thread *thread) int ls_id = 0; oa = (struct ospf6_area *)THREAD_ARG(thread); - oa->thread_intra_prefix_lsa = NULL; if (oa->ospf6->gr_info.restart_in_progress) { if (IS_DEBUG_OSPF6_GR) @@ -1269,7 +1261,6 @@ int ospf6_intra_prefix_lsa_originate_transit(struct thread *thread) uint16_t type; oi = (struct ospf6_interface *)THREAD_ARG(thread); - oi->thread_intra_prefix_lsa = NULL; assert(oi->area); diff --git a/ospf6d/ospf6_lsa.c b/ospf6d/ospf6_lsa.c index f406e828e1..99d0de39cf 100644 --- a/ospf6d/ospf6_lsa.c +++ b/ospf6d/ospf6_lsa.c @@ -54,7 +54,7 @@ DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_HEADER, "OSPF6 LSA header"); DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA_SUMMARY, "OSPF6 LSA summary"); -vector ospf6_lsa_handler_vector; +static struct ospf6_lsa_handler *lsa_handlers[OSPF6_LSTYPE_SIZE]; struct ospf6 *ospf6_get_by_lsdb(struct ospf6_lsa *lsa) { @@ -115,8 +115,13 @@ static struct ospf6_lsa_handler unknown_handler = { void ospf6_install_lsa_handler(struct ospf6_lsa_handler *handler) { /* type in handler is host byte order */ - int index = handler->lh_type & OSPF6_LSTYPE_FCODE_MASK; - vector_set_index(ospf6_lsa_handler_vector, index, (void *)handler); + unsigned int index = handler->lh_type & OSPF6_LSTYPE_FCODE_MASK; + + assertf(index < array_size(lsa_handlers), "index=%x", index); + assertf(lsa_handlers[index] == NULL, "old=%s, new=%s", + lsa_handlers[index]->lh_name, handler->lh_name); + + lsa_handlers[index] = handler; } struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type) @@ -124,10 +129,8 @@ struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type) struct ospf6_lsa_handler *handler = NULL; unsigned int index = ntohs(type) & OSPF6_LSTYPE_FCODE_MASK; - if (index >= vector_active(ospf6_lsa_handler_vector)) - handler = &unknown_handler; - else - handler = vector_slot(ospf6_lsa_handler_vector, index); + if (index < array_size(lsa_handlers)) + handler = lsa_handlers[index]; if (handler == NULL) handler = &unknown_handler; @@ -989,13 +992,11 @@ int ospf6_lsa_checksum_valid(struct ospf6_lsa_header *lsa_header) void ospf6_lsa_init(void) { - ospf6_lsa_handler_vector = vector_init(0); ospf6_install_lsa_handler(&unknown_handler); } void ospf6_lsa_terminate(void) { - vector_free(ospf6_lsa_handler_vector); } static char *ospf6_lsa_handler_name(const struct ospf6_lsa_handler *h) @@ -1020,27 +1021,32 @@ static char *ospf6_lsa_handler_name(const struct ospf6_lsa_handler *h) return buf; } -DEFPY (debug_ospf6_lsa_all, - debug_ospf6_lsa_all_cmd, - "[no$no] debug ospf6 lsa all", - NO_STR - DEBUG_STR - OSPF6_STR - "Debug Link State Advertisements (LSAs)\n" - "Display for all types of LSAs\n") +void ospf6_lsa_debug_set_all(bool val) { unsigned int i; struct ospf6_lsa_handler *handler = NULL; - for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) { - handler = vector_slot(ospf6_lsa_handler_vector, i); + for (i = 0; i < array_size(lsa_handlers); i++) { + handler = lsa_handlers[i]; if (handler == NULL) continue; - if (!no) + if (val) SET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_ALL); else UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_ALL); } +} + +DEFPY (debug_ospf6_lsa_all, + debug_ospf6_lsa_all_cmd, + "[no$no] debug ospf6 lsa all", + NO_STR + DEBUG_STR + OSPF6_STR + "Debug Link State Advertisements (LSAs)\n" + "Display for all types of LSAs\n") +{ + ospf6_lsa_debug_set_all(!no); return CMD_SUCCESS; } @@ -1070,7 +1076,7 @@ DEFPY (debug_ospf6_lsa_aggregation, DEFUN (debug_ospf6_lsa_type, debug_ospf6_lsa_hex_cmd, - "debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]", + "debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|nssa|link|intra-prefix|unknown> [<originate|examine|flooding>]", DEBUG_STR OSPF6_STR "Debug Link State Advertisements (LSAs)\n" @@ -1079,6 +1085,7 @@ DEFUN (debug_ospf6_lsa_type, "Display Inter-Area-Prefix LSAs\n" "Display Inter-Router LSAs\n" "Display As-External LSAs\n" + "Display NSSA LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display LSAs of unknown origin\n" @@ -1091,8 +1098,8 @@ DEFUN (debug_ospf6_lsa_type, unsigned int i; struct ospf6_lsa_handler *handler = NULL; - for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) { - handler = vector_slot(ospf6_lsa_handler_vector, i); + for (i = 0; i < array_size(lsa_handlers); i++) { + handler = lsa_handlers[i]; if (handler == NULL) continue; if (strncmp(argv[idx_lsa]->arg, ospf6_lsa_handler_name(handler), @@ -1122,7 +1129,7 @@ DEFUN (debug_ospf6_lsa_type, DEFUN (no_debug_ospf6_lsa_type, no_debug_ospf6_lsa_hex_cmd, - "no debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|link|intra-prefix|unknown> [<originate|examine|flooding>]", + "no debug ospf6 lsa <router|network|inter-prefix|inter-router|as-external|nssa|link|intra-prefix|unknown> [<originate|examine|flooding>]", NO_STR DEBUG_STR OSPF6_STR @@ -1132,6 +1139,7 @@ DEFUN (no_debug_ospf6_lsa_type, "Display Inter-Area-Prefix LSAs\n" "Display Inter-Router LSAs\n" "Display As-External LSAs\n" + "Display NSSA LSAs\n" "Display Link LSAs\n" "Display Intra-Area-Prefix LSAs\n" "Display LSAs of unknown origin\n" @@ -1144,8 +1152,8 @@ DEFUN (no_debug_ospf6_lsa_type, unsigned int i; struct ospf6_lsa_handler *handler = NULL; - for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) { - handler = vector_slot(ospf6_lsa_handler_vector, i); + for (i = 0; i < array_size(lsa_handlers); i++) { + handler = lsa_handlers[i]; if (handler == NULL) continue; if (strncmp(argv[idx_lsa]->arg, ospf6_lsa_handler_name(handler), @@ -1192,8 +1200,8 @@ int config_write_ospf6_debug_lsa(struct vty *vty) const struct ospf6_lsa_handler *handler; bool debug_all = true; - for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) { - handler = vector_slot(ospf6_lsa_handler_vector, i); + for (i = 0; i < array_size(lsa_handlers); i++) { + handler = lsa_handlers[i]; if (handler == NULL) continue; if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG_ALL) @@ -1208,8 +1216,8 @@ int config_write_ospf6_debug_lsa(struct vty *vty) return 0; } - for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) { - handler = vector_slot(ospf6_lsa_handler_vector, i); + for (i = 0; i < array_size(lsa_handlers); i++) { + handler = lsa_handlers[i]; if (handler == NULL) continue; if (CHECK_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG)) diff --git a/ospf6d/ospf6_lsa.h b/ospf6d/ospf6_lsa.h index 2316040694..aa1150afca 100644 --- a/ospf6d/ospf6_lsa.h +++ b/ospf6d/ospf6_lsa.h @@ -87,11 +87,6 @@ #define OSPF6_SCOPE_AS 0x4000 #define OSPF6_SCOPE_RESERVED 0x6000 -/* AS-external-LSA refresh method. */ -#define LSA_REFRESH_IF_CHANGED 0 -#define LSA_REFRESH_FORCE 1 - - /* XXX U-bit handling should be treated here */ #define OSPF6_LSA_SCOPE(type) (ntohs(type) & OSPF6_LSTYPE_SCOPE_MASK) @@ -178,8 +173,6 @@ struct ospf6_lsa_handler { #define OSPF6_LSA_IS_KNOWN(t) \ (ospf6_get_lsa_handler(t)->lh_type != OSPF6_LSTYPE_UNKNOWN ? 1 : 0) -extern vector ospf6_lsa_handler_vector; - /* Macro for LSA Origination */ /* addr is (struct prefix *) */ #define CONTINUE_IF_ADDRESS_LINKLOCAL(debug, addr) \ @@ -273,6 +266,7 @@ extern int ospf6_lsa_prohibited_duration(uint16_t type, uint32_t id, extern void ospf6_install_lsa_handler(struct ospf6_lsa_handler *handler); extern struct ospf6_lsa_handler *ospf6_get_lsa_handler(uint16_t type); +extern void ospf6_lsa_debug_set_all(bool val); extern void ospf6_lsa_init(void); extern void ospf6_lsa_terminate(void); diff --git a/ospf6d/ospf6_main.c b/ospf6d/ospf6_main.c index 54cf142ba8..165a764c38 100644 --- a/ospf6d/ospf6_main.c +++ b/ospf6d/ospf6_main.c @@ -148,7 +148,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t ospf6_signals[] = { +struct frr_signal_t ospf6_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index a81c3e728f..352cb137ed 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -409,9 +409,8 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, if (ntohs(hello->hello_interval) != oi->hello_interval) { zlog_warn( "VRF %s: I/F %s HelloInterval mismatch: (my %d, rcvd %d)", - vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name, oi->hello_interval, - ntohs(hello->hello_interval)); + oi->interface->vrf->name, oi->interface->name, + oi->hello_interval, ntohs(hello->hello_interval)); return; } @@ -419,9 +418,8 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, if (ntohs(hello->dead_interval) != oi->dead_interval) { zlog_warn( "VRF %s: I/F %s DeadInterval mismatch: (my %d, rcvd %d)", - vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name, oi->dead_interval, - ntohs(hello->dead_interval)); + oi->interface->vrf->name, oi->interface->name, + oi->dead_interval, ntohs(hello->dead_interval)); return; } @@ -429,8 +427,15 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, if (OSPF6_OPT_ISSET(hello->options, OSPF6_OPT_E) != OSPF6_OPT_ISSET(oi->area->options, OSPF6_OPT_E)) { zlog_warn("VRF %s: IF %s E-bit mismatch", - vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name); + oi->interface->vrf->name, oi->interface->name); + return; + } + + /* N-bit check */ + if (OSPF6_OPT_ISSET(hello->options, OSPF6_OPT_N) + != OSPF6_OPT_ISSET(oi->area->options, OSPF6_OPT_N)) { + zlog_warn("VRF %s: IF %s N-bit mismatch", + oi->interface->vrf->name, oi->interface->name); return; } @@ -622,10 +627,8 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh, memcpy(on->options, dbdesc->options, sizeof(on->options)); } else { - zlog_warn( - "VRF %s: Nbr %s: Negotiation failed", - vrf_id_to_name(on->ospf6_if->interface->vrf_id), - on->name); + zlog_warn("VRF %s: Nbr %s: Negotiation failed", + on->ospf6_if->interface->vrf->name, on->name); return; } /* fall through to exchange */ @@ -772,7 +775,8 @@ static void ospf6_dbdesc_recv_master(struct ospf6_header *oh, /* More bit check */ if (!CHECK_FLAG(dbdesc->bits, OSPF6_DBDESC_MBIT) && !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)) - thread_add_event(master, exchange_done, on, 0, NULL); + thread_add_event(master, exchange_done, on, 0, + &on->thread_exchange_done); else { thread_add_event(master, ospf6_dbdesc_send_newone, on, 0, &on->thread_send_dbdesc); @@ -837,10 +841,8 @@ static void ospf6_dbdesc_recv_slave(struct ospf6_header *oh, memcpy(on->options, dbdesc->options, sizeof(on->options)); } else { - zlog_warn( - "VRF %s: Nbr %s Negotiation failed", - vrf_id_to_name(on->ospf6_if->interface->vrf_id), - on->name); + zlog_warn("VRF %s: Nbr %s Negotiation failed", + on->ospf6_if->interface->vrf->name, on->name); return; } break; @@ -1007,8 +1009,8 @@ static void ospf6_dbdesc_recv(struct in6_addr *src, struct in6_addr *dst, /* Interface MTU check */ if (!oi->mtu_ignore && ntohs(dbdesc->ifmtu) != oi->ifmtu) { zlog_warn("VRF %s: I/F %s MTU mismatch (my %d rcvd %d)", - vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name, oi->ifmtu, ntohs(dbdesc->ifmtu)); + oi->interface->vrf->name, oi->interface->name, + oi->ifmtu, ntohs(dbdesc->ifmtu)); return; } @@ -1514,14 +1516,12 @@ static int ospf6_rxpacket_examin(struct ospf6_interface *oi, if (oh->area_id == OSPF_AREA_BACKBONE) zlog_warn( "VRF %s: I/F %s Message may be via Virtual Link: not supported", - vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name); + oi->interface->vrf->name, oi->interface->name); else zlog_warn( "VRF %s: I/F %s Area-ID mismatch (my %pI4, rcvd %pI4)", - vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name, &oi->area->area_id, - &oh->area_id); + oi->interface->vrf->name, oi->interface->name, + &oi->area->area_id, &oh->area_id); return MSG_NG; } @@ -1529,16 +1529,16 @@ static int ospf6_rxpacket_examin(struct ospf6_interface *oi, if (oh->instance_id != oi->instance_id) { zlog_warn( "VRF %s: I/F %s Instance-ID mismatch (my %u, rcvd %u)", - vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name, oi->instance_id, oh->instance_id); + oi->interface->vrf->name, oi->interface->name, + oi->instance_id, oh->instance_id); return MSG_NG; } /* Router-ID check */ if (oh->router_id == oi->area->ospf6->router_id) { zlog_warn("VRF %s: I/F %s Duplicate Router-ID (%pI4)", - vrf_id_to_name(oi->interface->vrf_id), - oi->interface->name, &oh->router_id); + oi->interface->vrf->name, oi->interface->name, + &oh->router_id); return MSG_NG; } return MSG_OK; @@ -1768,7 +1768,7 @@ static int ospf6_read_helper(int sockfd, struct ospf6 *ospf6) * Drop packet destined to another VRF. * This happens when raw_l3mdev_accept is set to 1. */ - if (ospf6->vrf_id != oi->interface->vrf_id) + if (ospf6->vrf_id != oi->interface->vrf->vrf_id) return OSPF6_READ_CONTINUE; oh = (struct ospf6_header *)recvbuf; @@ -2261,7 +2261,8 @@ int ospf6_dbdesc_send_newone(struct thread *thread) if (!CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MSBIT) && /* Slave */ !CHECK_FLAG(on->dbdesc_last.bits, OSPF6_DBDESC_MBIT) && !CHECK_FLAG(on->dbdesc_bits, OSPF6_DBDESC_MBIT)) - thread_add_event(master, exchange_done, on, 0, NULL); + thread_add_event(master, exchange_done, on, 0, + &on->thread_exchange_done); thread_execute(master, ospf6_dbdesc_send, on, 0); return 0; diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 6f2795a56d..1a8fedea0c 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -48,7 +48,7 @@ #include "ospf6_gr.h" #include "lib/json.h" -DEFINE_MTYPE(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor"); +DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_NEIGHBOR, "OSPF6 neighbor"); DEFINE_HOOK(ospf6_neighbor_change, (struct ospf6_neighbor * on, int state, int next_state), @@ -168,6 +168,9 @@ void ospf6_neighbor_delete(struct ospf6_neighbor *on) THREAD_OFF(on->thread_send_lsreq); THREAD_OFF(on->thread_send_lsupdate); THREAD_OFF(on->thread_send_lsack); + THREAD_OFF(on->thread_exchange_done); + THREAD_OFF(on->thread_adj_ok); + THREAD_OFF(on->gr_helper_info.t_grace_timer); bfd_sess_free(&on->bfd_session); @@ -603,6 +606,8 @@ int oneway_received(struct thread *thread) THREAD_OFF(on->thread_send_lsreq); THREAD_OFF(on->thread_send_lsupdate); THREAD_OFF(on->thread_send_lsack); + THREAD_OFF(on->thread_exchange_done); + THREAD_OFF(on->thread_adj_ok); return 0; } @@ -1068,10 +1073,7 @@ static void ospf6_neighbor_show_detail_common(struct vty *vty, json_object_object_add(json, "neighbors", json_array); else json_object_free(json_array); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } } @@ -1143,12 +1145,8 @@ static int ospf6_neighbor_show_common(struct vty *vty, int argc, (*showfunc)(vty, on, json, uj); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -1249,7 +1247,6 @@ DEFUN (no_debug_ospf6, OSPF6_STR) { unsigned int i; - struct ospf6_lsa_handler *handler = NULL; OSPF6_DEBUG_ABR_OFF(); OSPF6_DEBUG_ASBR_OFF(); @@ -1259,13 +1256,7 @@ DEFUN (no_debug_ospf6, OSPF6_DEBUG_FLOODING_OFF(); OSPF6_DEBUG_INTERFACE_OFF(); - for (i = 0; i < vector_active(ospf6_lsa_handler_vector); i++) { - handler = vector_slot(ospf6_lsa_handler_vector, i); - - if (handler != NULL) { - UNSET_FLAG(handler->lh_debug, OSPF6_LSA_DEBUG); - } - } + ospf6_lsa_debug_set_all(false); for (i = 0; i < 6; i++) OSPF6_DEBUG_MESSAGE_OFF(i, diff --git a/ospf6d/ospf6_neighbor.h b/ospf6d/ospf6_neighbor.h index f7735b87b9..de59a1ccf5 100644 --- a/ospf6d/ospf6_neighbor.h +++ b/ospf6d/ospf6_neighbor.h @@ -136,6 +136,8 @@ struct ospf6_neighbor { struct thread *thread_send_lsreq; struct thread *thread_send_lsupdate; struct thread *thread_send_lsack; + struct thread *thread_exchange_done; + struct thread *thread_adj_ok; /* BFD information */ struct bfd_session_params *bfd_session; diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c index 809768fb5c..cd1be3a5b7 100644 --- a/ospf6d/ospf6_nssa.c +++ b/ospf6d/ospf6_nssa.c @@ -49,6 +49,9 @@ #include "ospf6_asbr.h" #include "ospf6d.h" #include "ospf6_nssa.h" +#ifndef VTYSH_EXTRACT_PL +#include "ospf6d/ospf6_nssa_clippy.c" +#endif DEFINE_MTYPE_STATIC(OSPF6D, OSPF6_LSA, "OSPF6 LSA"); unsigned char config_debug_ospf6_nssa = 0; @@ -185,12 +188,15 @@ void ospf6_abr_nssa_check_status(struct ospf6 *ospf6) * when they are not translating. */ if (old_state != area->NSSATranslatorState) { - if (old_state == OSPF6_NSSA_TRANSLATE_DISABLED) + if (old_state == OSPF6_NSSA_TRANSLATE_DISABLED) { + ++ospf6->redist_count; ospf6_asbr_status_update(ospf6, - ++ospf6->redist_count); - else + ospf6->redist_count); + } else { + --ospf6->redist_count; ospf6_asbr_status_update(ospf6, - --ospf6->redist_count); + ospf6->redist_count); + } } } } @@ -262,22 +268,20 @@ static void ospf6_abr_announce_aggregates(struct ospf6 *ospf6) { struct ospf6_area *area; struct ospf6_route *range; - struct listnode *node, *nnode; + struct listnode *node; if (IS_OSPF6_DEBUG_ABR) zlog_debug("ospf6_abr_announce_aggregates(): Start"); - for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) { - for (range = ospf6_route_head(area->range_table); range; - range = ospf6_route_next(range)) - ospf6_abr_range_update(range, ospf6); - } - for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) { if (IS_OSPF6_DEBUG_ABR) zlog_debug( "ospf_abr_announce_aggregates(): looking at area %pI4", &area->area_id); + + for (range = ospf6_route_head(area->range_table); range; + range = ospf6_route_next(range)) + ospf6_abr_range_update(range, ospf6); } if (IS_OSPF6_DEBUG_ABR) @@ -381,22 +385,18 @@ static void ospf6_abr_unapprove_translates(struct ospf6 *ospf6) { struct ospf6_lsa *lsa; uint16_t type; - struct ospf6_area *oa; - struct listnode *node; if (IS_OSPF6_DEBUG_NSSA) zlog_debug("ospf6_abr_unapprove_translates(): Start"); type = htons(OSPF6_LSTYPE_AS_EXTERNAL); - for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { - for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) { - if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)) { - SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED); - if (IS_OSPF6_DEBUG_NSSA) - zlog_debug( - "%s : approved unset on link id %pI4", - __func__, &lsa->header->id); - } + for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa)) { + if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT)) { + SET_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED); + if (IS_OSPF6_DEBUG_NSSA) + zlog_debug( + "%s : approved unset on link id %pI4", + __func__, &lsa->header->id); } } @@ -408,17 +408,17 @@ static void ospf6_abr_unapprove_translates(struct ospf6 *ospf6) static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area, struct ospf6_lsa *type7) { - char *buffer; + char buffer[OSPF6_MAX_LSASIZE]; struct ospf6_lsa *lsa; struct ospf6_as_external_lsa *ext, *extnew; struct ospf6_lsa_header *lsa_header; caddr_t old_ptr, new_ptr; struct ospf6_as_external_lsa *nssa; struct prefix prefix; - struct ospf6_route *match; struct ospf6 *ospf6 = area->ospf6; ptrdiff_t tag_offset = 0; route_tag_t network_order; + struct ospf6_route *range; if (IS_OSPF6_DEBUG_NSSA) zlog_debug("%s : Start", __func__); @@ -430,7 +430,27 @@ static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area, return NULL; } - buffer = XCALLOC(MTYPE_OSPF6_LSA, OSPF6_MAX_LSASIZE); + /* find the translated Type-5 for this Type-7 */ + nssa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( + type7->header); + prefix.family = AF_INET6; + prefix.prefixlen = nssa->prefix.prefix_length; + ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa, &nssa->prefix); + + /* Check if the Type-7 LSA should be suppressed by aggregation. */ + range = ospf6_route_lookup_bestmatch(&prefix, area->nssa_range_table); + if (range && !prefix_same(&prefix, &range->prefix) + && !CHECK_FLAG(range->flag, OSPF6_ROUTE_REMOVE)) { + if (IS_OSPF6_DEBUG_NSSA) + zlog_debug( + "%s: LSA %s suppressed by range %pFX of area %s", + __func__, type7->name, &range->prefix, + area->name); + return NULL; + } + + /* prepare buffer */ + memset(buffer, 0, sizeof(buffer)); lsa_header = (struct ospf6_lsa_header *)buffer; extnew = (struct ospf6_as_external_lsa *)((caddr_t)lsa_header @@ -445,23 +465,6 @@ static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area, memcpy(extnew, ext, sizeof(struct ospf6_as_external_lsa)); - /* find the translated Type-5 for this Type-7 */ - nssa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( - type7->header); - - prefix.family = AF_INET6; - prefix.prefixlen = nssa->prefix.prefix_length; - ospf6_prefix_in6_addr(&prefix.u.prefix6, nssa, &nssa->prefix); - - /* Find the LSA from the external route */ - match = ospf6_route_lookup(&prefix, area->route_table); - if (match == NULL) { - if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("%s : no matching route %pFX", __func__, - &prefix); - return NULL; - } - /* set Prefix */ memcpy(new_ptr, old_ptr, OSPF6_PREFIX_SPACE(ext->prefix.prefix_length)); ospf6_prefix_apply_mask(&extnew->prefix); @@ -542,7 +545,6 @@ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area, struct ospf6_lsa *type5) { struct ospf6_lsa *new = NULL; - struct ospf6_as_external_lsa *ext_lsa; struct prefix prefix; struct ospf6 *ospf6 = area->ospf6; @@ -554,27 +556,27 @@ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area, /* Find the AS external LSA */ if (type5 == NULL) { + struct ospf6_as_external_lsa *ext_lsa; + struct ospf6_route *match; + + /* Find the AS external LSA from Type-7 LSA */ if (IS_OSPF6_DEBUG_NSSA) zlog_debug( - "%s: No translated Type-5 found for Type-7 with Id %pI4", - __func__, &type7->header->id); + "%s: try to find translated Type-5 LSA for %s", + __func__, type7->name); - /* find the translated Type-5 for this Type-7 */ ext_lsa = (struct ospf6_as_external_lsa *)OSPF6_LSA_HEADER_END( type7->header); - prefix.family = AF_INET6; prefix.prefixlen = ext_lsa->prefix.prefix_length; ospf6_prefix_in6_addr(&prefix.u.prefix6, ext_lsa, &ext_lsa->prefix); - /* Find the AS external LSA from Type-7 LSA */ - if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("%s: try to find external LSA id %d", - __func__, type7->external_lsa_id); - type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), - type7->external_lsa_id, - ospf6->router_id, ospf6->lsdb); + match = ospf6_route_lookup(&prefix, ospf6->external_table); + if (match) + type5 = ospf6_lsdb_lookup( + OSPF6_LSTYPE_AS_EXTERNAL, match->path.origin.id, + ospf6->router_id, ospf6->lsdb); } if (type5) { @@ -602,6 +604,7 @@ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area, __func__, &type7->header->id); return NULL; } + UNSET_FLAG(new->flag, OSPF6_LSA_UNAPPROVED); } if (IS_OSPF6_DEBUG_NSSA) @@ -610,32 +613,11 @@ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area, return new; } -/* Originate Translated Type-5 for supplied Type-7 NSSA LSA */ -struct ospf6_lsa *ospf6_translated_nssa_originate(struct ospf6_area *oa, - struct ospf6_lsa *type7) -{ - struct ospf6_lsa *new; - - if (ntohs(type7->header->type) != OSPF6_LSTYPE_TYPE_7) - return NULL; - - if ((new = ospf6_lsa_translated_nssa_new(oa, type7)) == NULL) { - if (IS_OSPF6_DEBUG_NSSA) - zlog_debug( - "%s : Could not translate Type-7, Id %pI4, to Type-5", - __func__, &type7->header->id); - return NULL; - } - - return new; -} - -int ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa) +static void ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa) { /* Incoming Type-7 or later aggregated Type-7 * * LSA is skipped if P-bit is off. - * LSA is aggregated if within range. * * The Type-7 is translated, Installed/Approved as a Type-5 into * global LSDB, then Flooded through AS @@ -659,7 +641,7 @@ int ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa) zlog_debug( "%s : LSA Id %pI4, P-bit off, NO Translation", __func__, &lsa->header->id); - return 1; + return; } if (IS_OSPF6_DEBUG_NSSA) @@ -676,7 +658,7 @@ int ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa) zlog_debug( "%s : LSA Id %pI4, Forward address is 0, NO Translation", __func__, &lsa->header->id); - return 1; + return; } /* Find the existing AS-External LSA for this prefix */ @@ -687,23 +669,13 @@ int ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa) ospf6->lsdb); } - /* Check Type 5 LSA using the matching external ID */ - if (old == NULL) { - old = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), - lsa->external_lsa_id, ospf6->router_id, - ospf6->lsdb); + if (OSPF6_LSA_IS_MAXAGE(lsa)) { + if (old) + ospf6_lsa_premature_aging(old); + return; } if (old) { - /* Do not continue if type 5 LSA not approved */ - if (CHECK_FLAG(old->flag, OSPF6_LSA_UNAPPROVED)) { - if (IS_OSPF6_DEBUG_NSSA) - zlog_debug( - "%s : LSA Id %pI4 type 5 is not approved", - __func__, &old->header->id); - return 1; - } - if (IS_OSPF6_DEBUG_NSSA) zlog_debug( "%s : found old translated LSA Id %pI4, refreshing", @@ -722,16 +694,14 @@ int ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa) * originate translated LSA */ - if (ospf6_translated_nssa_originate(area, lsa) == NULL) { + if (ospf6_lsa_translated_nssa_new(area, lsa) == NULL) { if (IS_OSPF6_DEBUG_NSSA) zlog_debug( "%s : Could not translate Type-7 for %pI4 to Type-5", __func__, &lsa->header->id); - return 1; + return; } } - - return 0; } static void ospf6_abr_process_nssa_translates(struct ospf6 *ospf6) @@ -751,6 +721,8 @@ static void ospf6_abr_process_nssa_translates(struct ospf6 *ospf6) zlog_debug("%s : Start", __func__); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, oa)) { + if (!IS_AREA_NSSA(oa)) + continue; /* skip if not translator */ if (oa->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED) { @@ -760,13 +732,6 @@ static void ospf6_abr_process_nssa_translates(struct ospf6 *ospf6) continue; } - /* skip if not Nssa Area */ - if (!IS_AREA_NSSA(oa)) { - zlog_debug("%s area %pI4 Flag %x", __func__, - &oa->area_id, oa->flag); - continue; - } - if (IS_OSPF6_DEBUG_NSSA) zlog_debug("%s : looking at area %pI4", __func__, &oa->area_id); @@ -784,71 +749,30 @@ static void ospf6_abr_process_nssa_translates(struct ospf6 *ospf6) zlog_debug("%s : Stop", __func__); } -/* Generate translated type-5 LSA from the configured area ranges*/ -static void ospf6_abr_translate_nssa_range(struct ospf6 *ospf6) -{ - struct listnode *node, *nnode; - struct ospf6_area *oa; - struct ospf6_route *range; - struct ospf6_lsa *lsa; - - for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, oa)) { - for (range = ospf6_route_head(oa->range_table); range; - range = ospf6_route_next(range)) { - if (IS_OSPF6_DEBUG_NSSA) - zlog_debug( - "Translating range %pFX of area %pI4", - &range->prefix, &oa->area_id); - if (CHECK_FLAG(range->flag, - OSPF6_ROUTE_DO_NOT_ADVERTISE)) - continue; - - /* Find the NSSA LSA from the route */ - /* Generate and flood external LSA */ - lsa = ospf6_lsdb_lookup(OSPF6_LSTYPE_TYPE_7, - range->path.origin.id, - ospf6->router_id, oa->lsdb); - if (lsa) - ospf6_abr_translate_nssa(oa, lsa); - } - } -} - static void ospf6_abr_send_nssa_aggregates(struct ospf6 *ospf6) { struct listnode *node; struct ospf6_area *area; + struct ospf6_route *range; if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("%s : Start", __func__); + zlog_debug("%s: Start", __func__); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) { if (area->NSSATranslatorState == OSPF6_NSSA_TRANSLATE_DISABLED) continue; if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("%s : looking at area %pI4", __func__, + zlog_debug("%s: looking at area %pI4", __func__, &area->area_id); - ospf6_abr_translate_nssa_range(ospf6); + for (range = ospf6_route_head(area->nssa_range_table); range; + range = ospf6_route_next(range)) + ospf6_abr_range_update(range, ospf6); } if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("%s : Stop", __func__); -} - -/*Flood max age LSA's for the unapproved LSA's */ -static int ospf6_abr_remove_unapproved_translates_apply(struct ospf6_lsa *lsa) -{ - if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT) - && CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED)) { - zlog_debug("%s : removing unapproved translates, lsa : %s", - __func__, lsa->name); - - /* FLUSH THROUGHOUT AS */ - ospf6_lsa_premature_aging(lsa); - } - return 0; + zlog_debug("%s: Stop", __func__); } static void ospf6_abr_remove_unapproved_translates(struct ospf6 *ospf6) @@ -862,8 +786,16 @@ static void ospf6_abr_remove_unapproved_translates(struct ospf6 *ospf6) zlog_debug("ospf6_abr_remove_unapproved_translates(): Start"); type = htons(OSPF6_LSTYPE_AS_EXTERNAL); - for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa)) - ospf6_abr_remove_unapproved_translates_apply(lsa); + for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa)) { + if (CHECK_FLAG(lsa->flag, OSPF6_LSA_LOCAL_XLT) + && CHECK_FLAG(lsa->flag, OSPF6_LSA_UNAPPROVED)) { + zlog_debug( + "%s : removing unapproved translates, lsa : %s", + __func__, lsa->name); + + ospf6_lsa_premature_aging(lsa); + } + } if (IS_OSPF6_DEBUG_NSSA) zlog_debug("ospf_abr_remove_unapproved_translates(): Stop"); @@ -948,11 +880,6 @@ void ospf6_abr_nssa_type_7_defaults(struct ospf6 *ospf6) static void ospf6_abr_nssa_task(struct ospf6 *ospf6) { - /* called only if any_nssa */ - struct ospf6_route *range; - struct ospf6_area *area; - struct listnode *node, *nnode; - if (IS_OSPF6_DEBUG_NSSA) zlog_debug("Check for NSSA-ABR Tasks():"); @@ -978,10 +905,10 @@ static void ospf6_abr_nssa_task(struct ospf6 *ospf6) ospf6_abr_unapprove_translates(ospf6); - /* RESET all Ranges in every Area, same as summaries */ + /* Originate Type-7 aggregates */ if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_nssa_task(): NSSA initialize aggregates"); - ospf6_abr_range_reset_cost(ospf6); + zlog_debug("ospf6_abr_nssa_task(): send NSSA aggregates"); + ospf6_abr_send_nssa_aggregates(ospf6); /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or * Aggregate as Type-7 @@ -991,32 +918,12 @@ static void ospf6_abr_nssa_task(struct ospf6 *ospf6) zlog_debug("ospf6_abr_nssa_task(): process translates"); ospf6_abr_process_nssa_translates(ospf6); - /* Translate/Send any "ranged" aggregates, and also 5-Install and - * Approve - * Scan Type-7's for aggregates, translate to Type-5's, - * Install/Flood/Approve - */ - if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_nssa_task(): send NSSA aggregates"); - ospf6_abr_send_nssa_aggregates(ospf6); /*TURNED OFF FOR NOW */ - /* Flush any unapproved previous translates from Global Data Base */ if (IS_OSPF6_DEBUG_NSSA) zlog_debug( "ospf6_abr_nssa_task(): remove unapproved translates"); ospf6_abr_remove_unapproved_translates(ospf6); - for (ALL_LIST_ELEMENTS(ospf6->area_list, node, nnode, area)) { - for (range = ospf6_route_head(area->range_table); range; - range = ospf6_route_next(range)) { - if (CHECK_FLAG(range->flag, - OSPF6_ROUTE_DO_NOT_ADVERTISE)) - ospf6_zebra_delete_discard(range, ospf6); - else - ospf6_zebra_add_discard(range, ospf6); - } - } - if (IS_OSPF6_DEBUG_NSSA) zlog_debug("ospf6_abr_nssa_task(): Stop"); } @@ -1063,113 +970,11 @@ int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route, return 1; } -static void ospf6_external_lsa_refresh_type(struct ospf6 *ospf6, uint8_t type, - unsigned short instance, int force) -{ - struct ospf6_route *route; - struct ospf6_external_info *info; - struct ospf6_lsa *lsa; - - if (type == ZEBRA_ROUTE_MAX) - return; - - for (route = ospf6_route_head(ospf6->external_table); route; - route = ospf6_route_next(route)) { - info = route->route_option; - - /* Find the external LSA in the database */ - if (!is_default_prefix(&route->prefix)) { - lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), - htonl(info->id), - ospf6->router_id, ospf6->lsdb); - - if (lsa) { - THREAD_OFF(lsa->refresh); - - /* LSA is maxage, immediate refresh */ - if (OSPF6_LSA_IS_MAXAGE(lsa)) - ospf6_flood(NULL, lsa); - else - thread_add_timer(master, - ospf6_lsa_refresh, lsa, - OSPF_LS_REFRESH_TIME, - &lsa->refresh); - } else { - /* LSA not found in the database - * Verify and originate external LSA - */ - if (ospf6_redistribute_check(ospf6, route, - type)) - ospf6_as_external_lsa_originate(route, - ospf6); - } - } - } -} - -/* Refresh default route */ -static void ospf6_external_lsa_refresh_default(struct ospf6 *ospf6) -{ - struct ospf6_route *route; - struct ospf6_external_info *info; - struct ospf6_lsa *lsa; - - for (route = ospf6_route_head(ospf6->external_table); route; - route = ospf6_route_next(route)) { - if (is_default_prefix(&route->prefix)) { - info = route->route_option; - lsa = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), - htonl(info->id), - ospf6->router_id, ospf6->lsdb); - - if (lsa) { - if (IS_OSPF6_DEBUG_NSSA) - zlog_debug( - "LSA[Type5:0.0.0.0]: Refresh AS-external-LSA %p", - (void *)lsa); - if (OSPF6_LSA_IS_MAXAGE(lsa)) - ospf6_flood(NULL, lsa); - else - thread_add_timer(master, - ospf6_lsa_refresh, lsa, - OSPF_LS_REFRESH_TIME, - &lsa->refresh); - } else if (!lsa) { - if (IS_OSPF6_DEBUG_NSSA) - zlog_debug( - "LSA[Type5:0.0.0.0]: Originate AS-external-LSA"); - ospf6_as_external_lsa_originate(route, ospf6); - } - } - } -} - -/* If there's redistribution configured, we need to refresh external - * LSAs in order to install Type-7 and flood to all NSSA Areas - */ -void ospf6_asbr_nssa_redist_task(struct ospf6 *ospf6) -{ - int type; - struct ospf6_redist *red; - - for (type = 0; type < ZEBRA_ROUTE_MAX; type++) { - red = ospf6_redist_lookup(ospf6, type, 0); - if (!red) - return; - - ospf6_external_lsa_refresh_type(ospf6, type, red->instance, - LSA_REFRESH_IF_CHANGED); - } - ospf6_external_lsa_refresh_default(ospf6); -} - /* This function performs ABR related processing */ static int ospf6_abr_task_timer(struct thread *thread) { struct ospf6 *ospf6 = THREAD_ARG(thread); - ospf6->t_abr_task = NULL; - if (IS_OSPF6_DEBUG_ABR) zlog_debug("Running ABR task on timer"); @@ -1178,7 +983,6 @@ static int ospf6_abr_task_timer(struct thread *thread) ospf6_abr_task(ospf6); /* if nssa-abr, then scan Type-7 LSDB */ ospf6_abr_nssa_task(ospf6); - ospf6_asbr_nssa_redist_task(ospf6); return 0; } @@ -1339,6 +1143,13 @@ int ospf6_area_nssa_unset(struct ospf6 *ospf6, struct ospf6_area *area) UNSET_FLAG(area->flag, OSPF6_AREA_NSSA); if (IS_OSPF6_DEBUG_NSSA) zlog_debug("area %s nssa reset", area->name); + + /* Clear the table of NSSA ranges. */ + ospf6_route_table_delete(area->nssa_range_table); + area->nssa_range_table = + OSPF6_ROUTE_TABLE_CREATE(AREA, PREFIX_RANGES); + area->nssa_range_table->scope = area; + ospf6_area_nssa_update(area); } @@ -1352,10 +1163,14 @@ static struct in6_addr *ospf6_get_nssa_fwd_addr(struct ospf6_area *oa) struct ospf6_interface *oi; for (ALL_LIST_ELEMENTS(oa->if_list, node, nnode, oi)) { - if (if_is_operative(oi->interface)) - if (oi->area && IS_AREA_NSSA(oi->area)) - return ospf6_interface_get_global_address( - oi->interface); + struct in6_addr *addr; + + if (!if_is_operative(oi->interface)) + continue; + + addr = ospf6_interface_get_global_address(oi->interface); + if (addr) + return addr; } return NULL; } @@ -1465,17 +1280,119 @@ void ospf6_abr_check_translate_nssa(struct ospf6_area *area, if (IS_OSPF6_DEBUG_NSSA) zlog_debug("%s : start", __func__); + if (!ospf6_check_and_set_router_abr(ospf6)) + return; + type5 = ospf6_lsdb_lookup(htons(OSPF6_LSTYPE_AS_EXTERNAL), lsa->external_lsa_id, ospf6->router_id, ospf6->lsdb); - - if (ospf6_check_and_set_router_abr(ospf6) && (type5 == NULL)) { + if (!type5) { if (IS_OSPF6_DEBUG_NSSA) zlog_debug("%s : Originating type5 LSA", __func__); ospf6_lsa_translated_nssa_new(area, lsa); } } +DEFPY (area_nssa_range, + area_nssa_range_cmd, + "area <A.B.C.D|(0-4294967295)>$area nssa range X:X::X:X/M$prefix [<not-advertise$not_adv|cost (0-16777215)$cost>]", + "OSPF6 area parameters\n" + "OSPF6 area ID in IP address format\n" + "OSPF6 area ID as a decimal value\n" + "Configure OSPF6 area as nssa\n" + "Configured address range\n" + "Specify IPv6 prefix\n" + "Do not advertise\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") +{ + struct ospf6_area *oa; + struct ospf6_route *range; + + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + OSPF6_CMD_AREA_GET(area, oa, ospf6); + + if (!IS_AREA_NSSA(oa)) { + vty_out(vty, "%% First configure %s as an NSSA area\n", area); + return CMD_WARNING; + } + + range = ospf6_route_lookup((struct prefix *)prefix, + oa->nssa_range_table); + if (range == NULL) { + range = ospf6_route_create(ospf6); + range->type = OSPF6_DEST_TYPE_RANGE; + SET_FLAG(range->flag, OSPF6_ROUTE_NSSA_RANGE); + prefix_copy(&range->prefix, prefix); + range->path.area_id = oa->area_id; + range->path.metric_type = 2; + range->path.cost = OSPF_AREA_RANGE_COST_UNSPEC; + range->path.origin.type = htons(OSPF6_LSTYPE_TYPE_7); + range->path.origin.id = htonl(ospf6->external_id++); + range->path.origin.adv_router = ospf6->router_id; + ospf6_route_add(range, oa->nssa_range_table); + } + + /* process "not-advertise" */ + if (not_adv) + SET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); + else + UNSET_FLAG(range->flag, OSPF6_ROUTE_DO_NOT_ADVERTISE); + + /* process "cost" */ + if (!cost_str) + cost = OSPF_AREA_RANGE_COST_UNSPEC; + range->path.u.cost_config = cost; + + /* Redo summaries if required */ + if (ospf6_check_and_set_router_abr(ospf6)) + ospf6_schedule_abr_task(ospf6); + + return CMD_SUCCESS; +} + +DEFPY (no_area_nssa_range, + no_area_nssa_range_cmd, + "no area <A.B.C.D|(0-4294967295)>$area nssa range X:X::X:X/M$prefix [<not-advertise|cost (0-16777215)>]", + NO_STR + "OSPF6 area parameters\n" + "OSPF6 area ID in IP address format\n" + "OSPF6 area ID as a decimal value\n" + "Configure OSPF6 area as nssa\n" + "Configured address range\n" + "Specify IPv6 prefix\n" + "Do not advertise\n" + "User specified metric for this range\n" + "Advertised metric for this range\n") +{ + struct ospf6_area *oa; + struct ospf6_route *range; + + VTY_DECLVAR_CONTEXT(ospf6, ospf6); + + OSPF6_CMD_AREA_GET(area, oa, ospf6); + + range = ospf6_route_lookup((struct prefix *)prefix, + oa->nssa_range_table); + if (range == NULL) { + vty_out(vty, "%% range %s does not exists.\n", prefix_str); + return CMD_SUCCESS; + } + + if (ospf6_check_and_set_router_abr(oa->ospf6)) { + /* Blow away the aggregated LSA and route */ + SET_FLAG(range->flag, OSPF6_ROUTE_REMOVE); + + /* Redo summaries if required */ + thread_execute(master, ospf6_abr_task_timer, ospf6, 0); + } + + ospf6_route_remove(range, oa->nssa_range_table); + + return CMD_SUCCESS; +} + DEFUN(debug_ospf6_nssa, debug_ospf6_nssa_cmd, "debug ospf6 nssa", DEBUG_STR @@ -1505,6 +1422,9 @@ void config_write_ospf6_debug_nssa(struct vty *vty) void install_element_ospf6_debug_nssa(void) { + install_element(OSPF6_NODE, &area_nssa_range_cmd); + install_element(OSPF6_NODE, &no_area_nssa_range_cmd); + install_element(ENABLE_NODE, &debug_ospf6_nssa_cmd); install_element(ENABLE_NODE, &no_debug_ospf6_nssa_cmd); install_element(CONFIG_NODE, &debug_ospf6_nssa_cmd); diff --git a/ospf6d/ospf6_nssa.h b/ospf6d/ospf6_nssa.h index 99cb04c003..02234cc8bd 100644 --- a/ospf6d/ospf6_nssa.h +++ b/ospf6d/ospf6_nssa.h @@ -55,8 +55,6 @@ extern void ospf6_nssa_lsa_flush(struct ospf6 *ospf6, struct prefix_ipv6 *p); extern struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *oa, struct ospf6_lsa *type7, struct ospf6_lsa *type5); -extern struct ospf6_lsa * -ospf6_translated_nssa_originate(struct ospf6_area *oa, struct ospf6_lsa *type7); extern void ospf6_asbr_nssa_redist_task(struct ospf6 *ospf6); @@ -69,8 +67,6 @@ extern void install_element_ospf6_debug_nssa(void); extern void ospf6_abr_nssa_type_7_defaults(struct ospf6 *osof6); int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route, int type); -extern int ospf6_abr_translate_nssa(struct ospf6_area *area, - struct ospf6_lsa *lsa); extern void ospf6_abr_check_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa); extern void ospf6_abr_nssa_check_status(struct ospf6 *ospf6); diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 4b87c4cf30..f5d60d80fa 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -580,9 +580,7 @@ ospf6_route_lookup_identical(struct ospf6_route *route, for (target = ospf6_route_lookup(&route->prefix, table); target; target = target->next) { if (target->type == route->type - && (memcmp(&target->prefix, &route->prefix, - sizeof(struct prefix)) - == 0) + && prefix_same(&target->prefix, &route->prefix) && target->path.type == route->path.type && target->path.cost == route->path.cost && target->path.u.cost_e2 == route->path.u.cost_e2 @@ -706,27 +704,6 @@ struct ospf6_route *ospf6_route_add(struct ospf6_route *route, } if (old) { - /* if route does not actually change, return unchanged */ - if (ospf6_route_is_identical(old, route)) { - if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) - zlog_debug( - "%s %p: route add %p: needless update of %p old cost %u", - ospf6_route_table_name(table), - (void *)table, (void *)route, - (void *)old, old->path.cost); - else if (IS_OSPF6_DEBUG_ROUTE(TABLE)) - zlog_debug("%s: route add: needless update", - ospf6_route_table_name(table)); - - ospf6_route_delete(route); - SET_FLAG(old->flag, OSPF6_ROUTE_ADD); - ospf6_route_table_assert(table); - - /* to free the lookup lock */ - route_unlock_node(node); - return old; - } - if (IS_OSPF6_DEBUG_ROUTE(MEMORY)) zlog_debug( "%s %p: route add %p cost %u paths %u nh %u: update of %p cost %u paths %u nh %u", @@ -1098,7 +1075,6 @@ struct ospf6_route_table *ospf6_route_table_create(int s, int t) void ospf6_route_table_delete(struct ospf6_route_table *table) { ospf6_route_remove_all(table); - bf_free(table->idspace); route_table_finish(table->table); XFREE(MTYPE_OSPF6_ROUTE_TABLE, table); } @@ -1117,6 +1093,7 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route, json_object *json_route = NULL; json_object *json_array_next_hops = NULL; json_object *json_next_hop; + vrf_id_t vrf_id = route->ospf6->vrf_id; monotime(&now); timersub(&now, &route->changed, &res); @@ -1150,16 +1127,15 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route, else i = 0; for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) { - struct interface *ifp; /* nexthop */ inet_ntop(AF_INET6, &nh->address, nexthop, sizeof(nexthop)); - ifp = if_lookup_by_index_all_vrf(nh->ifindex); if (use_json) { json_next_hop = json_object_new_object(); json_object_string_add(json_next_hop, "nextHop", nexthop); - json_object_string_add(json_next_hop, "interfaceName", - ifp->name); + json_object_string_add( + json_next_hop, "interfaceName", + ifindex2ifname(nh->ifindex, vrf_id)); json_object_array_add(json_array_next_hops, json_next_hop); } else { @@ -1171,12 +1147,14 @@ void ospf6_route_show(struct vty *vty, struct ospf6_route *route, OSPF6_PATH_TYPE_SUBSTR( route->path.type), destination, nexthop, IFNAMSIZ, - ifp->name, duration); + ifindex2ifname(nh->ifindex, vrf_id), + duration); i++; } else vty_out(vty, "%c%1s %2s %-30s %-25s %6.*s %s\n", ' ', "", "", "", nexthop, IFNAMSIZ, - ifp->name, ""); + ifindex2ifname(nh->ifindex, vrf_id), + ""); } } if (use_json) { @@ -1200,6 +1178,7 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route, json_object *json_route = NULL; json_object *json_array_next_hops = NULL; json_object *json_next_hop; + vrf_id_t vrf_id = route->ospf6->vrf_id; monotime(&now); @@ -1350,8 +1329,6 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route, vty_out(vty, "Nexthop:\n"); for (ALL_LIST_ELEMENTS_RO(route->nh_list, node, nh)) { - struct interface *ifp; - ifp = if_lookup_by_index_all_vrf(nh->ifindex); /* nexthop */ if (use_json) { inet_ntop(AF_INET6, &nh->address, nexthop, @@ -1359,13 +1336,14 @@ void ospf6_route_show_detail(struct vty *vty, struct ospf6_route *route, json_next_hop = json_object_new_object(); json_object_string_add(json_next_hop, "nextHop", nexthop); - json_object_string_add(json_next_hop, "interfaceName", - ifp->name); + json_object_string_add( + json_next_hop, "interfaceName", + ifindex2ifname(nh->ifindex, vrf_id)); json_object_array_add(json_array_next_hops, json_next_hop); } else vty_out(vty, " %pI6 %.*s\n", &nh->address, IFNAMSIZ, - ifp->name); + ifindex2ifname(nh->ifindex, vrf_id)); } if (use_json) { json_object_object_add(json_route, "nextHops", @@ -1632,12 +1610,8 @@ int ospf6_route_table_show(struct vty *vty, int argc_start, int argc, /* Give summary of this route table */ if (summary) { ospf6_route_show_table_summary(vty, table, json, use_json); - if (use_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); return CMD_SUCCESS; } @@ -1651,12 +1625,8 @@ int ospf6_route_table_show(struct vty *vty, int argc_start, int argc, ospf6_route_show_table_prefix(vty, &prefix, table, json, use_json); - if (use_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); return CMD_SUCCESS; } @@ -1669,12 +1639,8 @@ int ospf6_route_table_show(struct vty *vty, int argc_start, int argc, else ospf6_route_show_table(vty, detail, table, json, use_json); - if (use_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); return CMD_SUCCESS; } diff --git a/ospf6d/ospf6_route.h b/ospf6d/ospf6_route.h index e29439b95e..633b8d77cd 100644 --- a/ospf6d/ospf6_route.h +++ b/ospf6d/ospf6_route.h @@ -186,7 +186,7 @@ struct ospf6_route { struct timeval changed; /* flag */ - uint8_t flag; + uint16_t flag; /* Prefix Options */ uint8_t prefix_options; @@ -221,14 +221,15 @@ struct ospf6_route { #define OSPF6_DEST_TYPE_RANGE 5 #define OSPF6_DEST_TYPE_MAX 6 -#define OSPF6_ROUTE_CHANGE 0x01 -#define OSPF6_ROUTE_ADD 0x02 -#define OSPF6_ROUTE_REMOVE 0x04 -#define OSPF6_ROUTE_BEST 0x08 -#define OSPF6_ROUTE_ACTIVE_SUMMARY 0x10 -#define OSPF6_ROUTE_DO_NOT_ADVERTISE 0x20 -#define OSPF6_ROUTE_WAS_REMOVED 0x40 -#define OSPF6_ROUTE_BLACKHOLE_ADDED 0x80 +#define OSPF6_ROUTE_CHANGE 0x0001 +#define OSPF6_ROUTE_ADD 0x0002 +#define OSPF6_ROUTE_REMOVE 0x0004 +#define OSPF6_ROUTE_BEST 0x0008 +#define OSPF6_ROUTE_ACTIVE_SUMMARY 0x0010 +#define OSPF6_ROUTE_DO_NOT_ADVERTISE 0x0020 +#define OSPF6_ROUTE_WAS_REMOVED 0x0040 +#define OSPF6_ROUTE_BLACKHOLE_ADDED 0x0080 +#define OSPF6_ROUTE_NSSA_RANGE 0x0100 struct ospf6; struct ospf6_route_table { @@ -241,8 +242,6 @@ struct ospf6_route_table { uint32_t count; - bitfield_t idspace; - /* hooks */ void (*hook_add)(struct ospf6_route *); void (*hook_change)(struct ospf6_route *); @@ -292,20 +291,13 @@ extern const char *const ospf6_path_type_substr[OSPF6_PATH_TYPE_MAX]; #define OSPF6_ROUTE_PREFIX_STR "Display the route\n" #define OSPF6_ROUTE_MATCH_STR "Display the route matches the prefix\n" -#define ospf6_route_is_prefix(p, r) \ - (memcmp(p, &(r)->prefix, sizeof(struct prefix)) == 0) +#define ospf6_route_is_prefix(p, r) (prefix_same(p, &(r)->prefix)) #define ospf6_route_is_same(ra, rb) (prefix_same(&(ra)->prefix, &(rb)->prefix)) #define ospf6_route_is_same_origin(ra, rb) \ ((ra)->path.area_id == (rb)->path.area_id \ - && memcmp(&(ra)->path.origin, &(rb)->path.origin, \ - sizeof(struct ospf6_ls_origin)) \ - == 0) -#define ospf6_route_is_identical(ra, rb) \ - ((ra)->type == (rb)->type \ - && memcmp(&(ra)->prefix, &(rb)->prefix, sizeof(struct prefix)) == 0 \ - && memcmp(&(ra)->path, &(rb)->path, sizeof(struct ospf6_path)) == 0 \ - && listcount(ra->paths) == listcount(rb->paths) \ - && ospf6_route_cmp_nexthops(ra, rb) == 0) + && (ra)->path.origin.type == (rb)->path.origin.type \ + && (ra)->path.origin.id == (rb)->path.origin.id \ + && (ra)->path.origin.adv_router == (rb)->path.origin.adv_router) #define ospf6_route_is_best(r) (CHECK_FLAG ((r)->flag, OSPF6_ROUTE_BEST)) diff --git a/ospf6d/ospf6_snmp.c b/ospf6d/ospf6_snmp.c index 92922567e8..1070474d0f 100644 --- a/ospf6d/ospf6_snmp.c +++ b/ospf6d/ospf6_snmp.c @@ -971,8 +971,7 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length, for (ALL_LIST_ELEMENTS_RO(ifslist, node, iif)) { if (!iif->ifindex) continue; - oi = ospf6_interface_lookup_by_ifindex( - iif->ifindex, iif->vrf_id); + oi = iif->info; if (!oi) continue; if (iif->ifindex < ifindex) @@ -1039,7 +1038,6 @@ static uint8_t *ospfv3WwLsdbEntry(struct variable *v, oid *name, size_t *length, return SNMP_INTEGER(OSPF6_LSA_IS_KNOWN(lsa->header->type) ? SNMP_TRUE : SNMP_FALSE); - break; } return NULL; } @@ -1107,8 +1105,7 @@ static uint8_t *ospfv3IfEntry(struct variable *v, oid *name, size_t *length, for (ALL_LIST_ELEMENTS_RO(ifslist, i, iif)) { if (!iif->ifindex) continue; - oi = ospf6_interface_lookup_by_ifindex(iif->ifindex, - iif->vrf_id); + oi = iif->info; if (!oi) continue; if (iif->ifindex > ifindex @@ -1273,8 +1270,7 @@ static uint8_t *ospfv3NbrEntry(struct variable *v, oid *name, size_t *length, for (ALL_LIST_ELEMENTS_RO(ifslist, i, iif)) { if (!iif->ifindex) continue; - oi = ospf6_interface_lookup_by_ifindex(iif->ifindex, - iif->vrf_id); + oi = iif->info; if (!oi) continue; for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, j, on)) { diff --git a/ospf6d/ospf6_spf.c b/ospf6d/ospf6_spf.c index a9bd7febcf..f9c47cbce5 100644 --- a/ospf6d/ospf6_spf.c +++ b/ospf6d/ospf6_spf.c @@ -461,6 +461,10 @@ void ospf6_spf_reason_string(uint32_t reason, char *buf, int size) if (!buf) return; + if (!reason) { + buf[0] = '\0'; + return; + } for (bit = 0; bit < array_size(ospf6_spf_reason_str); bit++) { if ((reason & (1 << bit)) && (len < size)) { len += snprintf((buf + len), (size - len), "%s%s", diff --git a/ospf6d/ospf6_top.c b/ospf6d/ospf6_top.c index 6fe7055202..6bff52fc56 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -423,7 +423,6 @@ static struct ospf6 *ospf6_create(const char *name) * 1::1, this happened because of LS ID 0. */ o->external_id = OSPF6_EXT_INIT_LS_ID; - o->external_id_table = route_table_init(); o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT; o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; @@ -432,7 +431,6 @@ static struct ospf6 *ospf6_create(const char *name) o->rt_aggr_tbl = route_table_init(); o->aggr_delay_interval = OSPF6_EXTL_AGGR_DEFAULT_DELAY; - o->t_external_aggr = NULL; o->aggr_action = OSPF6_ROUTE_AGGR_NONE; o->fd = -1; @@ -516,7 +514,6 @@ void ospf6_delete(struct ospf6 *o) ospf6_route_table_delete(o->brouter_table); ospf6_route_table_delete(o->external_table); - route_table_finish(o->external_id_table); ospf6_distance_reset(o); route_table_finish(o->distance_table); @@ -563,6 +560,8 @@ static void ospf6_disable(struct ospf6 *o) THREAD_OFF(o->t_ospf6_receive); THREAD_OFF(o->t_external_aggr); THREAD_OFF(o->gr_info.t_grace_period); + THREAD_OFF(o->t_write); + THREAD_OFF(o->t_abr_task); } } @@ -584,8 +583,6 @@ static int ospf6_maxage_remover(struct thread *thread) struct listnode *i, *j, *k; int reschedule = 0; - o->maxage_remover = (struct thread *)NULL; - for (ALL_LIST_ELEMENTS_RO(o->area_list, i, oa)) { for (ALL_LIST_ELEMENTS_RO(oa->if_list, j, oi)) { for (ALL_LIST_ELEMENTS_RO(oi->neighbor_list, k, on)) { @@ -1033,7 +1030,6 @@ DEFUN_HIDDEN (ospf6_interface_area, struct ospf6_area *oa; struct ospf6_interface *oi; struct interface *ifp; - vrf_id_t vrf_id = VRF_DEFAULT; uint32_t area_id; int format; @@ -1042,11 +1038,8 @@ DEFUN_HIDDEN (ospf6_interface_area, vty_out(vty, "Please, use \"ipv6 ospf6 area\" on an interface instead.\n"); - if (ospf6->vrf_id != VRF_UNKNOWN) - vrf_id = ospf6->vrf_id; - /* find/create ospf6 interface */ - ifp = if_get_by_name(argv[idx_ifname]->arg, vrf_id); + ifp = if_get_by_name(argv[idx_ifname]->arg, ospf6->vrf_id, ospf6->name); oi = (struct ospf6_interface *)ifp->info; if (oi == NULL) oi = ospf6_interface_create(ifp); @@ -1108,18 +1101,14 @@ DEFUN_HIDDEN (no_ospf6_interface_area, struct ospf6_area *oa; struct interface *ifp; uint32_t area_id; - vrf_id_t vrf_id = VRF_DEFAULT; vty_out(vty, "This command is deprecated, because it is not VRF-aware.\n"); vty_out(vty, "Please, use \"no ipv6 ospf6 area\" on an interface instead.\n"); - if (ospf6->vrf_id != VRF_UNKNOWN) - vrf_id = ospf6->vrf_id; - /* find/create ospf6 interface */ - ifp = if_get_by_name(argv[idx_ifname]->arg, vrf_id); + ifp = if_get_by_name(argv[idx_ifname]->arg, ospf6->vrf_id, ospf6->name); if (ifp == NULL) { vty_out(vty, "No such interface %s\n", argv[idx_ifname]->arg); @@ -1491,9 +1480,8 @@ DEFUN(show_ipv6_ospf6_vrfs, show_ipv6_ospf6_vrfs_cmd, if (uj) { json_object_int_add(json_vrf, "vrfId", vrf_id_ui); - json_object_string_add(json_vrf, "routerId", - inet_ntop(AF_INET, &router_id, - buf, sizeof(buf))); + json_object_string_addf(json_vrf, "routerId", "%pI4", + &router_id); json_object_object_add(json_vrfs, name, json_vrf); } else { @@ -1508,10 +1496,7 @@ DEFUN(show_ipv6_ospf6_vrfs, show_ipv6_ospf6_vrfs_cmd, json_object_object_add(json, "vrfs", json_vrfs); json_object_int_add(json, "totalVrfs", count); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { if (count) vty_out(vty, "\nTotal number of OSPF VRFs: %d\n", @@ -2103,9 +2088,7 @@ DEFPY (show_ipv6_ospf6_external_aggregator, } if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } return CMD_SUCCESS; @@ -2113,9 +2096,8 @@ DEFPY (show_ipv6_ospf6_external_aggregator, static void ospf6_stub_router_config_write(struct vty *vty, struct ospf6 *ospf6) { - if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) { + if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) vty_out(vty, " stub-router administrative\n"); - } return; } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 55cab72307..4cc0923e93 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -136,7 +136,6 @@ struct ospf6 { struct ospf6_route_table *brouter_table; struct ospf6_route_table *external_table; - struct route_table *external_id_table; #define OSPF6_EXT_INIT_LS_ID 1 uint32_t external_id; diff --git a/ospf6d/ospf6_zebra.c b/ospf6d/ospf6_zebra.c index 1a0c5a9971..5e50a6cc55 100644 --- a/ospf6d/ospf6_zebra.c +++ b/ospf6d/ospf6_zebra.c @@ -145,16 +145,17 @@ void ospf6_zebra_import_default_route(struct ospf6 *ospf6, bool unreg) prefix.prefixlen = 0; if (unreg) - command = ZEBRA_IMPORT_ROUTE_UNREGISTER; + command = ZEBRA_NEXTHOP_UNREGISTER; else - command = ZEBRA_IMPORT_ROUTE_REGISTER; + command = ZEBRA_NEXTHOP_REGISTER; if (IS_OSPF6_DEBUG_ZEBRA(SEND)) zlog_debug("%s: sending cmd %s for %pFX (vrf %u)", __func__, zserv_command_string(command), &prefix, ospf6->vrf_id); - if (zclient_send_rnh(zclient, command, &prefix, true, ospf6->vrf_id) + if (zclient_send_rnh(zclient, command, &prefix, false, true, + ospf6->vrf_id) == ZCLIENT_SEND_FAILURE) flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_send_rnh() failed", __func__); @@ -708,19 +709,22 @@ static void ospf6_zebra_connected(struct zclient *zclient) zclient_send_reg_requests(zclient, VRF_DEFAULT); } +static zclient_handler *const ospf6_handlers[] = { + [ZEBRA_ROUTER_ID_UPDATE] = ospf6_router_id_update_zebra, + [ZEBRA_INTERFACE_ADDRESS_ADD] = ospf6_zebra_if_address_update_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = ospf6_zebra_if_address_update_delete, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ospf6_zebra_read_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ospf6_zebra_read_route, + [ZEBRA_NEXTHOP_UPDATE] = ospf6_zebra_import_check_update, +}; + void ospf6_zebra_init(struct thread_master *master) { /* Allocate zebra structure. */ - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, ospf6_handlers, + array_size(ospf6_handlers)); zclient_init(zclient, ZEBRA_ROUTE_OSPF6, 0, &ospf6d_privs); zclient->zebra_connected = ospf6_zebra_connected; - zclient->router_id_update = ospf6_router_id_update_zebra; - zclient->interface_address_add = ospf6_zebra_if_address_update_add; - zclient->interface_address_delete = - ospf6_zebra_if_address_update_delete; - zclient->redistribute_route_add = ospf6_zebra_read_route; - zclient->redistribute_route_del = ospf6_zebra_read_route; - zclient->import_check_update = ospf6_zebra_import_check_update; /* Install command element for zebra node. */ install_element(VIEW_NODE, &show_ospf6_zebra_cmd); diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 5e6dcde991..d9f730586b 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -292,10 +292,7 @@ static void ospf6_lsdb_show_wrapper(struct vty *vty, json_object_array_add(json_array, json_obj); json_object_object_add(json, "asScopedLinkStateDb", json_array); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else vty_out(vty, "\n"); } @@ -386,12 +383,9 @@ static void ospf6_lsdb_type_show_wrapper(struct vty *vty, assert(0); break; } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "\n"); } diff --git a/ospf6d/subdir.am b/ospf6d/subdir.am index be626646a0..34aabc205b 100644 --- a/ospf6d/subdir.am +++ b/ospf6d/subdir.am @@ -99,6 +99,7 @@ clippy_scan += \ ospf6d/ospf6_lsa.c \ ospf6d/ospf6_gr_helper.c \ ospf6d/ospf6_gr.c \ + ospf6d/ospf6_nssa.c \ ospf6d/ospf6_route.c \ # end diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index 6a009d2144..8e59bd9ebd 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -318,10 +318,29 @@ int ospf_area_range_substitute_unset(struct ospf *ospf, struct in_addr area_id, int ospf_act_bb_connection(struct ospf *ospf) { + struct ospf_interface *oi; + struct listnode *node; + int full_nbrs = 0; + if (ospf->backbone == NULL) return 0; - return ospf->backbone->full_nbrs; + for (ALL_LIST_ELEMENTS_RO(ospf->backbone->oiflist, node, oi)) { + struct ospf_neighbor *nbr; + struct route_node *rn; + + for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { + nbr = rn->info; + if (!nbr) + continue; + + if (nbr->state == NSM_Full + || OSPF_GR_IS_ACTIVE_HELPER(nbr)) + full_nbrs++; + } + } + + return full_nbrs; } /* Determine whether this router is elected translator or not for area */ diff --git a/ospfd/ospf_apiserver.c b/ospfd/ospf_apiserver.c index cbd03441ef..a33ca95777 100644 --- a/ospfd/ospf_apiserver.c +++ b/ospfd/ospf_apiserver.c @@ -2059,7 +2059,8 @@ void ospf_apiserver_nsm_change(struct ospf_neighbor *nbr, int old_status) } } -void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa) +void ospf_apiserver_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct opaque_lsa { struct lsa_header header; @@ -2070,6 +2071,9 @@ void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa) struct opaque_lsa *olsa; int opaquelen; + if (json) + return; + olsa = (struct opaque_lsa *)lsa->data; if (VALID_OPAQUE_INFO_LEN(lsa->data)) diff --git a/ospfd/ospf_apiserver.h b/ospfd/ospf_apiserver.h index 89a9474972..544a32a28c 100644 --- a/ospfd/ospf_apiserver.h +++ b/ospfd/ospf_apiserver.h @@ -182,7 +182,8 @@ extern void ospf_apiserver_nsm_change(struct ospf_neighbor *nbr, extern void ospf_apiserver_config_write_router(struct vty *vty); extern void ospf_apiserver_config_write_if(struct vty *vty, struct interface *ifp); -extern void ospf_apiserver_show_info(struct vty *vty, struct ospf_lsa *lsa); +extern void ospf_apiserver_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); extern int ospf_ospf_apiserver_lsa_originator(void *arg); extern struct ospf_lsa *ospf_apiserver_lsa_refresher(struct ospf_lsa *lsa); extern void ospf_apiserver_flush_opaque_lsa(struct ospf_apiserver *apiserv, diff --git a/ospfd/ospf_asbr.c b/ospfd/ospf_asbr.c index 53d2ec538c..000c62e305 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -72,12 +72,13 @@ void ospf_external_route_remove(struct ospf *ospf, struct prefix_ipv4 *p) } /* Add an External info for AS-external-LSA. */ -struct external_info *ospf_external_info_new(uint8_t type, +struct external_info *ospf_external_info_new(struct ospf *ospf, uint8_t type, unsigned short instance) { struct external_info *new; new = XCALLOC(MTYPE_OSPF_EXTERNAL_INFO, sizeof(struct external_info)); + new->ospf = ospf; new->type = type; new->instance = instance; new->to_be_processed = 0; @@ -138,7 +139,7 @@ ospf_external_info_add(struct ospf *ospf, uint8_t type, unsigned short instance, } /* Create new External info instance. */ - new = ospf_external_info_new(type, instance); + new = ospf_external_info_new(ospf, type, instance); new->p = p; new->ifindex = ifindex; new->nexthop = nexthop; @@ -419,7 +420,7 @@ static void ospf_aggr_handle_external_info(void *data) { struct external_info *ei = (struct external_info *)data; struct ospf_external_aggr_rt *aggr = NULL; - struct ospf *ospf = NULL; + struct ospf *ospf = ei->ospf; struct ospf_lsa *lsa = NULL; ei->aggr_route = NULL; @@ -430,8 +431,6 @@ static void ospf_aggr_handle_external_info(void *data) zlog_debug("%s: Handle extrenal route(%pI4/%d)", __func__, &ei->p.prefix, ei->p.prefixlen); - ospf = ospf_lookup_instance(ei->instance); - assert(ospf); if (!ospf_redistribute_check(ospf, ei, NULL)) diff --git a/ospfd/ospf_asbr.h b/ospfd/ospf_asbr.h index d3e50903ef..160883144f 100644 --- a/ospfd/ospf_asbr.h +++ b/ospfd/ospf_asbr.h @@ -29,6 +29,8 @@ struct route_map_set_values { /* Redistributed external information. */ struct external_info { + struct ospf *ospf; + /* Type of source protocol. */ uint8_t type; @@ -107,7 +109,8 @@ struct ospf_external_aggr_rt { #define OSPF_ASBR_NSSA_REDIST_UPDATE_DELAY 9 extern void ospf_external_route_remove(struct ospf *, struct prefix_ipv4 *); -extern struct external_info *ospf_external_info_new(uint8_t, unsigned short); +extern struct external_info *ospf_external_info_new(struct ospf *, uint8_t, + unsigned short); extern void ospf_reset_route_map_set_values(struct route_map_set_values *); extern int ospf_route_map_set_compare(struct route_map_set_values *, struct route_map_set_values *); diff --git a/ospfd/ospf_ase.c b/ospfd/ospf_ase.c index aaacebca14..e9fb891d7e 100644 --- a/ospfd/ospf_ase.c +++ b/ospfd/ospf_ase.c @@ -280,6 +280,19 @@ int ospf_ase_calculate_route(struct ospf *ospf, struct ospf_lsa *lsa) return 0; } + /* Type-5 shouldn't be calculated if it is originated from NSSA ASBR. + * As per RFC 3101, expectation is to receive type-7 lsas from + * NSSA ASBR. Ignore calculation, if the current LSA is type-5 and + * originated ASBR's area is NSSA. + */ + if ((lsa->data->type == OSPF_AS_EXTERNAL_LSA) + && (asbr_route->u.std.external_routing != OSPF_AREA_DEFAULT)) { + if (IS_DEBUG_OSPF(lsa, LSA)) + zlog_debug( + "Route[External]: Ignore, If type-5 LSA from NSSA area."); + return 0; + } + /* Else, this LSA describes an AS external path to destination N. Examine the forwarding address specified in the AS- external-LSA. This indicates the IP address to which diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index f11c84b092..2f7556f7ff 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -127,7 +127,9 @@ const char *ospf_area_desc_string(struct ospf_area *area) return buf; } -#define OSPF_IF_STRING_MAXLEN 40 +#define OSPF_IF_STRING_MAXLEN 40 + +/* Display both nbr and ism state of the ospf neighbor.*/ const char *ospf_if_name_string(struct ospf_interface *oi) { static char buf[OSPF_IF_STRING_MAXLEN] = ""; @@ -146,9 +148,15 @@ const char *ospf_if_name_string(struct ospf_interface *oi) return buf; } - +/* Display only the nbr state.*/ void ospf_nbr_state_message(struct ospf_neighbor *nbr, char *buf, size_t size) { + snprintf(buf, size, "%s", + lookup_msg(ospf_nsm_state_msg, nbr->state, NULL)); +} + +int ospf_nbr_ism_state(struct ospf_neighbor *nbr) +{ int state; struct ospf_interface *oi = nbr->oi; @@ -159,6 +167,27 @@ void ospf_nbr_state_message(struct ospf_neighbor *nbr, char *buf, size_t size) else state = ISM_DROther; + return state; +} + +void ospf_nbr_ism_state_message(struct ospf_neighbor *nbr, char *buf, + size_t size) +{ + int state; + struct ospf_interface *oi = nbr->oi; + + if (!oi) + return; + + /* network type is point-to-point */ + if (oi->type == OSPF_IFTYPE_POINTOPOINT) { + snprintf(buf, size, "%s/-", + lookup_msg(ospf_nsm_state_msg, nbr->state, NULL)); + return; + } + + state = ospf_nbr_ism_state(nbr); + snprintf(buf, size, "%s/%s", lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), lookup_msg(ospf_ism_state_msg, state, NULL)); @@ -1616,11 +1645,15 @@ DEFUN (no_debug_ospf, DEBUG_OFF(nsm, NSM_EVENTS); DEBUG_OFF(nsm, NSM_STATUS); DEBUG_OFF(nsm, NSM_TIMERS); + DEBUG_OFF(event, EVENT); DEBUG_OFF(zebra, ZEBRA); DEBUG_OFF(zebra, ZEBRA_INTERFACE); DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE); DEBUG_OFF(defaultinfo, DEFAULTINFO); DEBUG_OFF(ldp_sync, LDP_SYNC); + DEBUG_OFF(te, TE); + DEBUG_OFF(sr, SR); + DEBUG_OFF(ti_lfa, TI_LFA); /* BFD debugging is two parts: OSPF and library. */ DEBUG_OFF(bfd, BFD_LIB); @@ -1653,6 +1686,9 @@ DEFUN (no_debug_ospf, TERM_DEBUG_OFF(zebra, ZEBRA_REDISTRIBUTE); TERM_DEBUG_OFF(defaultinfo, DEFAULTINFO); TERM_DEBUG_OFF(ldp_sync, LDP_SYNC); + TERM_DEBUG_OFF(te, TE); + TERM_DEBUG_OFF(sr, SR); + TERM_DEBUG_OFF(ti_lfa, TI_LFA); TERM_DEBUG_OFF(bfd, BFD_LIB); return CMD_SUCCESS; @@ -1763,6 +1799,18 @@ static int show_debugging_ospf_common(struct vty *vty) if (IS_DEBUG_OSPF(gr, GR) == OSPF_DEBUG_GR) vty_out(vty, " OSPF Graceful Restart debugging is on\n"); + /* Show debug status for TE */ + if (IS_DEBUG_OSPF(te, TE) == OSPF_DEBUG_TE) + vty_out(vty, " OSPF TE debugging is on\n"); + + /* Show debug status for SR */ + if (IS_DEBUG_OSPF(sr, SR) == OSPF_DEBUG_SR) + vty_out(vty, " OSPF SR debugging is on\n"); + + /* Show debug status for TI-LFA */ + if (IS_DEBUG_OSPF(ti_lfa, TI_LFA) == OSPF_DEBUG_TI_LFA) + vty_out(vty, " OSPF TI-LFA debugging is on\n"); + if (IS_DEBUG_OSPF(bfd, BFD_LIB) == OSPF_DEBUG_BFD_LIB) vty_out(vty, " OSPF BFD integration library debugging is on\n"); @@ -1937,7 +1985,7 @@ static int config_write_debug(struct vty *vty) } /* debug ospf sr ti-lfa */ - if (IS_CONF_DEBUG_OSPF(sr, TI_LFA) == OSPF_DEBUG_TI_LFA) { + if (IS_CONF_DEBUG_OSPF(ti_lfa, TI_LFA) == OSPF_DEBUG_TI_LFA) { vty_out(vty, "debug ospf%s ti-lfa\n", str); write = 1; } diff --git a/ospfd/ospf_dump.h b/ospfd/ospf_dump.h index a1f55dd0af..58227d038e 100644 --- a/ospfd/ospf_dump.h +++ b/ospfd/ospf_dump.h @@ -150,7 +150,11 @@ extern char *ospf_lsa_type_str[]; extern const char *ospf_area_name_string(struct ospf_area *); extern const char *ospf_area_desc_string(struct ospf_area *); extern const char *ospf_if_name_string(struct ospf_interface *); -extern void ospf_nbr_state_message(struct ospf_neighbor *, char *, size_t); +extern int ospf_nbr_ism_state(struct ospf_neighbor *nbr); +extern void ospf_nbr_state_message(struct ospf_neighbor *nbr, char *buf, + size_t size); +extern void ospf_nbr_ism_state_message(struct ospf_neighbor *nbr, char *buf, + size_t size); extern const char *ospf_timer_dump(struct thread *, char *, size_t); extern const char *ospf_timeval_dump(struct timeval *, char *, size_t); extern void ospf_packet_dump(struct stream *); diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c index 2d08eeece2..0e5a7e29c0 100644 --- a/ospfd/ospf_ext.c +++ b/ospfd/ospf_ext.c @@ -80,7 +80,8 @@ static struct ospf_ext_lp OspfEXT; */ /* Extended Prefix Opaque LSA related callback functions */ -static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa); +static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); static int ospf_ext_pref_lsa_originate(void *arg); static struct ospf_lsa *ospf_ext_pref_lsa_refresh(struct ospf_lsa *lsa); static void ospf_ext_pref_lsa_schedule(struct ext_itf *exti, @@ -90,7 +91,8 @@ static int ospf_ext_link_new_if(struct interface *ifp); static int ospf_ext_link_del_if(struct interface *ifp); static void ospf_ext_ism_change(struct ospf_interface *oi, int old_status); static void ospf_ext_link_nsm_change(struct ospf_neighbor *nbr, int old_status); -static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa); +static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); static int ospf_ext_link_lsa_originate(void *arg); static struct ospf_lsa *ospf_ext_link_lsa_refresh(struct ospf_lsa *lsa); static void ospf_ext_link_lsa_schedule(struct ext_itf *exti, @@ -254,10 +256,10 @@ static uint32_t get_ext_link_instance_value(void) /* Lookup Extended Prefix/Links by ifp from OspfEXT struct iflist */ static struct ext_itf *lookup_ext_by_ifp(struct interface *ifp) { - struct listnode *node, *nnode; + struct listnode *node; struct ext_itf *exti; - for (ALL_LIST_ELEMENTS(OspfEXT.iflist, node, nnode, exti)) + for (ALL_LIST_ELEMENTS_RO(OspfEXT.iflist, node, exti)) if (exti->ifp == ifp) return exti; @@ -1846,12 +1848,16 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext, } /* Extended Link TLVs */ -static void ospf_ext_link_show_info(struct vty *vty, struct ospf_lsa *lsa) +static void ospf_ext_link_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint16_t length = 0, sum = 0; + if (json) + return; + /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; @@ -1932,12 +1938,16 @@ static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext, } /* Extended Prefix TLVs */ -static void ospf_ext_pref_show_info(struct vty *vty, struct ospf_lsa *lsa) +static void ospf_ext_pref_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint16_t length = 0, sum = 0; + if (json) + return; + /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; diff --git a/ospfd/ospf_gr.c b/ospfd/ospf_gr.c index c108040303..6bfe48145f 100644 --- a/ospfd/ospf_gr.c +++ b/ospfd/ospf_gr.c @@ -150,7 +150,7 @@ static struct ospf_lsa *ospf_gr_lsa_new(struct ospf_interface *oi) } /* Originate and install Grace-LSA for a given interface. */ -static void ospf_gr_lsa_originate(struct ospf_interface *oi) +static void ospf_gr_lsa_originate(struct ospf_interface *oi, bool maxage) { struct ospf_lsa *lsa, *old; @@ -164,6 +164,9 @@ static void ospf_gr_lsa_originate(struct ospf_interface *oi) return; } + if (maxage) + lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); + /* Find the old LSA and increase the seqno. */ old = ospf_gr_lsa_lookup(oi->ospf, oi->area); if (old) @@ -183,37 +186,6 @@ static void ospf_gr_lsa_originate(struct ospf_interface *oi) ospf_flood_through_interface(oi, NULL, lsa); } -/* Flush a given self-originated Grace-LSA. */ -static struct ospf_lsa *ospf_gr_flush_grace_lsa(struct ospf_interface *oi, - struct ospf_lsa *old) -{ - struct ospf_lsa *lsa; - - if (ospf_interface_neighbor_count(oi) == 0) - return NULL; - - if (IS_DEBUG_OSPF_GR) - zlog_debug( - "GR: flushing self-originated Grace-LSAs [interface %s]", - oi->ifp->name); - - lsa = ospf_lsa_dup(old); - lsa->data->ls_age = htons(OSPF_LSA_MAXAGE); - lsa->data->ls_seqnum = lsa_seqnum_increment(lsa); - - /* Install updated LSA into LSDB. */ - if (ospf_lsa_install(oi->ospf, oi, lsa) == NULL) { - zlog_warn("%s: ospf_lsa_install() failed", __func__); - ospf_lsa_unlock(&lsa); - return NULL; - } - - /* Flood the LSA through out the interface */ - ospf_flood_through_interface(oi, NULL, lsa); - - return lsa; -} - /* Flush all self-originated Grace-LSAs. */ static void ospf_gr_flush_grace_lsas(struct ospf *ospf) { @@ -221,7 +193,6 @@ static void ospf_gr_flush_grace_lsas(struct ospf *ospf) struct listnode *anode; for (ALL_LIST_ELEMENTS_RO(ospf->areas, anode, area)) { - struct ospf_lsa *lsa; struct ospf_interface *oi; struct listnode *inode; @@ -230,15 +201,8 @@ static void ospf_gr_flush_grace_lsas(struct ospf *ospf) "GR: flushing self-originated Grace-LSAs [area %pI4]", &area->area_id); - lsa = ospf_gr_lsa_lookup(ospf, area); - if (!lsa) { - zlog_warn("%s: Grace-LSA not found [area %pI4]", - __func__, &area->area_id); - continue; - } - for (ALL_LIST_ELEMENTS_RO(area->oiflist, inode, oi)) - ospf_gr_flush_grace_lsa(oi, lsa); + ospf_gr_lsa_originate(oi, true); } } @@ -584,7 +548,7 @@ static void ospf_gr_nvm_update(struct ospf *ospf) json_object *json_instance; filepath = ospf_gr_nvm_filepath(ospf); - inst_name = ospf->name ? ospf->name : VRF_DEFAULT_NAME; + inst_name = ospf_get_name(ospf); json = json_object_from_file(filepath); if (json == NULL) @@ -630,7 +594,7 @@ static void ospf_gr_nvm_delete(struct ospf *ospf) json_object *json_instances; filepath = ospf_gr_nvm_filepath(ospf); - inst_name = ospf->name ? ospf->name : VRF_DEFAULT_NAME; + inst_name = ospf_get_name(ospf); json = json_object_from_file(filepath); if (json == NULL) @@ -663,7 +627,7 @@ void ospf_gr_nvm_read(struct ospf *ospf) time_t timestamp = 0; filepath = ospf_gr_nvm_filepath(ospf); - inst_name = ospf->name ? ospf->name : VRF_DEFAULT_NAME; + inst_name = ospf_get_name(ospf); json = json_object_from_file(filepath); if (json == NULL) @@ -750,7 +714,7 @@ static void ospf_gr_prepare(void) /* Send a Grace-LSA to all neighbors. */ for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, inode, oi)) - ospf_gr_lsa_originate(oi); + ospf_gr_lsa_originate(oi, false); /* Record end of the grace period in non-volatile memory. */ ospf_gr_nvm_update(ospf); @@ -770,6 +734,18 @@ DEFPY(graceful_restart_prepare, graceful_restart_prepare_cmd, IP_STR "Prepare to restart the OSPF process") { + struct ospf *ospf; + struct listnode *node; + + for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { + if (!CHECK_FLAG(ospf->config, OSPF_OPAQUE_CAPABLE)) { + vty_out(vty, + "%% Can't start graceful restart: opaque capability not enabled (VRF %s)\n\n", + ospf_get_name(ospf)); + return CMD_WARNING; + } + } + ospf_gr_prepare(); return CMD_SUCCESS; @@ -794,7 +770,7 @@ DEFPY(graceful_restart, graceful_restart_cmd, } DEFPY(no_graceful_restart, no_graceful_restart_cmd, - "no graceful-restart [period (1-1800)]", + "no graceful-restart [grace-period (1-1800)]", NO_STR OSPF_GR_STR "Maximum length of the 'grace period'\n" "Maximum length of the 'grace period' in seconds\n") diff --git a/ospfd/ospf_gr_helper.c b/ospfd/ospf_gr_helper.c index b3eaf7bbdb..ae002fdc97 100644 --- a/ospfd/ospf_gr_helper.c +++ b/ospfd/ospf_gr_helper.c @@ -75,7 +75,8 @@ static const char * const ospf_rejected_reason_desc[] = { "Router is in the process of graceful restart", }; -static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa); +static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); static bool ospf_check_change_in_rxmt_list(struct ospf_neighbor *nbr); static unsigned int ospf_enable_rtr_hash_key(const void *data) @@ -623,9 +624,6 @@ void ospf_helper_handle_topo_chg(struct ospf *ospf, struct ospf_lsa *lsa) struct listnode *node; struct ospf_interface *oi; - if (!ospf->active_restarter_cnt) - return; - /* Topo change not required to be handled if strict * LSA check is disabled for this router. */ @@ -1012,7 +1010,8 @@ void ospf_gr_helper_set_supported_planned_only_restart(struct ospf *ospf, * Returns: * Nothing. */ -static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa) +static void show_ospf_grace_lsa_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = NULL; struct tlv_header *tlvh = NULL; @@ -1022,6 +1021,9 @@ static void show_ospf_grace_lsa_info(struct vty *vty, struct ospf_lsa *lsa) uint16_t length = 0; int sum = 0; + if (json) + return; + lsah = (struct lsa_header *)lsa->data; if (lsa->size <= OSPF_LSA_HEADER_SIZE) { diff --git a/ospfd/ospf_interface.c b/ospfd/ospf_interface.c index 81cc346000..299e753ccf 100644 --- a/ospfd/ospf_interface.c +++ b/ospfd/ospf_interface.c @@ -360,9 +360,8 @@ void ospf_if_free(struct ospf_interface *oi) if (IS_DEBUG_OSPF_EVENT) zlog_debug("%s: ospf interface %s vrf %s id %u deleted", - __func__, oi->ifp->name, - ospf_vrf_id_to_name(oi->ifp->vrf_id), - oi->ifp->vrf_id); + __func__, oi->ifp->name, oi->ifp->vrf->name, + oi->ifp->vrf->vrf_id); ospf_delete_from_if(oi->ifp, oi); @@ -477,7 +476,7 @@ struct ospf_interface *ospf_if_lookup_recv_if(struct ospf *ospf, if (oi->type == OSPF_IFTYPE_VIRTUALLINK) continue; - if (if_is_loopback_or_vrf(oi->ifp)) + if (if_is_loopback(oi->ifp)) continue; if (CHECK_FLAG(oi->connected->flags, ZEBRA_IFA_UNNUMBERED)) @@ -705,11 +704,11 @@ static int ospf_if_delete_hook(struct interface *ifp) */ ospf_del_if_params(ifp, IF_DEF_PARAMS(ifp)); - route_table_finish(IF_OIFS(ifp)); - for (rn = route_top(IF_OIFS_PARAMS(ifp)); rn; rn = route_next(rn)) if (rn->info) ospf_del_if_params(ifp, rn->info); + + route_table_finish(IF_OIFS(ifp)); route_table_finish(IF_OIFS_PARAMS(ifp)); XFREE(MTYPE_OSPF_IF_INFO, ifp->info); @@ -719,7 +718,7 @@ static int ospf_if_delete_hook(struct interface *ifp) int ospf_if_is_enable(struct ospf_interface *oi) { - if (!(if_is_loopback_or_vrf(oi->ifp))) + if (!(if_is_loopback(oi->ifp))) if (if_is_up(oi->ifp)) return 1; @@ -915,9 +914,9 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf, ospf->vrf_id); snprintf(ifname, sizeof(ifname), "VLINK%u", vlink_count); - vi = if_create_name(ifname, ospf->vrf_id); + vi = if_get_by_name(ifname, ospf->vrf_id, ospf->name); /* - * if_create_name sets ZEBRA_INTERFACE_LINKDETECTION + * if_get_by_name sets ZEBRA_INTERFACE_LINKDETECTION * virtual links don't need this. */ UNSET_FLAG(vi->status, ZEBRA_INTERFACE_LINKDETECTION); @@ -971,11 +970,14 @@ struct ospf_interface *ospf_vl_new(struct ospf *ospf, static void ospf_vl_if_delete(struct ospf_vl_data *vl_data) { struct interface *ifp = vl_data->vl_oi->ifp; + struct vrf *vrf = ifp->vrf; vl_data->vl_oi->address->u.prefix4.s_addr = INADDR_ANY; vl_data->vl_oi->address->prefixlen = 0; ospf_if_free(vl_data->vl_oi); if_delete(&ifp); + if (!vrf_is_enabled(vrf)) + vrf_delete(vrf); vlink_count--; } @@ -1291,7 +1293,7 @@ uint8_t ospf_default_iftype(struct interface *ifp) { if (if_is_pointopoint(ifp)) return OSPF_IFTYPE_POINTOPOINT; - else if (if_is_loopback_or_vrf(ifp)) + else if (if_is_loopback(ifp)) return OSPF_IFTYPE_LOOPBACK; else return OSPF_IFTYPE_BROADCAST; @@ -1328,10 +1330,9 @@ static int ospf_ifp_create(struct interface *ifp) if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) zlog_debug( "Zebra: interface add %s vrf %s[%u] index %d flags %llx metric %d mtu %d speed %u", - ifp->name, ospf_vrf_id_to_name(ifp->vrf_id), - ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu, - ifp->speed); + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu, ifp->speed); assert(ifp->info); @@ -1344,7 +1345,7 @@ static int ospf_ifp_create(struct interface *ifp) IF_DEF_PARAMS(ifp)->type = ospf_default_iftype(ifp); } - ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); + ospf = ifp->vrf->info; if (!ospf) return 0; @@ -1428,13 +1429,13 @@ static int ospf_ifp_destroy(struct interface *ifp) if (IS_DEBUG_OSPF(zebra, ZEBRA_INTERFACE)) zlog_debug( "Zebra: interface delete %s vrf %s[%u] index %d flags %llx metric %d mtu %d", - ifp->name, ospf_vrf_id_to_name(ifp->vrf_id), - ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu); hook_call(ospf_if_delete, ifp); - ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); + ospf = ifp->vrf->info; if (ospf) { if (ospf_if_count_area_params(ifp) > 0) ospf_interface_area_unset(ospf, ifp); diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c index dbd45635b2..247ceb0a08 100644 --- a/ospfd/ospf_ldp_sync.c +++ b/ospfd/ospf_ldp_sync.c @@ -129,8 +129,9 @@ void ospf_ldp_sync_if_init(struct ospf_interface *oi) * if LDP-IGP Sync is configured globally set state * if ptop interface inform LDP LDP-SYNC is enabled */ - if (if_is_loopback(ifp) || (ifp->vrf_id != VRF_DEFAULT) || - !(CHECK_FLAG(oi->ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE))) + if (if_is_loopback(ifp) || (ifp->vrf->vrf_id != VRF_DEFAULT) + || !(CHECK_FLAG(oi->ospf->ldp_sync_cmd.flags, + LDP_SYNC_FLAG_ENABLE))) return; ols_debug("ldp_sync: init if %s",ifp->name); @@ -856,7 +857,7 @@ DEFPY (mpls_ldp_sync, return CMD_ERR_NOTHING_TODO; } - if (ifp->vrf_id != VRF_DEFAULT) { + if (ifp->vrf->vrf_id != VRF_DEFAULT) { vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n"); return CMD_ERR_NOTHING_TODO; } @@ -897,7 +898,7 @@ DEFPY (no_mpls_ldp_sync, return CMD_ERR_NOTHING_TODO; } - if (ifp->vrf_id != VRF_DEFAULT) { + if (ifp->vrf->vrf_id != VRF_DEFAULT) { vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n"); return CMD_ERR_NOTHING_TODO; } @@ -940,7 +941,7 @@ DEFPY (mpls_ldp_sync_holddown, return CMD_ERR_NOTHING_TODO; } - if (ifp->vrf_id != VRF_DEFAULT) { + if (ifp->vrf->vrf_id != VRF_DEFAULT) { vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n"); return CMD_ERR_NOTHING_TODO; } @@ -978,7 +979,7 @@ DEFPY (no_mpls_ldp_sync_holddown, return CMD_ERR_NOTHING_TODO; } - if (ifp->vrf_id != VRF_DEFAULT) { + if (ifp->vrf->vrf_id != VRF_DEFAULT) { vty_out(vty, "ldp-sync only runs on DEFAULT VRF\n"); return CMD_ERR_NOTHING_TODO; } @@ -1030,32 +1031,25 @@ DEFPY (show_ip_ospf_mpls_ldp_interface, /* Display default ospf (instance 0) info */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; } if (!CHECK_FLAG(ospf->ldp_sync_cmd.flags, LDP_SYNC_FLAG_ENABLE)) { - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "LDP-sync is disabled\n"); return CMD_SUCCESS; } ret = show_ip_ospf_mpls_ldp_interface_common(vty, ospf, intf_name, json, uj); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } diff --git a/ospfd/ospf_lsa.c b/ospfd/ospf_lsa.c index cc1b2919c0..6588d70208 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2480,10 +2480,6 @@ ospf_router_lsa_install(struct ospf *ospf, struct ospf_lsa *new, int rt_recalc) return new; } -#define OSPF_INTERFACE_TIMER_ON(T, F, V) \ - if (!(T)) \ - (T) = thread_add_timer(master, (F), oi, (V)) - /* Install network-LSA to an area. */ static struct ospf_lsa *ospf_network_lsa_install(struct ospf *ospf, struct ospf_interface *oi, @@ -2696,7 +2692,7 @@ struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi, /* Do comparision and record if recalc needed. */ rt_recalc = 0; - if (old == NULL || ospf_lsa_different(old, lsa)) { + if (old == NULL || ospf_lsa_different(old, lsa, false)) { /* Ref rfc3623 section 3.2.3 * Installing new lsa or change in the existing LSA * or flushing existing LSA leads to topo change @@ -2704,7 +2700,9 @@ struct ospf_lsa *ospf_lsa_install(struct ospf *ospf, struct ospf_interface *oi, * So, router should be aborted from HELPER role * if it is detected as TOPO change. */ - if (CHECK_LSA_TYPE_1_TO_5_OR_7(lsa->data->type)) + if (ospf->active_restarter_cnt + && CHECK_LSA_TYPE_1_TO_5_OR_7(lsa->data->type) + && ospf_lsa_different(old, lsa, true)) ospf_helper_handle_topo_chg(ospf, lsa); rt_recalc = 1; @@ -3306,8 +3304,25 @@ int ospf_lsa_more_recent(struct ospf_lsa *l1, struct ospf_lsa *l2) return 0; } -/* If two LSAs are different, return 1, otherwise return 0. */ -int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2) +/* + * Check if two LSAs are different. + * + * l1 + * The first LSA to compare. + * + * l2 + * The second LSA to compare. + * + * ignore_rcvd_flag + * When set to true, ignore whether the LSAs were received from the network + * or not. This parameter should be set to true when checking for topology + * changes as part of the Graceful Restart helper neighbor procedures. + * + * Returns: + * true if the LSAs are different, false otherwise. + */ +int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2, + bool ignore_rcvd_flag) { char *p1, *p2; assert(l1); @@ -3330,7 +3345,8 @@ int ospf_lsa_different(struct ospf_lsa *l1, struct ospf_lsa *l2) if (l1->size == 0) return 1; - if (CHECK_FLAG((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED)) + if (!ignore_rcvd_flag + && CHECK_FLAG((l1->flags ^ l2->flags), OSPF_LSA_RECEIVED)) return 1; /* May be a stale LSA in the LSBD */ assert(l1->size > OSPF_LSA_HEADER_SIZE); diff --git a/ospfd/ospf_lsa.h b/ospfd/ospf_lsa.h index 5dcd072774..a979573715 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -223,10 +223,6 @@ struct as_external_lsa { #define OSPF_LSA_UPDATE_DELAY 2 -#define OSPF_LSA_UPDATE_TIMER_ON(T, F) \ - if (!(T)) \ - (T) = thread_add_timer(master, (F), 0, 2) - #define CHECK_LSA_TYPE_1_TO_5_OR_7(type) \ ((type == OSPF_ROUTER_LSA) || (type == OSPF_NETWORK_LSA) \ || (type == OSPF_SUMMARY_LSA) || (type == OSPF_ASBR_SUMMARY_LSA) \ @@ -297,7 +293,8 @@ extern struct ospf_lsa *ospf_lsa_lookup_by_id(struct ospf_area *, uint32_t, extern struct ospf_lsa *ospf_lsa_lookup_by_header(struct ospf_area *, struct lsa_header *); extern int ospf_lsa_more_recent(struct ospf_lsa *, struct ospf_lsa *); -extern int ospf_lsa_different(struct ospf_lsa *, struct ospf_lsa *); +extern int ospf_lsa_different(struct ospf_lsa *, struct ospf_lsa *, + bool ignore_rcvd_flag); extern void ospf_flush_self_originated_lsas_now(struct ospf *); extern int ospf_lsa_is_self_originated(struct ospf *, struct ospf_lsa *); diff --git a/ospfd/ospf_main.c b/ospfd/ospf_main.c index 257429ebe8..2f9787bca5 100644 --- a/ospfd/ospf_main.c +++ b/ospfd/ospf_main.c @@ -112,7 +112,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t ospf_signals[] = { +struct frr_signal_t ospf_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/ospfd/ospf_nsm.c b/ospfd/ospf_nsm.c index 5f84d04fed..e3cf1cfc8b 100644 --- a/ospfd/ospf_nsm.c +++ b/ospfd/ospf_nsm.c @@ -76,10 +76,11 @@ static int ospf_inactivity_timer(struct thread *thread) */ if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer); - else if (IS_DEBUG_OSPF_GR) { - zlog_debug( - "%s, Acting as HELPER for this neighbour, So restart the dead timer", - __func__); + else { + if (IS_DEBUG_OSPF_GR) + zlog_debug( + "%s, Acting as HELPER for this neighbour, So restart the dead timer", + __func__); OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer, nbr->v_inactivity); } @@ -759,10 +760,8 @@ static void nsm_change_state(struct ospf_neighbor *nbr, int state) if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) zlog_info( "%s: Initializing [DD]: %pI4 with seqnum:%x , flags:%x", - (oi->ospf->name) ? oi->ospf->name - : VRF_DEFAULT_NAME, - &nbr->router_id, nbr->dd_seqnum, - nbr->dd_flags); + ospf_get_name(oi->ospf), &nbr->router_id, + nbr->dd_seqnum, nbr->dd_flags); ospf_db_desc_send(nbr); } diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index 9ec2ed0aa8..4670316db4 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -274,7 +274,8 @@ struct ospf_opaque_functab { void (*config_write_router)(struct vty *vty); void (*config_write_if)(struct vty *vty, struct interface *ifp); void (*config_write_debug)(struct vty *vty); - void (*show_opaque_info)(struct vty *vty, struct ospf_lsa *lsa); + void (*show_opaque_info)(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); int (*lsa_originator)(void *arg); struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa); int (*new_lsa_hook)(struct ospf_lsa *lsa); @@ -373,7 +374,8 @@ int ospf_register_opaque_functab( void (*config_write_router)(struct vty *vty), void (*config_write_if)(struct vty *vty, struct interface *ifp), void (*config_write_debug)(struct vty *vty), - void (*show_opaque_info)(struct vty *vty, struct ospf_lsa *lsa), + void (*show_opaque_info)(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa), int (*lsa_originator)(void *arg), struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa), int (*new_lsa_hook)(struct ospf_lsa *lsa), @@ -578,7 +580,6 @@ register_opaque_info_per_type(struct ospf_opaque_functab *functab, oipt->lsa_type = new->data->type; oipt->opaque_type = GET_OPAQUE_TYPE(ntohl(new->data->id.s_addr)); oipt->status = PROC_NORMAL; - oipt->t_opaque_lsa_self = NULL; oipt->functab = functab; functab->oipt = oipt; oipt->id_list = list_new(); @@ -703,7 +704,6 @@ register_opaque_info_per_id(struct opaque_info_per_type *oipt, sizeof(struct opaque_info_per_id)); oipi->opaque_id = GET_OPAQUE_ID(ntohl(new->data->id.s_addr)); - oipi->t_opaque_lsa_self = NULL; oipi->opqctl_type = oipt; oipi->lsa = ospf_lsa_lock(new); @@ -1182,6 +1182,16 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa, VALID_OPAQUE_INFO_LEN(lsah) ? "" : "(Invalid length?)"); + } else { + json_object_string_add( + json, "opaqueType", + ospf_opaque_type_name(opaque_type)); + json_object_int_add(json, "opaqueId", opaque_id); + json_object_int_add(json, "opaqueDataLength", + ntohs(lsah->length) + - OSPF_LSA_HEADER_SIZE); + json_object_boolean_add(json, "opaqueDataLengthValid", + VALID_OPAQUE_INFO_LEN(lsah)); } } else { zlog_debug(" Opaque-Type %u (%s)", opaque_type, @@ -1197,7 +1207,7 @@ void show_opaque_info_detail(struct vty *vty, struct ospf_lsa *lsa, /* Call individual output functions. */ if ((functab = ospf_opaque_functab_lookup(lsa)) != NULL) if (functab->show_opaque_info != NULL) - (*functab->show_opaque_info)(vty, lsa); + (*functab->show_opaque_info)(vty, json, lsa); return; } @@ -1845,7 +1855,6 @@ static int ospf_opaque_type9_lsa_reoriginate_timer(struct thread *t) int rc = -1; oipt = THREAD_ARG(t); - oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { @@ -1897,7 +1906,6 @@ static int ospf_opaque_type10_lsa_reoriginate_timer(struct thread *t) int n, rc = -1; oipt = THREAD_ARG(t); - oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { @@ -1951,7 +1959,6 @@ static int ospf_opaque_type11_lsa_reoriginate_timer(struct thread *t) int rc = -1; oipt = THREAD_ARG(t); - oipt->t_opaque_lsa_self = NULL; if ((functab = oipt->functab) == NULL || functab->lsa_originator == NULL) { @@ -2067,7 +2074,6 @@ static int ospf_opaque_lsa_refresh_timer(struct thread *t) zlog_debug("Timer[Opaque-LSA]: (Opaque-LSA Refresh expire)"); oipi = THREAD_ARG(t); - oipi->t_opaque_lsa_self = NULL; if ((lsa = oipi->lsa) != NULL) if ((functab = oipi->opqctl_type->functab) != NULL) diff --git a/ospfd/ospf_opaque.h b/ospfd/ospf_opaque.h index 7d401c3dcc..b26bc1e10c 100644 --- a/ospfd/ospf_opaque.h +++ b/ospfd/ospf_opaque.h @@ -77,6 +77,8 @@ #define OPAQUE_TYPE_RANGE_RESERVED(type) (127 < (type) && (type) <= 255) +#define OSPF_OPAQUE_LSA_MIN_SIZE 4U + #define VALID_OPAQUE_INFO_LEN(lsahdr) \ ((ntohs((lsahdr)->length) >= sizeof(struct lsa_header)) \ && ((ntohs((lsahdr)->length) < OSPF_MAX_LSA_SIZE)) \ @@ -136,7 +138,8 @@ extern int ospf_register_opaque_functab( void (*config_write_router)(struct vty *vty), void (*config_write_if)(struct vty *vty, struct interface *ifp), void (*config_write_debug)(struct vty *vty), - void (*show_opaque_info)(struct vty *vty, struct ospf_lsa *lsa), + void (*show_opaque_info)(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa), int (*lsa_originator)(void *arg), struct ospf_lsa *(*lsa_refresher)(struct ospf_lsa *lsa), int (*new_lsa_hook)(struct ospf_lsa *lsa), diff --git a/ospfd/ospf_packet.c b/ospfd/ospf_packet.c index 1dcf93dcde..e17e531098 100644 --- a/ospfd/ospf_packet.c +++ b/ospfd/ospf_packet.c @@ -99,18 +99,18 @@ static const uint16_t ospf_packet_minlen[] = { /* Minimum (besides OSPF_LSA_HEADER_SIZE) lengths for LSAs of particular types, offset is the "LSA type" field. */ static const uint16_t ospf_lsa_minlen[] = { - 0, - OSPF_ROUTER_LSA_MIN_SIZE, - OSPF_NETWORK_LSA_MIN_SIZE, - OSPF_SUMMARY_LSA_MIN_SIZE, - OSPF_SUMMARY_LSA_MIN_SIZE, - OSPF_AS_EXTERNAL_LSA_MIN_SIZE, - 0, - OSPF_AS_EXTERNAL_LSA_MIN_SIZE, - 0, - 0, - 0, - 0, + 0, /* OSPF_UNKNOWN_LSA */ + OSPF_ROUTER_LSA_MIN_SIZE, /* OSPF_ROUTER_LSA */ + OSPF_NETWORK_LSA_MIN_SIZE, /* OSPF_NETWORK_LSA */ + OSPF_SUMMARY_LSA_MIN_SIZE, /* OSPF_SUMMARY_LSA */ + OSPF_SUMMARY_LSA_MIN_SIZE, /* OSPF_ASBR_SUMMARY_LSA */ + OSPF_AS_EXTERNAL_LSA_MIN_SIZE, /* OSPF_AS_EXTERNAL_LSA */ + 0, /* Unsupported, OSPF_GROUP_MEMBER_LSA */ + OSPF_AS_EXTERNAL_LSA_MIN_SIZE, /* OSPF_AS_NSSA_LSA */ + 0, /* Unsupported, OSPF_EXTERNAL_ATTRIBURES_LSA */ + OSPF_OPAQUE_LSA_MIN_SIZE, /* OSPF_OPAQUE_LINK_LSA */ + OSPF_OPAQUE_LSA_MIN_SIZE, /* OSPF_OPAQUE_AREA_LSA */ + OSPF_OPAQUE_LSA_MIN_SIZE, /* OSPF_OPAQUE_AS_LSA */ }; /* for ospf_check_auth() */ @@ -398,7 +398,7 @@ static int ospf_make_md5_digest(struct ospf_interface *oi, /* We do this here so when we dup a packet, we don't have to waste CPU rewriting other headers. - Note that quagga_time /deliberately/ is not used here */ + Note that frr_time /deliberately/ is not used here */ t = (time(NULL) & 0xFFFFFFFF); if (t > oi->crypt_seqnum) oi->crypt_seqnum = t; @@ -1096,44 +1096,61 @@ static void ospf_hello(struct ip *iph, struct ospf_header *ospfh, zlog_debug( "%s, Neighbor is under GR Restart, hence ignoring the ISM Events", __PRETTY_FUNCTION__); - - return; - } - - /* If neighbor itself declares DR and no BDR exists, - cause event BackupSeen */ - if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->d_router)) - if (hello->bd_router.s_addr == INADDR_ANY - && oi->state == ISM_Waiting) + } else { + /* If neighbor itself declares DR and no BDR exists, + cause event BackupSeen */ + if (IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->d_router)) + if (hello->bd_router.s_addr == INADDR_ANY + && oi->state == ISM_Waiting) + OSPF_ISM_EVENT_SCHEDULE(oi, ISM_BackupSeen); + + /* neighbor itself declares BDR. */ + if (oi->state == ISM_Waiting + && IPV4_ADDR_SAME(&nbr->address.u.prefix4, + &hello->bd_router)) OSPF_ISM_EVENT_SCHEDULE(oi, ISM_BackupSeen); - /* neighbor itself declares BDR. */ - if (oi->state == ISM_Waiting - && IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->bd_router)) - OSPF_ISM_EVENT_SCHEDULE(oi, ISM_BackupSeen); - - /* had not previously. */ - if ((IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->d_router) - && IPV4_ADDR_CMP(&nbr->address.u.prefix4, &nbr->d_router)) - || (IPV4_ADDR_CMP(&nbr->address.u.prefix4, &hello->d_router) - && IPV4_ADDR_SAME(&nbr->address.u.prefix4, &nbr->d_router))) - OSPF_ISM_EVENT_SCHEDULE(oi, ISM_NeighborChange); - - /* had not previously. */ - if ((IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->bd_router) - && IPV4_ADDR_CMP(&nbr->address.u.prefix4, &nbr->bd_router)) - || (IPV4_ADDR_CMP(&nbr->address.u.prefix4, &hello->bd_router) - && IPV4_ADDR_SAME(&nbr->address.u.prefix4, &nbr->bd_router))) - OSPF_ISM_EVENT_SCHEDULE(oi, ISM_NeighborChange); - - /* Neighbor priority check. */ - if (nbr->priority >= 0 && nbr->priority != hello->priority) - OSPF_ISM_EVENT_SCHEDULE(oi, ISM_NeighborChange); + /* had not previously. */ + if ((IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->d_router) + && IPV4_ADDR_CMP(&nbr->address.u.prefix4, &nbr->d_router)) + || (IPV4_ADDR_CMP(&nbr->address.u.prefix4, &hello->d_router) + && IPV4_ADDR_SAME(&nbr->address.u.prefix4, + &nbr->d_router))) + OSPF_ISM_EVENT_SCHEDULE(oi, ISM_NeighborChange); + + /* had not previously. */ + if ((IPV4_ADDR_SAME(&nbr->address.u.prefix4, &hello->bd_router) + && IPV4_ADDR_CMP(&nbr->address.u.prefix4, &nbr->bd_router)) + || (IPV4_ADDR_CMP(&nbr->address.u.prefix4, + &hello->bd_router) + && IPV4_ADDR_SAME(&nbr->address.u.prefix4, + &nbr->bd_router))) + OSPF_ISM_EVENT_SCHEDULE(oi, ISM_NeighborChange); + + /* Neighbor priority check. */ + if (nbr->priority >= 0 && nbr->priority != hello->priority) + OSPF_ISM_EVENT_SCHEDULE(oi, ISM_NeighborChange); + } /* Set neighbor information. */ nbr->priority = hello->priority; nbr->d_router = hello->d_router; nbr->bd_router = hello->bd_router; + + /* + * RFC 3623 - Section 2: + * "If the restarting router determines that it was the Designated + * Router on a given segment prior to the restart, it elects + * itself as the Designated Router again. The restarting router + * knows that it was the Designated Router if, while the + * associated interface is in Waiting state, a Hello packet is + * received from a neighbor listing the router as the Designated + * Router". + */ + if (oi->area->ospf->gr_info.restart_in_progress + && oi->state == ISM_Waiting + && IPV4_ADDR_SAME(&hello->d_router, &oi->address->u.prefix4)) + DR(oi) = hello->d_router; } /* Save DD flags/options/Seqnum received. */ @@ -1378,8 +1395,7 @@ static void ospf_db_desc(struct ip *iph, struct ospf_header *ospfh, if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) zlog_info( "%s:Packet[DD]: Neighbor %pI4 state is %s, seq_num:0x%x, local:0x%x", - (oi->ospf->name) ? oi->ospf->name : VRF_DEFAULT_NAME, - &nbr->router_id, + ospf_get_name(oi->ospf), &nbr->router_id, lookup_msg(ospf_nsm_state_msg, nbr->state, NULL), ntohl(dd->dd_seqnum), nbr->dd_seqnum); @@ -2996,7 +3012,7 @@ static enum ospf_read_return_enum ospf_read_helper(struct ospf *ospf) } } - if (ospf->vrf_id == VRF_DEFAULT && ospf->vrf_id != ifp->vrf_id) { + if (ospf->vrf_id == VRF_DEFAULT && ospf->vrf_id != ifp->vrf->vrf_id) { /* * We may have a situation where l3mdev_accept == 1 * let's just kindly drop the packet and move on. @@ -3879,9 +3895,8 @@ void ospf_db_desc_send(struct ospf_neighbor *nbr) if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) zlog_info( "%s:Packet[DD]: %pI4 DB Desc send with seqnum:%x , flags:%x", - (oi->ospf->name) ? oi->ospf->name : VRF_DEFAULT_NAME, - &nbr->router_id, nbr->dd_seqnum, - nbr->dd_flags); + ospf_get_name(oi->ospf), &nbr->router_id, + nbr->dd_seqnum, nbr->dd_flags); } /* Re-send Database Description. */ @@ -3899,9 +3914,8 @@ void ospf_db_desc_resend(struct ospf_neighbor *nbr) if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)) zlog_info( "%s:Packet[DD]: %pI4 DB Desc resend with seqnum:%x , flags:%x", - (oi->ospf->name) ? oi->ospf->name : VRF_DEFAULT_NAME, - &nbr->router_id, nbr->dd_seqnum, - nbr->dd_flags); + ospf_get_name(oi->ospf), &nbr->router_id, + nbr->dd_seqnum, nbr->dd_flags); } /* Send Link State Request. */ diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c index 602f98d141..0efa6ca4d5 100644 --- a/ospfd/ospf_ri.c +++ b/ospfd/ospf_ri.c @@ -73,7 +73,9 @@ static struct ospf_router_info OspfRI; static void ospf_router_info_ism_change(struct ospf_interface *oi, int old_status); static void ospf_router_info_config_write_router(struct vty *vty); -static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa); +static void ospf_router_info_show_info(struct vty *vty, + struct json_object *json, + struct ospf_lsa *lsa); static int ospf_router_info_lsa_originate(void *arg); static struct ospf_lsa *ospf_router_info_lsa_refresh(struct ospf_lsa *lsa); static void ospf_router_info_lsa_schedule(struct ospf_ri_area_info *ai, @@ -1552,12 +1554,17 @@ static uint16_t show_vty_sr_msd(struct vty *vty, struct tlv_header *tlvh) return TLV_SIZE(tlvh); } -static void ospf_router_info_show_info(struct vty *vty, struct ospf_lsa *lsa) +static void ospf_router_info_show_info(struct vty *vty, + struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh; uint16_t length = 0, sum = 0; + if (json) + return; + /* Initialize TLV browsing */ length = lsa->size - OSPF_LSA_HEADER_SIZE; diff --git a/ospfd/ospf_routemap.c b/ospfd/ospf_routemap.c index 2525c1cf3a..b1216626c4 100644 --- a/ospfd/ospf_routemap.c +++ b/ospfd/ospf_routemap.c @@ -320,7 +320,7 @@ route_match_interface(void *rule, const struct prefix *prefix, void *object) struct external_info *ei; ei = object; - ifp = if_lookup_by_name_all_vrf((char *)rule); + ifp = if_lookup_by_name((char *)rule, ei->ospf->vrf_id); if (ifp == NULL || ifp->ifindex != ei->ifindex) return RMAP_NOMATCH; diff --git a/ospfd/ospf_snmp.c b/ospfd/ospf_snmp.c index 432f95f9dd..7ec3db7894 100644 --- a/ospfd/ospf_snmp.c +++ b/ospfd/ospf_snmp.c @@ -2090,7 +2090,7 @@ static struct ospf_neighbor *ospfNbrLookup(struct variable *v, oid *name, return NULL; } -/* map internal quagga neighbor states to official MIB values: +/* map internal frr neighbor states to official MIB values: ospfNbrState OBJECT-TYPE SYNTAX INTEGER { @@ -2432,7 +2432,7 @@ static void ospfTrapNbrStateChange(struct ospf_neighbor *on) oid index[sizeof(oid) * (IN_ADDR_SIZE + 1)]; char msgbuf[16]; - ospf_nbr_state_message(on, msgbuf, sizeof(msgbuf)); + ospf_nbr_ism_state_message(on, msgbuf, sizeof(msgbuf)); if (IS_DEBUG_OSPF_EVENT) zlog_info("%s: trap sent: %pI4 now %s", __func__, &on->address.u.prefix4, msgbuf); diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index 9a9e64cc23..181cc37f4f 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -279,17 +279,19 @@ static int sr_local_block_init(uint32_t lower_bound, uint32_t upper_bound) */ size = upper_bound - lower_bound + 1; if (ospf_zebra_request_label_range(lower_bound, size)) { - srlb->reserved = false; + zlog_err("SR: Error reserving SRLB [%u/%u] %u labels", + lower_bound, upper_bound, size); return -1; } - osr_debug("SR (%s): Got new SRLB [%u/%u]", __func__, lower_bound, - upper_bound); + osr_debug("SR: Got new SRLB [%u/%u], %u labels", lower_bound, + upper_bound, size); /* Initialize the SRLB */ srlb->start = lower_bound; srlb->end = upper_bound; srlb->current = 0; + /* Compute the needed Used Mark number and allocate them */ srlb->max_block = size / SRLB_BLOCK_SIZE; if ((size % SRLB_BLOCK_SIZE) != 0) @@ -301,6 +303,31 @@ static int sr_local_block_init(uint32_t lower_bound, uint32_t upper_bound) return 0; } +static int sr_global_block_init(uint32_t start, uint32_t size) +{ + struct sr_global_block *srgb = &OspfSR.srgb; + + /* Check if already configured */ + if (srgb->reserved) + return 0; + + /* request chunk */ + uint32_t end = start + size - 1; + if (ospf_zebra_request_label_range(start, size) < 0) { + zlog_err("SR: Error reserving SRGB [%u/%u], %u labels", start, + end, size); + return -1; + } + + osr_debug("SR: Got new SRGB [%u/%u], %u labels", start, end, size); + + /* success */ + srgb->start = start; + srgb->size = size; + srgb->reserved = true; + return 0; +} + /** * Remove Segment Routing Local Block. * @@ -322,10 +349,31 @@ static void sr_local_block_delete(void) /* Then reset SRLB structure */ if (srlb->used_mark != NULL) XFREE(MTYPE_OSPF_SR_PARAMS, srlb->used_mark); + srlb->reserved = false; } /** + * Remove Segment Routing Global block + */ +static void sr_global_block_delete(void) +{ + struct sr_global_block *srgb = &OspfSR.srgb; + + if (!srgb->reserved) + return; + + osr_debug("SR (%s): Remove SRGB [%u/%u]", __func__, srgb->start, + srgb->start + srgb->size - 1); + + ospf_zebra_release_label_range(srgb->start, + srgb->start + srgb->size - 1); + + srgb->reserved = false; +} + + +/** * Request a label from the Segment Routing Local Block. * * @return First available label on success or MPLS_INVALID_LABEL if the @@ -337,9 +385,10 @@ mpls_label_t ospf_sr_local_block_request_label(void) mpls_label_t label; uint32_t index; uint32_t pos; + uint32_t size = srlb->end - srlb->start + 1; /* Check if we ran out of available labels */ - if (srlb->current >= srlb->end) + if (srlb->current >= size) return MPLS_INVALID_LABEL; /* Get first available label and mark it used */ @@ -351,7 +400,7 @@ mpls_label_t ospf_sr_local_block_request_label(void) /* Jump to the next free position */ srlb->current++; pos = srlb->current % SRLB_BLOCK_SIZE; - while (srlb->current < srlb->end) { + while (srlb->current < size) { if (pos == 0) index++; if (!((1ULL << pos) & srlb->used_mark[index])) @@ -362,6 +411,10 @@ mpls_label_t ospf_sr_local_block_request_label(void) } } + if (srlb->current == size) + zlog_warn( + "SR: Warning, SRLB is depleted and next label request will fail"); + return label; } @@ -469,16 +522,11 @@ static int ospf_sr_start(struct ospf *ospf) * If the allocation fails, return an error to disable SR until a new * SRLB and/or SRGB are successfully allocated. */ - sr_local_block_init(OspfSR.srlb.start, OspfSR.srlb.end); - if (!OspfSR.srgb.reserved) { - if (ospf_zebra_request_label_range(OspfSR.srgb.start, - OspfSR.srgb.size) - < 0) { - OspfSR.srgb.reserved = false; - return -1; - } else - OspfSR.srgb.reserved = true; - } + if (sr_local_block_init(OspfSR.srlb.start, OspfSR.srlb.end) < 0) + return -1; + + if (sr_global_block_init(OspfSR.srgb.start, OspfSR.srgb.size) < 0) + return -1; /* SR is UP and ready to flood LSA */ OspfSR.status = SR_UP; @@ -534,13 +582,10 @@ static void ospf_sr_stop(void) /* Disable any re-attempt to connect to Label Manager */ THREAD_OFF(OspfSR.t_start_lm); - /* Release SRGB & SRLB if active. */ - if (OspfSR.srgb.reserved) { - ospf_zebra_release_label_range( - OspfSR.srgb.start, - OspfSR.srgb.start + OspfSR.srgb.size - 1); - OspfSR.srgb.reserved = false; - } + /* Release SRGB if active */ + sr_global_block_delete(); + + /* Release SRLB if active */ sr_local_block_delete(); /* @@ -581,7 +626,7 @@ int ospf_sr_init(void) OspfSR.srgb.reserved = false; OspfSR.srlb.start = DEFAULT_SRLB_LABEL; - OspfSR.srlb.end = DEFAULT_SRLB_LABEL + DEFAULT_SRLB_SIZE - 1; + OspfSR.srlb.end = DEFAULT_SRLB_END; OspfSR.srlb.reserved = false; OspfSR.msd = 0; @@ -1200,7 +1245,9 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) /* Search for existing Segment Prefix */ for (ALL_LIST_ELEMENTS_RO(srn->ext_prefix, node, pref)) - if (pref->instance == srp->instance) { + if (pref->instance == srp->instance + && prefix_same((struct prefix *)&srp->prefv4, + &pref->prefv4)) { found = true; break; } @@ -1231,9 +1278,6 @@ static void update_ext_prefix_sid(struct sr_node *srn, struct sr_prefix *srp) /* Replace Segment Prefix */ listnode_delete(srn->ext_prefix, pref); XFREE(MTYPE_OSPF_SR_PARAMS, pref); - srp->srn = srn; - IPV4_ADDR_COPY(&srp->adv_router, - &srn->adv_router); listnode_add(srn->ext_prefix, srp); ospf_zebra_update_prefix_sid(srp); } else { @@ -2099,6 +2143,20 @@ static int ospf_sr_enabled(struct vty *vty) return 0; } +/* tell if two ranges [r1_lower, r1_upper] and [r2_lower,r2_upper] overlap */ +static bool ranges_overlap(uint32_t r1_lower, uint32_t r1_upper, + uint32_t r2_lower, uint32_t r2_upper) +{ + return !((r1_upper < r2_lower) || (r1_lower > r2_upper)); +} + + +/* tell if a range is valid */ +static bool sr_range_is_valid(uint32_t lower, uint32_t upper, uint32_t min_size) +{ + return (upper >= lower + min_size); +} + /** * Update SRGB and/or SRLB using new CLI values. * @@ -2136,12 +2194,8 @@ static int update_sr_blocks(uint32_t gb_lower, uint32_t gb_upper, /* Release old SRGB if it has changed and is active. */ if (gb_changed) { - if (OspfSR.srgb.reserved) { - ospf_zebra_release_label_range( - OspfSR.srgb.start, - OspfSR.srgb.start + OspfSR.srgb.size - 1); - OspfSR.srgb.reserved = false; - } + + sr_global_block_delete(); /* Set new SRGB values - but do not reserve yet (we need to * release the SRLB too) */ @@ -2155,8 +2209,8 @@ static int update_sr_blocks(uint32_t gb_lower, uint32_t gb_upper, /* Release old SRLB if it has changed and reserve new block as needed. */ if (lb_changed) { - if (OspfSR.srlb.reserved) - sr_local_block_delete(); + + sr_local_block_delete(); /* Set new SRLB values */ if (sr_local_block_init(lb_lower, lb_upper) < 0) { @@ -2175,18 +2229,11 @@ static int update_sr_blocks(uint32_t gb_lower, uint32_t gb_upper, * allocated. */ if (gb_changed) { - if (ospf_zebra_request_label_range(OspfSR.srgb.start, - OspfSR.srgb.size) + if (sr_global_block_init(OspfSR.srgb.start, OspfSR.srgb.size) < 0) { - OspfSR.srgb.reserved = false; ospf_sr_stop(); return -1; - } else - OspfSR.srgb.reserved = true; - - osr_debug("SR(%s): Got new SRGB [%u/%u]", __func__, - OspfSR.srgb.start, - OspfSR.srgb.start + OspfSR.srgb.size - 1); + } } /* Update Self SR-Node */ @@ -2227,16 +2274,29 @@ DEFUN(sr_global_label_range, sr_global_label_range_cmd, /* Get lower and upper bound for mandatory global-block */ gb_lower = strtoul(argv[idx_gb_low]->arg, NULL, 10); gb_upper = strtoul(argv[idx_gb_up]->arg, NULL, 10); + /* SRLB values are taken from vtysh if there, else use the known ones */ lb_upper = argc > idx_lb_up ? strtoul(argv[idx_lb_up]->arg, NULL, 10) : OspfSR.srlb.end; lb_lower = argc > idx_lb_low ? strtoul(argv[idx_lb_low]->arg, NULL, 10) : OspfSR.srlb.start; + /* check correctness of input SRGB */ + if (!sr_range_is_valid(gb_lower, gb_upper, MIN_SRGB_SIZE)) { + vty_out(vty, "Invalid SRGB range\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + /* check correctness of SRLB */ + if (!sr_range_is_valid(lb_lower, lb_upper, MIN_SRLB_SIZE)) { + vty_out(vty, "Invalid SRLB range\n"); + return CMD_WARNING_CONFIG_FAILED; + } + /* Validate SRGB against SRLB */ - if (!((gb_upper < lb_lower) || (gb_lower > lb_upper))) { + if (ranges_overlap(gb_lower, gb_upper, lb_lower, lb_upper)) { vty_out(vty, - "New SR Global Block (%u/%u) conflict with Local Block (%u/%u)\n", + "New SR Global Block (%u/%u) conflicts with Local Block (%u/%u)\n", gb_lower, gb_upper, lb_lower, lb_upper); return CMD_WARNING_CONFIG_FAILED; } @@ -2287,6 +2347,12 @@ DEFUN_HIDDEN(sr_local_label_range, sr_local_label_range_cmd, lower = strtoul(argv[idx_low]->arg, NULL, 10); upper = strtoul(argv[idx_up]->arg, NULL, 10); + /* check correctness of SRLB */ + if (!sr_range_is_valid(lower, upper, MIN_SRLB_SIZE)) { + vty_out(vty, "Invalid SRLB range\n"); + return CMD_WARNING_CONFIG_FAILED; + } + /* Check if values have changed */ if ((OspfSR.srlb.start == lower) && (OspfSR.srlb.end == upper)) @@ -2294,9 +2360,10 @@ DEFUN_HIDDEN(sr_local_label_range, sr_local_label_range_cmd, /* Validate SRLB against SRGB */ srgb_upper = OspfSR.srgb.start + OspfSR.srgb.size - 1; - if (!((upper < OspfSR.srgb.start) || (lower > srgb_upper))) { + + if (ranges_overlap(OspfSR.srgb.start, srgb_upper, lower, upper)) { vty_out(vty, - "New SR Local Block (%u/%u) conflict with Global Block (%u/%u)\n", + "New SR Local Block (%u/%u) conflicts with Global Block (%u/%u)\n", lower, upper, OspfSR.srgb.start, srgb_upper); return CMD_WARNING_CONFIG_FAILED; } @@ -2319,10 +2386,10 @@ DEFUN_HIDDEN(no_sr_local_label_range, no_sr_local_label_range_cmd, /* Validate SRLB against SRGB */ srgb_end = OspfSR.srgb.start + OspfSR.srgb.size - 1; - if (!((DEFAULT_SRLB_END < OspfSR.srgb.start) - || (DEFAULT_SRLB_LABEL > srgb_end))) { + if (ranges_overlap(OspfSR.srgb.start, srgb_end, DEFAULT_SRLB_LABEL, + DEFAULT_SRLB_END)) { vty_out(vty, - "New SR Local Block (%u/%u) conflict with Global Block (%u/%u)\n", + "New SR Local Block (%u/%u) conflicts with Global Block (%u/%u)\n", DEFAULT_SRLB_LABEL, DEFAULT_SRLB_END, OspfSR.srgb.start, srgb_end); return CMD_WARNING_CONFIG_FAILED; @@ -2412,11 +2479,15 @@ DEFUN (sr_prefix_sid, "Upstream neighbor must replace prefix-sid with explicit null label\n") { int idx = 0; - struct prefix p; + struct prefix p, pexist; uint32_t index; struct listnode *node; - struct sr_prefix *srp, *new = NULL; + struct sr_prefix *srp, *exist = NULL; struct interface *ifp; + bool no_php_flag = false; + bool exp_null = false; + bool index_in_use = false; + uint8_t desired_flags = 0; if (!ospf_sr_enabled(vty)) return CMD_WARNING_CONFIG_FAILED; @@ -2437,53 +2508,67 @@ DEFUN (sr_prefix_sid, return CMD_WARNING_CONFIG_FAILED; } + /* Get options */ + no_php_flag = argv_find(argv, argc, "no-php-flag", &idx); + exp_null = argv_find(argv, argc, "explicit-null", &idx); + + desired_flags |= no_php_flag ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0; + desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_NPFLG : 0; + desired_flags |= exp_null ? EXT_SUBTLV_PREFIX_SID_EFLG : 0; + /* Search for an existing Prefix-SID */ for (ALL_LIST_ELEMENTS_RO(OspfSR.self->ext_prefix, node, srp)) { + if (prefix_same((struct prefix *)&srp->prefv4, &p)) + exist = srp; if (srp->sid == index) { - if (prefix_same((struct prefix *)&srp->prefv4, &p)) { - new = srp; - break; - } else { - vty_out(vty, "Index %u is already used\n", - index); - return CMD_WARNING_CONFIG_FAILED; - } + index_in_use = true; + pexist = p; } } - /* Create new Extended Prefix to SRDB if not found */ - if (new == NULL) { - new = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix)); - IPV4_ADDR_COPY(&new->prefv4.prefix, &p.u.prefix4); - new->prefv4.prefixlen = p.prefixlen; - new->prefv4.family = p.family; - new->sid = index; - new->type = LOCAL_SID; + /* done if prefix segment already there with same index and flags */ + if (exist && exist->sid == index && exist->flags == desired_flags) + return CMD_SUCCESS; + + /* deny if index is already in use by a distinct prefix */ + if (!exist && index_in_use) { + vty_out(vty, "Index %u is already used by %pFX\n", index, + &pexist); + return CMD_WARNING_CONFIG_FAILED; } /* First, remove old NHLFE if installed */ - if (srp == new && CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_NPFLG) - && !CHECK_FLAG(srp->flags, EXT_SUBTLV_PREFIX_SID_EFLG)) - ospf_zebra_delete_prefix_sid(srp); - /* Then, reset Flag & labels to handle flag update */ - new->flags = 0; - new->label_in = 0; - new->nhlfe.label_out = 0; + if (exist && CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_NPFLG) + && !CHECK_FLAG(exist->flags, EXT_SUBTLV_PREFIX_SID_EFLG)) + ospf_zebra_delete_prefix_sid(exist); - /* Set NO PHP flag if present and compute NHLFE */ - if (argv_find(argv, argc, "no-php-flag", &idx)) { - SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG); - new->label_in = index2label(new->sid, OspfSR.self->srgb); - new->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL; + /* Create new Extended Prefix to SRDB if not found */ + if (exist == NULL) { + srp = XCALLOC(MTYPE_OSPF_SR_PARAMS, sizeof(struct sr_prefix)); + IPV4_ADDR_COPY(&srp->prefv4.prefix, &p.u.prefix4); + srp->prefv4.prefixlen = p.prefixlen; + srp->prefv4.family = p.family; + srp->sid = index; + srp->type = LOCAL_SID; + } else { + /* we work on the existing SR prefix */ + srp = exist; } - /* Set EXPLICIT NULL flag is present */ - if (argv_find(argv, argc, "explicit-null", &idx)) { - SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG); - SET_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG); + + /* Reset labels to handle flag update */ + srp->label_in = 0; + srp->nhlfe.label_out = 0; + srp->sid = index; + srp->flags = desired_flags; + + /* If NO PHP flag is present, compute NHLFE and set label */ + if (no_php_flag) { + srp->label_in = index2label(srp->sid, OspfSR.self->srgb); + srp->nhlfe.label_out = MPLS_LABEL_IMPLICIT_NULL; } osr_debug("SR (%s): Add new index %u to Prefix %pFX", __func__, index, - (struct prefix *)&new->prefv4); + (struct prefix *)&srp->prefv4); /* Get Interface and check if it is a Loopback */ ifp = if_lookup_prefix(&p, VRF_DEFAULT); @@ -2494,7 +2579,8 @@ DEFUN (sr_prefix_sid, * ready. In this case, store the prefix SID for latter * update of this Extended Prefix */ - listnode_add(OspfSR.self->ext_prefix, new); + if (exist == NULL) + listnode_add(OspfSR.self->ext_prefix, srp); zlog_info( "Interface for prefix %pFX not found. Deferred LSA flooding", &p); @@ -2503,27 +2589,26 @@ DEFUN (sr_prefix_sid, if (!if_is_loopback(ifp)) { vty_out(vty, "interface %s is not a Loopback\n", ifp->name); - XFREE(MTYPE_OSPF_SR_PARAMS, new); + XFREE(MTYPE_OSPF_SR_PARAMS, srp); return CMD_WARNING_CONFIG_FAILED; } - new->nhlfe.ifindex = ifp->ifindex; + srp->nhlfe.ifindex = ifp->ifindex; - /* Add this new SR Prefix if not already found */ - if (srp != new) - listnode_add(OspfSR.self->ext_prefix, new); + /* Add SR Prefix if new */ + if (!exist) + listnode_add(OspfSR.self->ext_prefix, srp); /* Update Prefix SID if SR is UP */ if (OspfSR.status == SR_UP) { - if (CHECK_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_NPFLG) - && !CHECK_FLAG(new->flags, EXT_SUBTLV_PREFIX_SID_EFLG)) - ospf_zebra_update_prefix_sid(new); + if (no_php_flag && !exp_null) + ospf_zebra_update_prefix_sid(srp); } else return CMD_SUCCESS; /* Finally, update Extended Prefix LSA id SR is UP */ - new->instance = ospf_ext_schedule_prefix_index( - ifp, new->sid, &new->prefv4, new->flags); - if (new->instance == 0) { + srp->instance = ospf_ext_schedule_prefix_index( + ifp, srp->sid, &srp->prefv4, srp->flags); + if (srp->instance == 0) { vty_out(vty, "Unable to set index %u for prefix %pFX\n", index, &p); return CMD_WARNING; @@ -2674,10 +2759,8 @@ static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json, srp->nhlfe.label_out); json_object_string_add(json_obj, "interface", itf ? itf->name : "-"); - json_object_string_add( - json_obj, "nexthop", - inet_ntop(AF_INET, &srp->nhlfe.nexthop, - buf, sizeof(buf))); + json_object_string_addf(json_obj, "nexthop", "%pI4", + &srp->nhlfe.nexthop); json_object_array_add(json_route, json_obj); } else { sbuf_push(sbuf, 0, "%20s %9s %15s\n", @@ -2712,10 +2795,8 @@ static void show_sr_prefix(struct sbuf *sbuf, struct json_object *json, path->srni.label_out); json_object_string_add(json_obj, "interface", itf ? itf->name : "-"); - json_object_string_add( - json_obj, "nexthop", - inet_ntop(AF_INET, &path->nexthop, - buf, sizeof(buf))); + json_object_string_addf(json_obj, "nexthop", "%pI4", + &path->nexthop); json_object_array_add(json_route, json_obj); } else { sbuf_push(sbuf, indent, "%20s %9s %15s\n", @@ -2755,9 +2836,8 @@ static void show_sr_node(struct vty *vty, struct json_object *json, if (json) { json_node = json_object_new_object(); - json_object_string_add(json_node, "routerID", - inet_ntop(AF_INET, &srn->adv_router, - buf, sizeof(buf))); + json_object_string_addf(json_node, "routerID", "%pI4", + &srn->adv_router); json_object_int_add(json_node, "srgbSize", srn->srgb.range_size); json_object_int_add(json_node, "srgbLabel", @@ -2846,10 +2926,8 @@ static void show_sr_node(struct vty *vty, struct json_object *json, srl->nhlfe[0].label_out); json_object_string_add(json_obj, "interface", itf ? itf->name : "-"); - json_object_string_add( - json_obj, "nexthop", - inet_ntop(AF_INET, &srl->nhlfe[0].nexthop, - buf, sizeof(buf))); + json_object_string_addf(json_obj, "nexthop", "%pI4", + &srl->nhlfe[0].nexthop); json_object_array_add(json_link, json_obj); /* Backup Link */ json_obj = json_object_new_object(); @@ -2862,10 +2940,8 @@ static void show_sr_node(struct vty *vty, struct json_object *json, srl->nhlfe[1].label_out); json_object_string_add(json_obj, "interface", itf ? itf->name : "-"); - json_object_string_add( - json_obj, "nexthop", - inet_ntop(AF_INET, &srl->nhlfe[1].nexthop, - buf, sizeof(buf))); + json_object_string_addf(json_obj, "nexthop", "%pI4", + &srl->nhlfe[1].nexthop); json_object_array_add(json_link, json_obj); } else { sbuf_push(&sbuf, 0, "%18s %21s %20s %9s %15s\n", @@ -2925,7 +3001,6 @@ DEFUN (show_ip_opsf_srdb, int idx = 0; struct in_addr rid; struct sr_node *srn; - char buf[PREFIX_STRLEN]; bool uj = use_json(argc, argv); json_object *json = NULL, *json_node_array = NULL; @@ -2937,10 +3012,8 @@ DEFUN (show_ip_opsf_srdb, if (uj) { json = json_object_new_object(); json_node_array = json_object_new_array(); - json_object_string_add( - json, "srdbID", - inet_ntop(AF_INET, &OspfSR.self->adv_router, - buf, sizeof(buf))); + json_object_string_addf(json, "srdbID", "%pI4", + &OspfSR.self->adv_router); json_object_object_add(json, "srNodes", json_node_array); } else { vty_out(vty, @@ -2951,12 +3024,8 @@ DEFUN (show_ip_opsf_srdb, if (argv_find(argv, argc, "self-originate", &idx)) { srn = OspfSR.self; show_sr_node(vty, json_node_array, srn); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -2970,12 +3039,8 @@ DEFUN (show_ip_opsf_srdb, srn = (struct sr_node *)hash_lookup(OspfSR.neighbors, (void *)&rid); show_sr_node(vty, json_node_array, srn); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -2984,9 +3049,7 @@ DEFUN (show_ip_opsf_srdb, hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *, void *))show_json_srdb, (void *)json_node_array); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { hash_iterate(OspfSR.neighbors, (void (*)(struct hash_bucket *, void *))show_vty_srdb, diff --git a/ospfd/ospf_sr.h b/ospfd/ospf_sr.h index d706d206fb..b153a220f5 100644 --- a/ospfd/ospf_sr.h +++ b/ospfd/ospf_sr.h @@ -38,7 +38,9 @@ #define SET_LABEL(label) ((label << 8) & SET_LABEL_MASK) #define GET_LABEL(label) ((label >> 8) & GET_LABEL_MASK) -#define OSPF_SR_DEFAULT_METRIC 1 +/* smallest configurable SRGB / SRLB sizes */ +#define MIN_SRLB_SIZE 16 +#define MIN_SRGB_SIZE 16 /* Segment Routing TLVs as per RFC 8665 */ @@ -221,7 +223,7 @@ struct sr_local_block { enum sid_type { PREF_SID, LOCAL_SID, ADJ_SID, LAN_ADJ_SID }; /* Status of Segment Routing: Off (Disable), On (Enable), (Up) Started */ -enum sr_status { SR_OFF, SR_ON, SR_UP, SR_DOWN }; +enum sr_status { SR_OFF, SR_ON, SR_UP }; /* Structure aggregating all OSPF Segment Routing information for the node */ struct ospf_sr_db { diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c index d95e677f6f..999bc49d91 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -87,7 +87,8 @@ static int ospf_mpls_te_del_if(struct interface *ifp); static void ospf_mpls_te_ism_change(struct ospf_interface *oi, int old_status); static void ospf_mpls_te_nsm_change(struct ospf_neighbor *nbr, int old_status); static void ospf_mpls_te_config_write_router(struct vty *vty); -static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa); +static void ospf_mpls_te_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa); static int ospf_mpls_te_lsa_originate_area(void *arg); static int ospf_mpls_te_lsa_inter_as_as(void *arg); static int ospf_mpls_te_lsa_inter_as_area(void *arg); @@ -2170,7 +2171,7 @@ static int ospf_te_parse_te(struct ls_ted *ted, struct ospf_lsa *lsa) if ((len == 0) || (ntohs(tlvh->type) != TE_TLV_LINK)) return 0; - sum = 0; + sum = sizeof(struct tlv_header); /* Browse sub-TLV and fulfill Link State Attributes */ for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { uint32_t val32, tab32[2]; @@ -2376,7 +2377,7 @@ static int ospf_te_delete_te(struct ls_ted *ted, struct ospf_lsa *lsa) if (ntohs(tlvh->type) == TE_TLV_ROUTER_ADDR) tlvh = TLV_HDR_NEXT(tlvh); len = TLV_BODY_SIZE(tlvh); - sum = 0; + sum = sizeof(struct tlv_header); /* Browse sub-TLV to find Link ID */ for (tlvh = TLV_DATA(tlvh); sum < len; tlvh = TLV_HDR_NEXT(tlvh)) { @@ -3783,7 +3784,8 @@ static uint16_t ospf_mpls_te_show_link_subtlv(struct vty *vty, return sum; } -static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) +static void ospf_mpls_te_show_info(struct vty *vty, struct json_object *json, + struct ospf_lsa *lsa) { struct lsa_header *lsah = lsa->data; struct tlv_header *tlvh, *next; @@ -3791,6 +3793,9 @@ static void ospf_mpls_te_show_info(struct vty *vty, struct ospf_lsa *lsa) uint16_t (*subfunc)(struct vty * vty, struct tlv_header * tlvh, uint16_t subtotal, uint16_t total) = NULL; + if (json) + return; + sum = 0; total = lsa->size - OSPF_LSA_HEADER_SIZE; @@ -4427,12 +4432,8 @@ DEFUN (show_ip_ospf_mpls_te_db, ls_show_ted(OspfMplsTE.ted, vty, json, verbose); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } diff --git a/ospfd/ospf_vty.c b/ospfd/ospf_vty.c index 4109ada64a..8cab6b9897 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -178,19 +178,11 @@ static void ospf_show_vrf_name(struct ospf *ospf, struct vty *vty, { if (use_vrf) { if (json) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_string_add(json, "vrfName", - "default"); - else - json_object_string_add(json, "vrfName", - ospf->name); + json_object_string_add(json, "vrfName", + ospf_get_name(ospf)); json_object_int_add(json, "vrfId", ospf->vrf_id); - } else { - if (ospf->vrf_id == VRF_DEFAULT) - vty_out(vty, "VRF Name: %s\n", "default"); - else if (ospf->name) - vty_out(vty, "VRF Name: %s\n", ospf->name); - } + } else + vty_out(vty, "VRF Name: %s\n", ospf_get_name(ospf)); } } @@ -230,8 +222,8 @@ DEFUN_NOSH (router_ospf, if (IS_DEBUG_OSPF_EVENT) zlog_debug( "Config command 'router ospf %d' received, vrf %s id %u oi_running %u", - ospf->instance, ospf->name ? ospf->name : "NIL", - ospf->vrf_id, ospf->oi_running); + ospf->instance, ospf_get_name(ospf), ospf->vrf_id, + ospf->oi_running); VTY_PUSH_CONTEXT(OSPF_NODE, ospf); @@ -453,7 +445,7 @@ DEFUN_HIDDEN (ospf_passive_interface_addr, "Please, use \"ip ospf passive\" on an interface instead.\n"); if (ospf->vrf_id != VRF_UNKNOWN) - ifp = if_get_by_name(argv[1]->arg, ospf->vrf_id); + ifp = if_get_by_name(argv[1]->arg, ospf->vrf_id, ospf->name); if (ifp == NULL) { vty_out(vty, "interface %s not found.\n", (char *)argv[1]->arg); @@ -514,7 +506,7 @@ DEFUN_HIDDEN (no_ospf_passive_interface, "Please, use \"no ip ospf passive\" on an interface instead.\n"); if (ospf->vrf_id != VRF_UNKNOWN) - ifp = if_get_by_name(argv[2]->arg, ospf->vrf_id); + ifp = if_get_by_name(argv[2]->arg, ospf->vrf_id, ospf->name); if (ifp == NULL) { vty_out(vty, "interface %s not found.\n", (char *)argv[2]->arg); @@ -571,8 +563,7 @@ DEFUN (ospf_network_area, if (IS_DEBUG_OSPF_EVENT) zlog_debug( "%s ospf vrf %s num of %u ip ospf area x config", - __func__, ospf->name ? ospf->name : "NIL", - count); + __func__, ospf_get_name(ospf), count); return CMD_WARNING_CONFIG_FAILED; } @@ -1784,7 +1775,7 @@ DEFUN (no_ospf_area_default_cost, DEFUN (ospf_area_export_list, ospf_area_export_list_cmd, - "area <A.B.C.D|(0-4294967295)> export-list NAME", + "area <A.B.C.D|(0-4294967295)> export-list ACCESSLIST4_NAME", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" @@ -1808,7 +1799,7 @@ DEFUN (ospf_area_export_list, DEFUN (no_ospf_area_export_list, no_ospf_area_export_list_cmd, - "no area <A.B.C.D|(0-4294967295)> export-list NAME", + "no area <A.B.C.D|(0-4294967295)> export-list ACCESSLIST4_NAME", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" @@ -1836,7 +1827,7 @@ DEFUN (no_ospf_area_export_list, DEFUN (ospf_area_import_list, ospf_area_import_list_cmd, - "area <A.B.C.D|(0-4294967295)> import-list NAME", + "area <A.B.C.D|(0-4294967295)> import-list ACCESSLIST4_NAME", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" @@ -1860,7 +1851,7 @@ DEFUN (ospf_area_import_list, DEFUN (no_ospf_area_import_list, no_ospf_area_import_list_cmd, - "no area <A.B.C.D|(0-4294967295)> import-list NAME", + "no area <A.B.C.D|(0-4294967295)> import-list ACCESSLIST4_NAME", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" @@ -1887,7 +1878,7 @@ DEFUN (no_ospf_area_import_list, DEFUN (ospf_area_filter_list, ospf_area_filter_list_cmd, - "area <A.B.C.D|(0-4294967295)> filter-list prefix WORD <in|out>", + "area <A.B.C.D|(0-4294967295)> filter-list prefix PREFIXLIST_NAME <in|out>", "OSPF area parameters\n" "OSPF area ID in IP address format\n" "OSPF area ID as a decimal value\n" @@ -1932,7 +1923,7 @@ DEFUN (ospf_area_filter_list, DEFUN (no_ospf_area_filter_list, no_ospf_area_filter_list_cmd, - "no area <A.B.C.D|(0-4294967295)> filter-list prefix WORD <in|out>", + "no area <A.B.C.D|(0-4294967295)> filter-list prefix PREFIXLIST_NAME <in|out>", NO_STR "OSPF area parameters\n" "OSPF area ID in IP address format\n" @@ -3052,7 +3043,6 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf, struct ospf_area *area; struct timeval result; char timebuf[OSPF_TIME_DUMP_SIZE]; - char buf[PREFIX_STRLEN]; json_object *json_vrf = NULL; json_object *json_areas = NULL; @@ -3077,9 +3067,8 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf, /* Show Router ID. */ if (json) { - json_object_string_add(json_vrf, "routerId", - inet_ntop(AF_INET, &ospf->router_id, - buf, sizeof(buf))); + json_object_string_addf(json_vrf, "routerId", "%pI4", + &ospf->router_id); } else { vty_out(vty, " OSPF Routing Process, Router ID: %pI4\n", &ospf->router_id); @@ -3343,12 +3332,8 @@ static int show_ip_ospf_common(struct vty *vty, struct ospf *ospf, if (json) { if (use_vrf) { json_object_object_add(json_vrf, "areas", json_areas); - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } else { json_object_object_add(json, "areas", json_areas); } @@ -3401,23 +3386,17 @@ DEFUN (show_ip_ospf, ret = show_ip_ospf_common(vty, ospf, json, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else if (!ospf_output) + if (uj) + vty_json(vty, json); + else if (!ospf_output) vty_out(vty, "%% OSPF instance not found\n"); return ret; } ospf = ospf_lookup_by_inst_name(inst, vrf_name); if ((ospf == NULL) || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -3426,12 +3405,9 @@ DEFUN (show_ip_ospf, ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); /* Display default ospf (instance 0) info */ if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -3481,11 +3457,8 @@ DEFUN (show_ip_ospf_instance, ret = show_ip_ospf_common(vty, ospf, json, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -3546,7 +3519,6 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, int is_up; struct ospf_neighbor *nbr; struct route_node *rn; - char buf[PREFIX_STRLEN]; uint32_t bandwidth = ifp->bandwidth ? ifp->bandwidth : ifp->speed; /* Is interface up? */ @@ -3616,11 +3588,9 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, /* Show OSPF interface information. */ if (use_json) { - json_object_string_add( - json_interface_sub, "ipAddress", - inet_ntop(AF_INET, - &oi->address->u.prefix4, - buf, sizeof(buf))); + json_object_string_addf( + json_interface_sub, "ipAddress", "%pI4", + &oi->address->u.prefix4); json_object_int_add(json_interface_sub, "ipAddressPrefixlen", oi->address->prefixlen); @@ -3650,17 +3620,13 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_interface_sub, "ospfIfType", dstr); if (oi->type == OSPF_IFTYPE_VIRTUALLINK) - json_object_string_add( - json_interface_sub, - "vlinkPeer", - inet_ntop(AF_INET, &dest, - buf, sizeof(buf))); + json_object_string_addf( + json_interface_sub, "vlinkPeer", + "%pI4", &dest); else - json_object_string_add( + json_object_string_addf( json_interface_sub, - "localIfUsed", - inet_ntop(AF_INET, &dest, - buf, sizeof(buf))); + "localIfUsed", "%pI4", &dest); } else vty_out(vty, " %s %pI4,", dstr, &dest); @@ -3672,10 +3638,8 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, json_object_boolean_true_add( json_interface_sub, "mtuMismatchDetect"); - json_object_string_add( - json_interface_sub, "routerId", - inet_ntop(AF_INET, &ospf->router_id, - buf, sizeof(buf))); + json_object_string_addf(json_interface_sub, "routerId", + "%pI4", &ospf->router_id); json_object_string_add(json_interface_sub, "networkType", ospf_network_type_str[oi->type]); @@ -3719,17 +3683,13 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, nbr = ospf_nbr_lookup_by_addr(oi->nbrs, &DR(oi)); if (nbr) { if (use_json) { - json_object_string_add( + json_object_string_addf( json_interface_sub, "drId", - inet_ntop(AF_INET, - &nbr->router_id, buf, - sizeof(buf))); - json_object_string_add( + "%pI4", &nbr->router_id); + json_object_string_addf( json_interface_sub, "drAddress", - inet_ntop( - AF_INET, - &nbr->address.u.prefix4, - buf, sizeof(buf))); + "%pI4", + &nbr->address.u.prefix4); } else { vty_out(vty, " Designated Router (ID) %pI4", @@ -3748,18 +3708,13 @@ static void show_ip_ospf_interface_sub(struct vty *vty, struct ospf *ospf, " No backup designated router on this network\n"); } else { if (use_json) { - json_object_string_add( + json_object_string_addf( json_interface_sub, "bdrId", - inet_ntop(AF_INET, - &nbr->router_id, - buf, sizeof(buf))); - json_object_string_add( + "%pI4", &nbr->router_id); + json_object_string_addf( json_interface_sub, - "bdrAddress", - inet_ntop(AF_INET, - &nbr->address.u - .prefix4, - buf, sizeof(buf))); + "bdrAddress", "%pI4", + &nbr->address.u.prefix4); } else { vty_out(vty, " Backup Designated Router (ID) %pI4,", @@ -3970,12 +3925,8 @@ static int show_ip_ospf_interface_common(struct vty *vty, struct ospf *ospf, if (use_json) { if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } } else vty_out(vty, "\n"); @@ -4115,14 +4066,9 @@ static int show_ip_ospf_interface_traffic_common( } if (use_json) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } else vty_out(vty, "\n"); @@ -4172,24 +4118,18 @@ DEFUN (show_ip_ospf_interface, uj); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else if (!ospf) + if (uj) + vty_json(vty, json); + else if (!ospf) vty_out(vty, "%% OSPF instance not found\n"); return ret; } ospf = ospf_lookup_by_inst_name(inst, vrf_name); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -4201,12 +4141,9 @@ DEFUN (show_ip_ospf_interface, /* Display default ospf (instance 0) info */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -4215,11 +4152,8 @@ DEFUN (show_ip_ospf_interface, use_vrf, json, uj); } - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4260,11 +4194,8 @@ DEFUN (show_ip_ospf_instance_interface, ret = show_ip_ospf_interface_common(vty, ospf, intf_name, 0, json, uj); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4315,12 +4246,8 @@ DEFUN (show_ip_ospf_interface_traffic, display_once = 1; } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4345,11 +4272,8 @@ DEFUN (show_ip_ospf_interface_traffic, vty, ospf, intf_name, json, display_once, use_vrf, uj); } - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4357,9 +4281,9 @@ DEFUN (show_ip_ospf_interface_traffic, static void show_ip_ospf_neighbour_header(struct vty *vty) { - vty_out(vty, "\n%-15s %3s %-15s %9s %-15s %-32s %5s %5s %5s\n", - "Neighbor ID", "Pri", "State", "Dead Time", "Address", - "Interface", "RXmtL", "RqstL", "DBsmL"); + vty_out(vty, "\n%-15s %-3s %-15s %-15s %-9s %-15s %-32s %5s %5s %5s\n", + "Neighbor ID", "Pri", "State", "Up Time", "Dead Time", + "Address", "Interface", "RXmtL", "RqstL", "DBsmL"); } static void show_ip_ospf_neighbor_sub(struct vty *vty, @@ -4369,9 +4293,11 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty, struct route_node *rn; struct ospf_neighbor *nbr, *prev_nbr = NULL; char msgbuf[16]; - char buf[PREFIX_STRLEN]; char timebuf[OSPF_TIME_DUMP_SIZE]; json_object *json_neighbor = NULL, *json_neigh_array = NULL; + struct timeval res = {.tv_sec = 0, .tv_usec = 0}; + long time_val = 0; + char uptime[OSPF_TIME_DUMP_SIZE]; for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) { if ((nbr = rn->info)) { @@ -4381,6 +4307,13 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty, /* Down state is not shown. */ if (nbr->state == NSM_Down) continue; + + if (nbr->ts_last_progress.tv_sec + || nbr->ts_last_progress.tv_usec) + time_val = monotime_since( + &nbr->ts_last_progress, &res) + / 1000LL; + if (use_json) { char neigh_str[INET_ADDRSTRLEN]; @@ -4412,13 +4345,23 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty, json_neighbor = json_object_new_object(); - ospf_nbr_state_message(nbr, msgbuf, 16); + ospf_nbr_ism_state_message(nbr, msgbuf, 16); json_object_int_add(json_neighbor, "priority", nbr->priority); json_object_string_add(json_neighbor, "state", msgbuf); + json_object_string_add( + json_neighbor, "converged", + lookup_msg(ospf_nsm_state_msg, + nbr->state, NULL)); + json_object_string_add( + json_neighbor, "role", + lookup_msg(ospf_ism_state_msg, + ospf_nbr_ism_state(nbr), + NULL)); + if (nbr->t_inactivity) { long time_store; @@ -4428,17 +4371,30 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty, NULL) / 1000LL; json_object_int_add(json_neighbor, + "upTimeInMsec", + time_val); + json_object_int_add(json_neighbor, "deadTimeMsecs", time_store); + json_object_string_add( + json_neighbor, "upTime", + ospf_timeval_dump( + &res, uptime, + sizeof(uptime))); + json_object_string_add( + json_neighbor, "deadTime", + ospf_timer_dump( + nbr->t_inactivity, + timebuf, + sizeof(timebuf))); } else { json_object_string_add(json_neighbor, "deadTimeMsecs", "inactive"); } - json_object_string_add( - json_neighbor, "address", - inet_ntop(AF_INET, &nbr->src, - buf, sizeof(buf))); + json_object_string_addf(json_neighbor, + "address", "%pI4", + &nbr->src); json_object_string_add(json_neighbor, "ifaceName", IF_NAME(oi)); @@ -4455,7 +4411,7 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty, json_object_array_add(json_neigh_array, json_neighbor); } else { - ospf_nbr_state_message(nbr, msgbuf, 16); + ospf_nbr_ism_state_message(nbr, msgbuf, 16); if (nbr->state == NSM_Attempt && nbr->router_id.s_addr == INADDR_ANY) @@ -4463,8 +4419,12 @@ static void show_ip_ospf_neighbor_sub(struct vty *vty, nbr->priority, msgbuf); else vty_out(vty, "%-15pI4 %3d %-15s ", - &nbr->router_id, - nbr->priority, msgbuf); + &nbr->router_id, nbr->priority, + msgbuf); + + vty_out(vty, "%-15s ", + ospf_timeval_dump(&res, uptime, + sizeof(uptime))); vty_out(vty, "%9s ", ospf_timer_dump(nbr->t_inactivity, @@ -4519,14 +4479,9 @@ static int show_ip_ospf_neighbor_common(struct vty *vty, struct ospf *ospf, if (use_json) { json_object_object_add(json_vrf, "neighbors", json_nbr_sub); - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } else vty_out(vty, "\n"); @@ -4571,12 +4526,9 @@ DEFUN (show_ip_ospf_neighbor, vty, ospf, json, uj, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else if (!ospf) + if (uj) + vty_json(vty, json); + else if (!ospf) vty_out(vty, "OSPF instance not found\n"); return ret; @@ -4584,12 +4536,9 @@ DEFUN (show_ip_ospf_neighbor, ospf = ospf_lookup_by_inst_name(inst, vrf_name); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -4598,12 +4547,9 @@ DEFUN (show_ip_ospf_neighbor, /* Display default ospf (instance 0) info */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -4658,11 +4604,8 @@ DEFUN (show_ip_ospf_instance_neighbor, ret = show_ip_ospf_neighbor_common(vty, ospf, json, uj, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4748,14 +4691,9 @@ static int show_ip_ospf_neighbor_all_common(struct vty *vty, struct ospf *ospf, } if (use_json) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } else vty_out(vty, "\n"); @@ -4801,12 +4739,8 @@ DEFUN (show_ip_ospf_neighbor_all, vty, ospf, json, uj, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4873,11 +4807,8 @@ DEFUN (show_ip_ospf_instance_neighbor_all, ret = show_ip_ospf_neighbor_all_common(vty, ospf, json, uj, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4922,11 +4853,9 @@ static int show_ip_ospf_neighbor_int_common(struct vty *vty, struct ospf *ospf, show_ip_ospf_neighbor_sub(vty, oi, json, use_json); } - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (use_json) + vty_json(vty, json); + else vty_out(vty, "\n"); return CMD_SUCCESS; @@ -5022,7 +4951,6 @@ static void show_ip_ospf_nbr_nbma_detail_sub(struct vty *vty, bool use_json, json_object *json) { char timebuf[OSPF_TIME_DUMP_SIZE]; - char buf[PREFIX_STRLEN]; json_object *json_sub = NULL; if (use_json) @@ -5032,9 +4960,8 @@ static void show_ip_ospf_nbr_nbma_detail_sub(struct vty *vty, /* Show interface address. */ if (use_json) - json_object_string_add(json_sub, "ifaceAddress", - inet_ntop(AF_INET, &nbr_nbma->addr, - buf, sizeof(buf))); + json_object_string_addf(json_sub, "ifaceAddress", "%pI4", + &nbr_nbma->addr); else vty_out(vty, " interface address %pI4\n", &nbr_nbma->addr); @@ -5107,7 +5034,6 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, char timebuf[OSPF_TIME_DUMP_SIZE]; json_object *json_neigh = NULL, *json_neigh_array = NULL; char neigh_str[INET_ADDRSTRLEN] = {0}; - char buf[PREFIX_STRLEN]; if (use_json) { if (prev_nbr && @@ -5144,10 +5070,8 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, /* Show interface address. */ if (use_json) - json_object_string_add(json_neigh, "ifaceAddress", - inet_ntop(AF_INET, - &nbr->address.u.prefix4, - buf, sizeof(buf))); + json_object_string_addf(json_neigh, "ifaceAddress", "%pI4", + &nbr->address.u.prefix4); else vty_out(vty, " interface address %pI4\n", &nbr->address.u.prefix4); @@ -5224,17 +5148,15 @@ static void show_ip_ospf_neighbor_detail_sub(struct vty *vty, /* Show Designated Rotuer ID. */ if (use_json) - json_object_string_add(json_neigh, "routerDesignatedId", - inet_ntop(AF_INET, &nbr->d_router, - buf, sizeof(buf))); + json_object_string_addf(json_neigh, "routerDesignatedId", + "%pI4", &nbr->d_router); else vty_out(vty, " DR is %pI4,", &nbr->d_router); /* Show Backup Designated Rotuer ID. */ if (use_json) - json_object_string_add(json_neigh, "routerDesignatedBackupId", - inet_ntop(AF_INET, &nbr->bd_router, - buf, sizeof(buf))); + json_object_string_addf(json_neigh, "routerDesignatedBackupId", + "%pI4", &nbr->bd_router); else vty_out(vty, " BDR is %pI4\n", &nbr->bd_router); @@ -5433,11 +5355,9 @@ static int show_ip_ospf_neighbor_id_common(struct vty *vty, struct ospf *ospf, } } - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (use_json) + vty_json(vty, json); + else vty_out(vty, "\n"); return CMD_SUCCESS; @@ -5541,14 +5461,9 @@ static int show_ip_ospf_neighbor_detail_common(struct vty *vty, if (use_json) { json_object_object_add(json_vrf, "neighbors", json_nbr_sub); - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } else vty_out(vty, "\n"); @@ -5593,12 +5508,8 @@ DEFUN (show_ip_ospf_neighbor_detail, ret = show_ip_ospf_neighbor_detail_common( vty, ospf, json, uj, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -5665,11 +5576,8 @@ DEFUN (show_ip_ospf_instance_neighbor_detail, ret = show_ip_ospf_neighbor_detail_common(vty, ospf, json, uj, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -5732,14 +5640,9 @@ static int show_ip_ospf_neighbor_detail_all_common(struct vty *vty, } if (use_json) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } else { vty_out(vty, "\n"); } @@ -5787,12 +5690,8 @@ DEFUN (show_ip_ospf_neighbor_detail_all, vty, ospf, json, uj, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -5860,11 +5759,8 @@ DEFUN (show_ip_ospf_instance_neighbor_detail_all, ret = show_ip_ospf_neighbor_detail_all_common(vty, ospf, json, uj, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -5920,11 +5816,9 @@ static int show_ip_ospf_neighbor_int_detail_common(struct vty *vty, } } - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (use_json) + vty_json(vty, json); + else vty_out(vty, "\n"); return CMD_SUCCESS; @@ -5999,7 +5893,6 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self, struct summary_lsa *sl; struct as_external_lsa *asel; struct prefix_ipv4 p; - char buf[PREFIX2STR_BUFFER]; if (lsa != NULL) /* If self option is set, check LSA self flag. */ @@ -6022,15 +5915,11 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self, ntohl(lsa->data->ls_seqnum)); snprintf(checksum, sizeof(checksum), "%x", ntohs(lsa->data->checksum)); - json_object_string_add( - json_lsa, "lsId", - inet_ntop(AF_INET, &lsa->data->id, - buf, sizeof(buf))); - json_object_string_add( - json_lsa, "advertisedRouter", - inet_ntop(AF_INET, - &lsa->data->adv_router, - buf, sizeof(buf))); + json_object_string_addf(json_lsa, "lsId", + "%pI4", &lsa->data->id); + json_object_string_addf( + json_lsa, "advertisedRouter", "%pI4", + &lsa->data->adv_router); json_object_int_add(json_lsa, "lsaAge", LS_AGE(lsa)); json_object_string_add( @@ -6062,10 +5951,9 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self, if (!json_lsa) vty_out(vty, " %pFX", &p); else { - prefix2str(&p, buf, sizeof(buf)); - json_object_string_add(json_lsa, - "summaryAddress", - buf); + json_object_string_addf( + json_lsa, "summaryAddress", + "%pFX", &p); } break; case OSPF_AS_EXTERNAL_LSA: @@ -6087,15 +5975,14 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self, (unsigned long)ntohl( asel->e[0].route_tag)); else { - prefix2str(&p, buf, sizeof(buf)); json_object_string_add( json_lsa, "metricType", IS_EXTERNAL_METRIC( asel->e[0].tos) ? "E2" : "E1"); - json_object_string_add(json_lsa, - "route", buf); + json_object_string_addf( + json_lsa, "route", "%pFX", &p); json_object_int_add( json_lsa, "tag", (unsigned long)ntohl( @@ -6166,7 +6053,6 @@ static const char *const show_database_header[] = { static void show_ip_ospf_database_header(struct vty *vty, struct ospf_lsa *lsa, json_object *json) { - char buf[PREFIX_STRLEN]; struct router_lsa *rlsa = (struct router_lsa *)lsa->data; if (!json) { @@ -6247,13 +6133,10 @@ static void show_ip_ospf_database_header(struct vty *vty, struct ospf_lsa *lsa, json_object_string_add( json, "lsaType", lookup_msg(ospf_lsa_type_msg, lsa->data->type, NULL)); - json_object_string_add(json, "linkStateId", - inet_ntop(AF_INET, &lsa->data->id, - buf, sizeof(buf))); - json_object_string_add(json, "advertisingRouter", - inet_ntop(AF_INET, - &lsa->data->adv_router, - buf, sizeof(buf))); + json_object_string_addf(json, "linkStateId", "%pI4", + &lsa->data->id); + json_object_string_addf(json, "advertisingRouter", "%pI4", + &lsa->data->adv_router); json_object_string_add(json, "lsaSeqNumber", seqnum); json_object_string_add(json, "checksum", checksum); json_object_int_add(json, "length", ntohs(lsa->data->length)); @@ -6482,7 +6365,6 @@ static int show_summary_asbr_lsa_detail(struct vty *vty, struct ospf_lsa *lsa, static int show_as_external_lsa_detail(struct vty *vty, struct ospf_lsa *lsa, json_object *json) { - char buf[PREFIX_STRLEN]; int tos = 0; if (lsa != NULL) { @@ -6517,10 +6399,8 @@ static int show_as_external_lsa_detail(struct vty *vty, struct ospf_lsa *lsa, json_object_int_add(json, "tos", tos); json_object_int_add(json, "metric", GET_METRIC(al->e[0].metric)); - json_object_string_add(json, "forwardAddress", - inet_ntop(AF_INET, - &(al->e[0].fwd_addr), - buf, sizeof(buf))); + json_object_string_addf(json, "forwardAddress", "%pI4", + &(al->e[0].fwd_addr)); json_object_int_add( json, "externalRouteTag", (route_tag_t)ntohl(al->e[0].route_tag)); @@ -6534,7 +6414,6 @@ static int show_as_external_lsa_detail(struct vty *vty, struct ospf_lsa *lsa, static int show_as_nssa_lsa_detail(struct vty *vty, struct ospf_lsa *lsa, json_object *json) { - char buf[PREFIX_STRLEN]; int tos = 0; if (lsa != NULL) { @@ -6570,10 +6449,8 @@ static int show_as_nssa_lsa_detail(struct vty *vty, struct ospf_lsa *lsa, json_object_int_add(json, "tos", tos); json_object_int_add(json, "metric", GET_METRIC(al->e[0].metric)); - json_object_string_add(json, "nssaForwardAddress", - inet_ntop(AF_INET, - &al->e[0].fwd_addr, - buf, sizeof(buf))); + json_object_string_addf(json, "nssaForwardAddress", + "%pI4", &al->e[0].fwd_addr); json_object_int_add( json, "externalRouteTag", (route_tag_t)ntohl(al->e[0].route_tag)); @@ -6965,15 +6842,11 @@ static void show_ip_ospf_database_maxage(struct vty *vty, struct ospf *ospf, json_lsa = json_object_new_object(); json_object_int_add(json_lsa, "linkType", lsa->data->type); - json_object_string_add( - json_lsa, "linkStateId", - inet_ntop(AF_INET, &lsa->data->id, - buf, sizeof(buf))); - json_object_string_add( - json_lsa, "advertisingRouter", - inet_ntop(AF_INET, - &lsa->data->adv_router, - buf, sizeof(buf))); + json_object_string_addf(json_lsa, "linkStateId", + "%pI4", &lsa->data->id); + json_object_string_addf( + json_lsa, "advertisingRouter", "%pI4", + &lsa->data->adv_router); json_object_int_add(json_lsa, "lsaLockCount", lsa->lock); json_object_object_add( @@ -7015,7 +6888,6 @@ static int show_ip_ospf_database_common(struct vty *vty, struct ospf *ospf, int idx_type = 4; int type, ret; struct in_addr id, adv_router; - char buf[PREFIX_STRLEN]; json_object *json_vrf = NULL; if (uj) { @@ -7037,9 +6909,8 @@ static int show_ip_ospf_database_common(struct vty *vty, struct ospf *ospf, /* Show Router ID. */ if (uj) { - json_object_string_add(json_vrf, "routerId", - inet_ntop(AF_INET, &ospf->router_id, - buf, sizeof(buf))); + json_object_string_addf(json_vrf, "routerId", "%pI4", + &ospf->router_id); } else { vty_out(vty, "\n OSPF Router with ID (%pI4)\n\n", &ospf->router_id); @@ -7049,14 +6920,9 @@ static int show_ip_ospf_database_common(struct vty *vty, struct ospf *ospf, if ((argc == arg_base + 4) || (uj && (argc == arg_base + 5))) { show_ip_ospf_database_summary(vty, ospf, 0, json_vrf); if (json) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add( + json, ospf_get_name(ospf), json_vrf); } return CMD_SUCCESS; } @@ -7077,27 +6943,17 @@ static int show_ip_ospf_database_common(struct vty *vty, struct ospf *ospf, else if (strncmp(argv[arg_base + idx_type]->text, "se", 2) == 0) { show_ip_ospf_database_summary(vty, ospf, 1, json_vrf); if (json) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add( + json, ospf_get_name(ospf), json_vrf); } return CMD_SUCCESS; } else if (strncmp(argv[arg_base + idx_type]->text, "m", 1) == 0) { show_ip_ospf_database_maxage(vty, ospf, json_vrf); if (json) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add( + json, ospf_get_name(ospf), json_vrf); } return CMD_SUCCESS; } else if (strncmp(argv[arg_base + idx_type]->text, "opaque-l", 8) == 0) @@ -7137,14 +6993,9 @@ static int show_ip_ospf_database_common(struct vty *vty, struct ospf *ospf, } if (json) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } return CMD_SUCCESS; @@ -7273,12 +7124,8 @@ DEFUN (show_ip_ospf_instance_database_max, show_ip_ospf_database_common(vty, ospf, 1, argc, argv, 0, json, uj); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -7309,7 +7156,6 @@ static int show_ip_ospf_database_type_adv_router_common(struct vty *vty, int idx_type = 4; int type, ret; struct in_addr adv_router; - char buf[PREFIX_STRLEN]; json_object *json_vrf = NULL; if (uj) { @@ -7331,9 +7177,8 @@ static int show_ip_ospf_database_type_adv_router_common(struct vty *vty, /* Show Router ID. */ if (uj) { - json_object_string_add(json_vrf, "routerId", - inet_ntop(AF_INET, &ospf->router_id, - buf, sizeof(buf))); + json_object_string_addf(json_vrf, "routerId", "%pI4", + &ospf->router_id); } else { vty_out(vty, "\n OSPF Router with ID (%pI4)\n\n", &ospf->router_id); @@ -7373,14 +7218,9 @@ static int show_ip_ospf_database_type_adv_router_common(struct vty *vty, show_lsa_detail_adv_router(vty, ospf, type, &adv_router, json_vrf); if (json) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } return CMD_SUCCESS; @@ -7497,12 +7337,8 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, show_ip_ospf_database_type_adv_router_common(vty, ospf, 1, argc, argv, 0, json, uj); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -8154,7 +7990,7 @@ static int ospf_vty_dead_interval_set(struct vty *vty, const char *interval_str, if (nbr_str) { struct ospf *ospf = NULL; - ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); + ospf = ifp->vrf->info; if (ospf) { oi = ospf_if_lookup_by_local_addr(ospf, ifp, addr); if (oi) @@ -8272,7 +8108,7 @@ DEFUN (no_ip_ospf_dead_interval, if (argc == 1) { struct ospf *ospf = NULL; - ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); + ospf = ifp->vrf->info; if (ospf) { oi = ospf_if_lookup_by_local_addr(ospf, ifp, addr); if (oi) @@ -8924,7 +8760,7 @@ DEFUN (ip_ospf_area, areaid = argv[idx + 1]->arg; if (!instance) - ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); + ospf = ifp->vrf->info; else ospf = ospf_lookup_instance(instance); @@ -8955,7 +8791,7 @@ DEFUN (ip_ospf_area, } if (count > 0) { - ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); + ospf = ifp->vrf->info; if (ospf) ospf_interface_area_unset(ospf, ifp); } @@ -9048,7 +8884,7 @@ DEFUN (no_ip_ospf_area, instance = strtol(argv[idx]->arg, NULL, 10); if (!instance) - ospf = ospf_lookup_by_vrf_id(ifp->vrf_id); + ospf = ifp->vrf->info; else ospf = ospf_lookup_instance(instance); @@ -9376,7 +9212,7 @@ DEFUN (no_ospf_redistribute_instance_source, DEFUN (ospf_distribute_list_out, ospf_distribute_list_out_cmd, - "distribute-list WORD out " FRR_REDIST_STR_OSPFD, + "distribute-list ACCESSLIST4_NAME out " FRR_REDIST_STR_OSPFD, "Filter networks in routing updates\n" "Access-list name\n" OUT_STR @@ -9398,7 +9234,7 @@ DEFUN (ospf_distribute_list_out, DEFUN (no_ospf_distribute_list_out, no_ospf_distribute_list_out_cmd, - "no distribute-list WORD out " FRR_REDIST_STR_OSPFD, + "no distribute-list ACCESSLIST4_NAME out " FRR_REDIST_STR_OSPFD, NO_STR "Filter networks in routing updates\n" "Access-list name\n" @@ -10187,14 +10023,9 @@ static int ospf_show_gr_helper_details(struct vty *vty, struct ospf *ospf, ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf); if (uj) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } else vty_out(vty, "\n"); @@ -10619,7 +10450,6 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf, struct ospf_route * or ; struct listnode *pnode, *pnnode; struct ospf_path *path; - char buf[PREFIX_STRLEN]; json_object *json_route = NULL, *json_nexthop_array = NULL, *json_nexthop = NULL; @@ -10649,11 +10479,9 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf, "N IA"); json_object_int_add(json_route, "cost", or->cost); - json_object_string_add( - json_route, "area", - inet_ntop(AF_INET, - &or->u.std.area_id, - buf1, sizeof(buf1))); + json_object_string_addf( + json_route, "area", "%pI4", + &or->u.std.area_id); } else { vty_out(vty, "N IA %-18s [%d] area: %pI4\n", @@ -10678,10 +10506,9 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf, "N"); json_object_int_add(json_route, "cost", or->cost); - json_object_string_add( - json_route, "area", - inet_ntop(AF_INET, &or->u.std.area_id, - buf1, sizeof(buf1))); + json_object_string_addf(json_route, "area", + "%pI4", + &or->u.std.area_id); } else { vty_out(vty, "N %-18s [%d] area: %pI4\n", buf1, or->cost, @@ -10732,14 +10559,10 @@ static void show_ip_ospf_route_network(struct vty *vty, struct ospf *ospf, } } else { if (json) { - json_object_string_add( + json_object_string_addf( json_nexthop, - "ip", - inet_ntop( - AF_INET, - &path->nexthop, - buf, - sizeof(buf))); + "ip", "%pI4", + &path->nexthop); json_object_string_add( json_nexthop, "via", @@ -10808,10 +10631,9 @@ static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf, if (json) { json_object_int_add(json_route, "cost", or->cost); - json_object_string_add( - json_route, "area", - inet_ntop(AF_INET, &or->u.std.area_id, - buf, sizeof(buf))); + json_object_string_addf(json_route, "area", + "%pI4", + &or->u.std.area_id); if (or->path_type == OSPF_PATH_INTER_AREA) json_object_boolean_true_add(json_route, "IA"); @@ -10876,13 +10698,10 @@ static void show_ip_ospf_route_router(struct vty *vty, struct ospf *ospf, } } else { if (json) { - json_object_string_add( + json_object_string_addf( json_nexthop, - "ip", - inet_ntop( - AF_INET, - &path->nexthop, - buf, sizeof(buf))); + "ip", "%pI4", + &path->nexthop); json_object_string_add( json_nexthop, "via", @@ -10915,7 +10734,6 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf, struct ospf_route *er; struct listnode *pnode, *pnnode; struct ospf_path *path; - char buf[PREFIX_STRLEN]; json_object *json_route = NULL, *json_nexthop_array = NULL, *json_nexthop = NULL; @@ -11006,13 +10824,9 @@ static void show_ip_ospf_route_external(struct vty *vty, struct ospf *ospf, } } else { if (json) { - json_object_string_add( + json_object_string_addf( json_nexthop, "ip", - inet_ntop( - AF_INET, - &path->nexthop, - buf, - sizeof(buf))); + "%pI4", &path->nexthop); json_object_string_add( json_nexthop, "via", ifindex2ifname( @@ -11183,12 +10997,8 @@ static int show_ip_ospf_route_common(struct vty *vty, struct ospf *ospf, if (use_vrf) { // json_object_object_add(json_vrf, "areas", // json_areas); - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } } else { vty_out(vty, "\n"); @@ -11241,11 +11051,7 @@ DEFUN (show_ip_ospf_route, if (uj) { /* Keep Non-pretty format */ - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, - JSON_C_TO_STRING_NOSLASHESCAPE)); - json_object_free(json); + vty_json(vty, json); } else if (!ospf_output) vty_out(vty, "%% OSPF instance not found\n"); @@ -11253,14 +11059,9 @@ DEFUN (show_ip_ospf_route, } ospf = ospf_lookup_by_inst_name(inst, vrf_name); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, - JSON_C_TO_STRING_PRETTY - | JSON_C_TO_STRING_NOSLASHESCAPE)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -11269,14 +11070,9 @@ DEFUN (show_ip_ospf_route, /* Display default ospf (instance 0) info */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, - JSON_C_TO_STRING_PRETTY - | JSON_C_TO_STRING_NOSLASHESCAPE)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -11338,7 +11134,6 @@ DEFUN (show_ip_ospf_vrfs, struct ospf *ospf = NULL; struct listnode *node = NULL; int count = 0; - char buf[PREFIX_STRLEN]; static const char header[] = "Name Id RouterId "; if (uj) { @@ -11358,10 +11153,7 @@ DEFUN (show_ip_ospf_vrfs, if (uj) json_vrf = json_object_new_object(); - if (ospf->vrf_id == VRF_DEFAULT) - name = VRF_DEFAULT_NAME; - else - name = ospf->name; + name = ospf_get_name(ospf); vrf_id_ui = (ospf->vrf_id == VRF_UNKNOWN) ? -1 @@ -11369,10 +11161,8 @@ DEFUN (show_ip_ospf_vrfs, if (uj) { json_object_int_add(json_vrf, "vrfId", vrf_id_ui); - json_object_string_add( - json_vrf, "routerId", - inet_ntop(AF_INET, &ospf->router_id, - buf, sizeof(buf))); + json_object_string_addf(json_vrf, "routerId", "%pI4", + &ospf->router_id); json_object_object_add(json_vrfs, name, json_vrf); @@ -11386,9 +11176,7 @@ DEFUN (show_ip_ospf_vrfs, json_object_object_add(json, "vrfs", json_vrfs); json_object_int_add(json, "totalVrfs", count); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { if (count) vty_out(vty, "\nTotal number of OSPF VRFs: %d\n", @@ -11623,14 +11411,9 @@ static int ospf_show_summary_address(struct vty *vty, struct ospf *ospf, } if (uj) { - if (use_vrf) { - if (ospf->vrf_id == VRF_DEFAULT) - json_object_object_add(json, "default", - json_vrf); - else - json_object_object_add(json, ospf->name, - json_vrf); - } + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); } else vty_out(vty, "\n"); @@ -11680,12 +11463,8 @@ DEFUN (show_ip_ospf_external_aggregator, vty, ospf, use_vrf, json, uj, detail); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -11693,12 +11472,9 @@ DEFUN (show_ip_ospf_external_aggregator, ospf = ospf_lookup_by_inst_name(inst, vrf_name); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -11709,12 +11485,9 @@ DEFUN (show_ip_ospf_external_aggregator, /* Default Vrf */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -11723,11 +11496,8 @@ DEFUN (show_ip_ospf_external_aggregator, ospf_show_summary_address(vty, ospf, use_vrf, json, uj, detail); } - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -11781,7 +11551,7 @@ static int config_write_interface_one(struct vty *vty, struct vrf *vrf) continue; vty_frame(vty, "!\n"); - if (ifp->vrf_id == VRF_DEFAULT) + if (ifp->vrf->vrf_id == VRF_DEFAULT) vty_frame(vty, "interface %s\n", ifp->name); else vty_frame(vty, "interface %s vrf %s\n", ifp->name, diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 2ba976af5a..b0ed66da5f 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -2102,25 +2102,33 @@ static int ospf_zebra_client_close_notify(ZAPI_CALLBACK_ARGS) return ret; } +static zclient_handler *const ospf_handlers[] = { + [ZEBRA_ROUTER_ID_UPDATE] = ospf_router_id_update_zebra, + [ZEBRA_INTERFACE_ADDRESS_ADD] = ospf_interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = ospf_interface_address_delete, + [ZEBRA_INTERFACE_LINK_PARAMS] = ospf_interface_link_params, + [ZEBRA_INTERFACE_VRF_UPDATE] = ospf_interface_vrf_update, + + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ospf_zebra_read_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ospf_zebra_read_route, + + [ZEBRA_OPAQUE_MESSAGE] = ospf_opaque_msg_handler, + + [ZEBRA_CLIENT_CLOSE_NOTIFY] = ospf_zebra_client_close_notify, +}; + void ospf_zebra_init(struct thread_master *master, unsigned short instance) { /* Allocate zebra structure. */ - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, ospf_handlers, + array_size(ospf_handlers)); zclient_init(zclient, ZEBRA_ROUTE_OSPF, instance, &ospfd_privs); zclient->zebra_connected = ospf_zebra_connected; - zclient->router_id_update = ospf_router_id_update_zebra; - zclient->interface_address_add = ospf_interface_address_add; - zclient->interface_address_delete = ospf_interface_address_delete; - zclient->interface_link_params = ospf_interface_link_params; - zclient->interface_vrf_update = ospf_interface_vrf_update; - - zclient->redistribute_route_add = ospf_zebra_read_route; - zclient->redistribute_route_del = ospf_zebra_read_route; /* Initialize special zclient for synchronous message exchanges. */ struct zclient_options options = zclient_options_default; options.synchronous = true; - zclient_sync = zclient_new(master, &options); + zclient_sync = zclient_new(master, &options, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_OSPF; zclient_sync->instance = instance; @@ -2135,10 +2143,6 @@ void ospf_zebra_init(struct thread_master *master, unsigned short instance) access_list_delete_hook(ospf_filter_update); prefix_list_add_hook(ospf_prefix_list_update); prefix_list_delete_hook(ospf_prefix_list_update); - - zclient->opaque_msg_handler = ospf_opaque_msg_handler; - - zclient->zebra_client_close_notify = ospf_zebra_client_close_notify; } void ospf_zebra_send_arp(const struct interface *ifp, const struct prefix *p) diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index 766be60778..05433ccb95 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -192,7 +192,7 @@ void ospf_process_refresh_data(struct ospf *ospf, bool reset) hit asserts in ospf_refresher_unregister_lsa(). This step is needed - because the current quagga code does look-up for + because the current frr code does look-up for self-originated LSAs based on the self router-id alone but expects OSPF_LSA_SELF to be @@ -582,6 +582,7 @@ static void ospf_deferred_shutdown_finish(struct ospf *ospf) /* ospfd being shut-down? If so, was this the last ospf instance? */ if (CHECK_FLAG(om->options, OSPF_MASTER_SHUTDOWN) && (listcount(om->ospf) == 0)) { + frr_fini(); exit(0); } @@ -1442,8 +1443,8 @@ void ospf_if_update(struct ospf *ospf, struct interface *ifp) if (IS_DEBUG_OSPF_EVENT) zlog_debug( - "%s: interface %s ifp->vrf_id %u ospf vrf %s vrf_id %u router_id %pI4", - __func__, ifp->name, ifp->vrf_id, + "%s: interface %s vrf %s(%u) ospf vrf %s vrf_id %u router_id %pI4", + __func__, ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, ospf_vrf_id_to_name(ospf->vrf_id), ospf->vrf_id, &ospf->router_id); diff --git a/pathd/path_cli.c b/pathd/path_cli.c index 46242fd05a..bfeea8c3db 100644 --- a/pathd/path_cli.c +++ b/pathd/path_cli.c @@ -298,14 +298,15 @@ DEFPY(srte_no_segment_list, return nb_cli_apply_changes(vty, NULL); } -void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode, +void cli_show_srte_segment_list(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " segment-list %s\n", yang_dnode_get_string(dnode, "./name")); } -void cli_show_srte_segment_list_end(struct vty *vty, struct lyd_node *dnode) +void cli_show_srte_segment_list_end(struct vty *vty, + const struct lyd_node *dnode) { vty_out(vty, " exit\n"); } @@ -557,7 +558,7 @@ DEFPY(srte_segment_list_no_segment, } void cli_show_srte_segment_list_segment(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " index %s", yang_dnode_get_string(dnode, "./index")); @@ -668,7 +669,7 @@ DEFPY(srte_no_policy, return nb_cli_apply_changes(vty, NULL); } -void cli_show_srte_policy(struct vty *vty, struct lyd_node *dnode, +void cli_show_srte_policy(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " policy color %s endpoint %s\n", @@ -676,7 +677,7 @@ void cli_show_srte_policy(struct vty *vty, struct lyd_node *dnode, yang_dnode_get_string(dnode, "./endpoint")); } -void cli_show_srte_policy_end(struct vty *vty, struct lyd_node *dnode) +void cli_show_srte_policy_end(struct vty *vty, const struct lyd_node *dnode) { vty_out(vty, " exit\n"); } @@ -708,8 +709,8 @@ DEFPY(srte_policy_no_name, } -void cli_show_srte_policy_name(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) +void cli_show_srte_policy_name(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) { vty_out(vty, " name %s\n", yang_dnode_get_string(dnode, NULL)); } @@ -741,7 +742,7 @@ DEFPY(srte_policy_no_binding_sid, } void cli_show_srte_policy_binding_sid(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " binding-sid %s\n", yang_dnode_get_string(dnode, NULL)); @@ -1187,7 +1188,7 @@ static int config_write_metric_cb(const struct lyd_node *dnode, void *arg) } void cli_show_srte_policy_candidate_path(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { float bandwidth; @@ -1253,7 +1254,7 @@ void cli_show_srte_policy_candidate_path(struct vty *vty, } void cli_show_srte_policy_candidate_path_end(struct vty *vty, - struct lyd_node *dnode) + const struct lyd_node *dnode) { const char *type = yang_dnode_get_string(dnode, "./type"); @@ -1265,7 +1266,7 @@ static int config_write_dnode(const struct lyd_node *dnode, void *arg) { struct vty *vty = arg; - nb_cli_show_dnode_cmds(vty, (struct lyd_node *)dnode, false); + nb_cli_show_dnode_cmds(vty, dnode, false); return YANG_ITER_CONTINUE; } diff --git a/pathd/path_main.c b/pathd/path_main.c index 7b702cca31..0a71c80ef0 100644 --- a/pathd/path_main.c +++ b/pathd/path_main.c @@ -83,7 +83,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t path_signals[] = { +struct frr_signal_t path_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/pathd/path_nb.h b/pathd/path_nb.h index 6a918b8b82..dacc5eb0d8 100644 --- a/pathd/path_nb.h +++ b/pathd/path_nb.h @@ -110,23 +110,26 @@ int pathd_srte_policy_candidate_path_segment_list_name_destroy( void pathd_apply_finish(struct nb_cb_apply_finish_args *args); /* Optional 'cli_show' callbacks. */ -void cli_show_srte_segment_list(struct vty *vty, struct lyd_node *dnode, +void cli_show_srte_segment_list(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_srte_segment_list_end(struct vty *vty, struct lyd_node *dnode); -void cli_show_srte_segment_list_segment(struct vty *vty, struct lyd_node *dnode, +void cli_show_srte_segment_list_end(struct vty *vty, + const struct lyd_node *dnode); +void cli_show_srte_segment_list_segment(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_srte_policy(struct vty *vty, struct lyd_node *dnode, +void cli_show_srte_policy(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_srte_policy_end(struct vty *vty, struct lyd_node *dnode); -void cli_show_srte_policy_name(struct vty *vty, struct lyd_node *dnode, +void cli_show_srte_policy_end(struct vty *vty, const struct lyd_node *dnode); +void cli_show_srte_policy_name(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_srte_policy_binding_sid(struct vty *vty, struct lyd_node *dnode, +void cli_show_srte_policy_binding_sid(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); void cli_show_srte_policy_candidate_path(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); void cli_show_srte_policy_candidate_path_end(struct vty *vty, - struct lyd_node *dnode); + const struct lyd_node *dnode); /* Utility functions */ typedef void (*of_pref_cp_t)(enum objfun_type type, void *arg); diff --git a/pathd/path_pcep_controller.c b/pathd/path_pcep_controller.c index 449c40c16c..162c53590f 100644 --- a/pathd/path_pcep_controller.c +++ b/pathd/path_pcep_controller.c @@ -38,14 +38,6 @@ #define MAX_RECONNECT_DELAY 120 -#define min(a, b) \ - ({ \ - __typeof__(a) _a = (a); \ - __typeof__(b) _b = (b); \ - _a <= _b ? _a : _b; \ - }) - - /* Event handling data structures */ enum pcep_ctrl_event_type { EV_UPDATE_PCC_OPTS = 1, @@ -1078,7 +1070,7 @@ void remove_pcc_state(struct ctrl_state *ctrl_state, uint32_t backoff_delay(uint32_t max, uint32_t base, uint32_t retry_count) { - uint32_t a = min(max, base * (1 << retry_count)); + uint32_t a = MIN(max, base * (1 << retry_count)); uint64_t r = frr_weak_random(), m = RAND_MAX; uint32_t b = (a / 2) + (r * (a / 2)) / m; return b; diff --git a/pathd/path_ted.c b/pathd/path_ted.c index d17b5a0aab..ff9bc82f39 100644 --- a/pathd/path_ted.c +++ b/pathd/path_ted.c @@ -447,7 +447,7 @@ DEFUN (no_path_ted_import, } /* clang-format off */ -DEFPY (show_pahtd_ted_db, +DEFPY (show_pathd_ted_db, show_pathd_ted_db_cmd, "show pathd ted database <verbose|json>$ver_json ", "show command\n" @@ -471,12 +471,8 @@ DEFPY (show_pahtd_ted_db, } /* Show the complete TED */ ls_show_ted(ted_state_g.ted, vty, json, !st_json); - if (st_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (st_json) + vty_json(vty, json); return CMD_SUCCESS; } diff --git a/pathd/path_zebra.c b/pathd/path_zebra.c index 53d834f360..156267a394 100644 --- a/pathd/path_zebra.c +++ b/pathd/path_zebra.c @@ -320,6 +320,12 @@ static int path_zebra_opaque_msg_handler(ZAPI_CALLBACK_ARGS) return ret; } +static zclient_handler *const path_handlers[] = { + [ZEBRA_SR_POLICY_NOTIFY_STATUS] = path_zebra_sr_policy_notify_status, + [ZEBRA_ROUTER_ID_UPDATE] = path_zebra_router_id_update, + [ZEBRA_OPAQUE_MESSAGE] = path_zebra_opaque_msg_handler, +}; + /** * Initializes Zebra asynchronous connection. * @@ -331,15 +337,13 @@ void path_zebra_init(struct thread_master *master) options.synchronous = true; /* Initialize asynchronous zclient. */ - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, path_handlers, + array_size(path_handlers)); zclient_init(zclient, ZEBRA_ROUTE_SRTE, 0, &pathd_privs); zclient->zebra_connected = path_zebra_connected; - zclient->sr_policy_notify_status = path_zebra_sr_policy_notify_status; - zclient->router_id_update = path_zebra_router_id_update; - zclient->opaque_msg_handler = path_zebra_opaque_msg_handler; /* Initialize special zclient for synchronous message exchanges. */ - zclient_sync = zclient_new(master, &options); + zclient_sync = zclient_new(master, &options, NULL, 0); zclient_sync->sock = -1; zclient_sync->redist_default = ZEBRA_ROUTE_SRTE; zclient_sync->instance = 1; diff --git a/pathd/pathd.c b/pathd/pathd.c index 90b8727284..7f6d34f752 100644 --- a/pathd/pathd.c +++ b/pathd/pathd.c @@ -22,6 +22,7 @@ #include "log.h" #include "lib_errors.h" #include "network.h" +#include "libfrr.h" #include "pathd/pathd.h" #include "pathd/path_zebra.h" @@ -1223,6 +1224,7 @@ void pathd_shutdown(void) { path_ted_teardown(); srte_clean_zebra(); + frr_fini(); } void trigger_pathd_candidate_created(struct srte_candidate *candidate) diff --git a/pbrd/pbr_main.c b/pbrd/pbr_main.c index c7cbbb4462..59aa3676bf 100644 --- a/pbrd/pbr_main.c +++ b/pbrd/pbr_main.c @@ -95,7 +95,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t pbr_signals[] = { +struct frr_signal_t pbr_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/pbrd/pbr_map.c b/pbrd/pbr_map.c index 053b7363a3..03e6bacf1e 100644 --- a/pbrd/pbr_map.c +++ b/pbrd/pbr_map.c @@ -178,9 +178,9 @@ static void pbr_map_pbrms_uninstall(struct pbr_map_sequence *pbrms) } static const char *const pbr_map_reason_str[] = { - "Invalid NH-group", "Invalid NH", "No Nexthops", - "Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF", - "Deleting Sequence", + "Invalid NH-group", "Invalid NH", "No Nexthops", + "Both NH and NH-Group", "Invalid Src or Dst", "Invalid VRF", + "Both VLAN Set and Strip", "Deleting Sequence", }; void pbr_map_reason_string(unsigned int reason, char *buf, int size) @@ -539,6 +539,13 @@ struct pbr_map_sequence *pbrms_get(const char *name, uint32_t seqno) pbrms->seqno = seqno; pbrms->ruleno = pbr_nht_get_next_rule(seqno); pbrms->parent = pbrm; + + pbrms->action_vlan_id = 0; + pbrms->action_vlan_flags = 0; + pbrms->action_pcp = 0; + + pbrms->action_queue_id = PBR_MAP_UNDEFINED_QUEUE_ID; + pbrms->reason = PBR_MAP_INVALID_EMPTY | PBR_MAP_INVALID_NO_NEXTHOPS; @@ -601,10 +608,28 @@ pbr_map_sequence_check_nexthops_valid(struct pbr_map_sequence *pbrms) static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms) { - if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield) + if (!pbrms->src && !pbrms->dst && !pbrms->mark && !pbrms->dsfield + && !pbrms->action_vlan_id && !pbrms->action_vlan_flags + && !pbrms->action_pcp + && pbrms->action_queue_id == PBR_MAP_UNDEFINED_QUEUE_ID) pbrms->reason |= PBR_MAP_INVALID_EMPTY; } +static void pbr_map_sequence_check_vlan_actions(struct pbr_map_sequence *pbrms) +{ + /* The set vlan tag action does the following: + * 1. If the frame is untagged, it tags the frame with the + * configured VLAN ID. + * 2. If the frame is tagged, if replaces the tag. + * + * The strip vlan action removes any inner tag, so it is invalid to + * specify both a set and strip action. + */ + if ((pbrms->action_vlan_id != 0) && (pbrms->action_vlan_flags != 0)) + pbrms->reason |= PBR_MAP_INVALID_SET_STRIP_VLAN; +} + + /* * Checks to see if we think that the pbmrs is valid. If we think * the config is valid return true. @@ -612,7 +637,7 @@ static void pbr_map_sequence_check_not_empty(struct pbr_map_sequence *pbrms) static void pbr_map_sequence_check_valid(struct pbr_map_sequence *pbrms) { pbr_map_sequence_check_nexthops_valid(pbrms); - + pbr_map_sequence_check_vlan_actions(pbrms); pbr_map_sequence_check_not_empty(pbrms); } diff --git a/pbrd/pbr_map.h b/pbrd/pbr_map.h index 694b915f48..3527523fc1 100644 --- a/pbrd/pbr_map.h +++ b/pbrd/pbr_map.h @@ -104,6 +104,17 @@ struct pbr_map_sequence { uint32_t mark; /* + * Actions + */ + uint8_t action_pcp; + uint8_t action_vlan_id; +#define PBR_MAP_STRIP_INNER_ANY (1 << 0) + uint8_t action_vlan_flags; + +#define PBR_MAP_UNDEFINED_QUEUE_ID 0 + uint32_t action_queue_id; + + /* * Family of the src/dst. Needed when deleting since we clear them */ unsigned char family; @@ -158,6 +169,7 @@ struct pbr_map_sequence { #define PBR_MAP_INVALID_BOTH_NHANDGRP (1 << 3) #define PBR_MAP_INVALID_EMPTY (1 << 4) #define PBR_MAP_INVALID_VRF (1 << 5) +#define PBR_MAP_INVALID_SET_STRIP_VLAN (1 << 6) uint64_t reason; QOBJ_FIELDS; diff --git a/pbrd/pbr_vrf.c b/pbrd/pbr_vrf.c index 1b69e23ce3..c3558ab591 100644 --- a/pbrd/pbr_vrf.c +++ b/pbrd/pbr_vrf.c @@ -92,17 +92,6 @@ static int pbr_vrf_delete(struct vrf *vrf) return 0; } -struct pbr_vrf *pbr_vrf_lookup_by_id(vrf_id_t vrf_id) -{ - struct vrf *vrf; - - vrf = vrf_lookup_by_id(vrf_id); - if (vrf) - return ((struct pbr_vrf *)vrf->info); - - return NULL; -} - struct pbr_vrf *pbr_vrf_lookup_by_name(const char *name) { struct vrf *vrf; diff --git a/pbrd/pbr_vrf.h b/pbrd/pbr_vrf.h index 5953387de2..e37bcd42ba 100644 --- a/pbrd/pbr_vrf.h +++ b/pbrd/pbr_vrf.h @@ -34,7 +34,6 @@ static inline vrf_id_t pbr_vrf_id(const struct pbr_vrf *pbr_vrf) return pbr_vrf->vrf->vrf_id; } -extern struct pbr_vrf *pbr_vrf_lookup_by_id(vrf_id_t vrf_id); extern struct pbr_vrf *pbr_vrf_lookup_by_name(const char *name); extern bool pbr_vrf_is_valid(const struct pbr_vrf *pbr_vrf); extern bool pbr_vrf_is_enabled(const struct pbr_vrf *pbr_vrf); diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index d083b9d2b0..ebcbbb7205 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -407,6 +407,82 @@ static void pbrms_clear_set_config(struct pbr_map_sequence *pbrms) pbrms->nhs_installed = false; } + +DEFPY(pbr_map_action_queue_id, pbr_map_action_queue_id_cmd, + "[no] set queue-id <(1-65535)$queue_id>", + NO_STR + "Set the rest of the command\n" + "Set based on egress port queue id\n" + "A valid value in range 1..65535 \n") +{ + struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + + if (!no) + pbrms->action_queue_id = queue_id; + else if ((uint32_t)queue_id == pbrms->action_queue_id) + pbrms->action_queue_id = PBR_MAP_UNDEFINED_QUEUE_ID; + + pbr_map_check(pbrms, true); + + return CMD_SUCCESS; +} + +DEFPY(pbr_map_action_pcp, pbr_map_action_pcp_cmd, "[no] set pcp <(0-7)$pcp>", + NO_STR + "Set the rest of the command\n" + "Set based on 802.1p Priority Code Point (PCP) value\n" + "A valid value in range 0..7\n") +{ + struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + + if (!no) + pbrms->action_pcp = pcp; + else if (pcp == pbrms->action_pcp) + pbrms->action_pcp = 0; + + pbr_map_check(pbrms, true); + + return CMD_SUCCESS; +} + +DEFPY(pbr_map_action_vlan_id, pbr_map_action_vlan_id_cmd, + "[no] set vlan <(1-4094)$vlan_id>", + NO_STR + "Set the rest of the command\n" + "Set action for VLAN tagging\n" + "A valid value in range 1..4094\n") +{ + struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + + if (!no) + pbrms->action_vlan_id = vlan_id; + else if (pbrms->action_vlan_id == vlan_id) + pbrms->action_vlan_id = 0; + + pbr_map_check(pbrms, true); + + return CMD_SUCCESS; +} + +DEFPY(pbr_map_action_strip_vlan, pbr_map_action_strip_vlan_cmd, + "[no] strip vlan", + NO_STR + "Strip the vlan tags from frame\n" + "Strip any inner vlan tag \n") +{ + struct pbr_map_sequence *pbrms = VTY_GET_CONTEXT(pbr_map_sequence); + + if (!no) + pbrms->action_vlan_flags = PBR_MAP_STRIP_INNER_ANY; + else + pbrms->action_vlan_flags = 0; + + pbr_map_check(pbrms, true); + + return CMD_SUCCESS; +} + + DEFPY(pbr_map_nexthop_group, pbr_map_nexthop_group_cmd, "set nexthop-group NHGNAME$name", "Set for the PBR-MAP\n" @@ -485,24 +561,43 @@ DEFPY(pbr_map_nexthop, pbr_map_nexthop_cmd, nhop.vrf_id = vrf->vrf_id; if (intf) { - struct interface *ifp; + struct interface *ifp = NULL; + struct interface *ifptmp; + struct vrf *vrftmp; + int count = 0; + + if (vrf_is_backend_netns() && vrf_name) { + ifp = if_lookup_by_name_vrf(intf, vrf); + } else { + RB_FOREACH (vrftmp, vrf_name_head, &vrfs_by_name) { + ifptmp = if_lookup_by_name_vrf(intf, vrftmp); + if (ifptmp) { + ifp = ifptmp; + count++; + if (!vrf_is_backend_netns()) + break; + } + } + } - ifp = if_lookup_by_name_all_vrf(intf); if (!ifp) { vty_out(vty, "Specified Intf %s does not exist\n", intf); return CMD_WARNING_CONFIG_FAILED; } - if (ifp->vrf_id != vrf->vrf_id) { - struct vrf *actual; - - actual = vrf_lookup_by_id(ifp->vrf_id); + if (count > 1) { vty_out(vty, - "Specified Intf %s is not in vrf %s but is in vrf %s, using actual vrf\n", - ifp->name, vrf->name, actual->name); + "Specified Intf %s exists in multiple VRFs\n", + intf); + vty_out(vty, "You must specify the nexthop-vrf\n"); + return CMD_WARNING_CONFIG_FAILED; } + if (ifp->vrf->vrf_id != vrf->vrf_id) + vty_out(vty, + "Specified Intf %s is not in vrf %s but is in vrf %s, using actual vrf\n", + ifp->name, vrf->name, ifp->vrf->name); nhop.ifindex = ifp->ifindex; - nhop.vrf_id = ifp->vrf_id; + nhop.vrf_id = ifp->vrf->vrf_id; } if (addr) { @@ -764,6 +859,18 @@ static void vty_show_pbrms(struct vty *vty, if (pbrms->mark) vty_out(vty, " MARK Match: %u\n", pbrms->mark); + if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID) + vty_out(vty, " Set Queue ID %u\n", + pbrms->action_queue_id); + + if (pbrms->action_vlan_id != 0) + vty_out(vty, " Set VLAN ID %u\n", pbrms->action_vlan_id); + if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY) + vty_out(vty, " Strip VLAN ID\n"); + if (pbrms->action_pcp) + vty_out(vty, " Set PCP %u\n", pbrms->action_pcp); + + if (pbrms->nhgrp_name) { vty_out(vty, " Nexthop-Group: %s\n", pbrms->nhgrp_name); @@ -810,7 +917,6 @@ static void vty_json_pbrms(json_object *j, struct vty *vty, json_object *jpbrm, *nexthop_group; char *nhg_name = pbrms->nhgrp_name ? pbrms->nhgrp_name : pbrms->internal_nhg_name; - char buf[PREFIX_STRLEN]; char rbuf[64]; jpbrm = json_object_new_object(); @@ -846,13 +952,9 @@ static void vty_json_pbrms(json_object *j, struct vty *vty, json_object_string_add(jpbrm, "vrfName", pbrms->vrf_name); if (pbrms->src) - json_object_string_add( - jpbrm, "matchSrc", - prefix2str(pbrms->src, buf, sizeof(buf))); + json_object_string_addf(jpbrm, "matchSrc", "%pFX", pbrms->src); if (pbrms->dst) - json_object_string_add( - jpbrm, "matchDst", - prefix2str(pbrms->dst, buf, sizeof(buf))); + json_object_string_addf(jpbrm, "matchDst", "%pFX", pbrms->dst); if (pbrms->mark) json_object_int_add(jpbrm, "matchMark", pbrms->mark); if (pbrms->dsfield & PBR_DSFIELD_DSCP) @@ -930,12 +1032,8 @@ DEFPY (show_pbr_map, vty_show_pbr_map(vty, pbrm, detail); } - if (j) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - j, JSON_C_TO_STRING_PRETTY)); - json_object_free(j); - } + if (j) + vty_json(vty, j); return CMD_SUCCESS; } @@ -957,11 +1055,7 @@ DEFPY(show_pbr_nexthop_group, if (j) { pbr_nht_json_nexthop_group(j, word); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - j, JSON_C_TO_STRING_PRETTY)); - - json_object_free(j); + vty_json(vty, j); } else pbr_nht_show_nexthop_group(vty, word); @@ -1035,12 +1129,8 @@ DEFPY (show_pbr_interface, } } - if (j) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - j, JSON_C_TO_STRING_PRETTY)); - json_object_free(j); - } + if (j) + vty_json(vty, j); return CMD_SUCCESS; } @@ -1170,6 +1260,19 @@ static int pbr_vty_map_config_write_sequence(struct vty *vty, if (pbrms->mark) vty_out(vty, " match mark %u\n", pbrms->mark); + + if (pbrms->action_queue_id != PBR_MAP_UNDEFINED_QUEUE_ID) + vty_out(vty, " set queue-id %d\n", pbrms->action_queue_id); + + if (pbrms->action_pcp) + vty_out(vty, " set pcp %d\n", pbrms->action_pcp); + + if (pbrms->action_vlan_id) + vty_out(vty, " set vlan %u\n", pbrms->action_vlan_id); + + if (pbrms->action_vlan_flags == PBR_MAP_STRIP_INNER_ANY) + vty_out(vty, " strip vlan any\n"); + if (pbrms->vrf_unchanged) vty_out(vty, " set vrf unchanged\n"); @@ -1257,6 +1360,10 @@ void pbr_vty_init(void) install_element(PBRMAP_NODE, &pbr_map_match_dscp_cmd); install_element(PBRMAP_NODE, &pbr_map_match_ecn_cmd); install_element(PBRMAP_NODE, &pbr_map_match_mark_cmd); + install_element(PBRMAP_NODE, &pbr_map_action_queue_id_cmd); + install_element(PBRMAP_NODE, &pbr_map_action_strip_vlan_cmd); + install_element(PBRMAP_NODE, &pbr_map_action_vlan_id_cmd); + install_element(PBRMAP_NODE, &pbr_map_action_pcp_cmd); install_element(PBRMAP_NODE, &pbr_map_nexthop_group_cmd); install_element(PBRMAP_NODE, &no_pbr_map_nexthop_group_cmd); install_element(PBRMAP_NODE, &pbr_map_nexthop_cmd); diff --git a/pbrd/pbr_zebra.c b/pbrd/pbr_zebra.c index 28def509d5..b480d4072e 100644 --- a/pbrd/pbr_zebra.c +++ b/pbrd/pbr_zebra.c @@ -429,20 +429,24 @@ static int pbr_zebra_nexthop_update(ZAPI_CALLBACK_ARGS) extern struct zebra_privs_t pbr_privs; +static zclient_handler *const pbr_handlers[] = { + [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, + [ZEBRA_INTERFACE_VRF_UPDATE] = interface_vrf_update, + [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner, + [ZEBRA_RULE_NOTIFY_OWNER] = rule_notify_owner, + [ZEBRA_NEXTHOP_UPDATE] = pbr_zebra_nexthop_update, +}; + void pbr_zebra_init(void) { struct zclient_options opt = { .receive_notify = true }; - zclient = zclient_new(master, &opt); + zclient = zclient_new(master, &opt, pbr_handlers, + array_size(pbr_handlers)); zclient_init(zclient, ZEBRA_ROUTE_PBR, 0, &pbr_privs); zclient->zebra_connected = zebra_connected; - zclient->interface_address_add = interface_address_add; - zclient->interface_address_delete = interface_address_delete; - zclient->interface_vrf_update = interface_vrf_update; - zclient->route_notify_owner = route_notify_owner; - zclient->rule_notify_owner = rule_notify_owner; - zclient->nexthop_update = pbr_zebra_nexthop_update; } void pbr_send_rnh(struct nexthop *nhop, bool reg) @@ -478,7 +482,7 @@ void pbr_send_rnh(struct nexthop *nhop, bool reg) break; } - if (zclient_send_rnh(zclient, command, &p, false, nhop->vrf_id) + if (zclient_send_rnh(zclient, command, &p, false, false, nhop->vrf_id) == ZCLIENT_SEND_FAILURE) { zlog_warn("%s: Failure to send nexthop to zebra", __func__); } @@ -509,7 +513,7 @@ pbr_encode_pbr_map_sequence_vrf(struct stream *s, struct pbr_vrf *pbr_vrf; if (pbrms->vrf_unchanged) - pbr_vrf = pbr_vrf_lookup_by_id(ifp->vrf_id); + pbr_vrf = ifp->vrf->info; else pbr_vrf = pbr_vrf_lookup_by_name(pbrms->vrf_name); @@ -542,6 +546,12 @@ static void pbr_encode_pbr_map_sequence(struct stream *s, stream_putc(s, pbrms->dsfield); stream_putl(s, pbrms->mark); + stream_putl(s, pbrms->action_queue_id); + + stream_putw(s, pbrms->action_vlan_id); + stream_putw(s, pbrms->action_vlan_flags); + stream_putw(s, pbrms->action_pcp); + if (pbrms->vrf_unchanged || pbrms->vrf_lookup) pbr_encode_pbr_map_sequence_vrf(s, pbrms, ifp); else if (pbrms->nhgrp_name) diff --git a/pceplib/pcep_msg_objects.h b/pceplib/pcep_msg_objects.h index f26618e291..270db4aa8d 100644 --- a/pceplib/pcep_msg_objects.h +++ b/pceplib/pcep_msg_objects.h @@ -367,7 +367,7 @@ enum pcep_lsp_operational_status { }; #define MAX_PLSP_ID 0x000fffff /* The plsp_id is only 20 bits */ -#define MAX_LSP_STATUS 0x0007 /* The status is only 3 bits */ +#define MAX_LSP_STATUS 0x0007 /* The status is only 3 bits */ #define OBJECT_LSP_FLAG_D 0x01 #define OBJECT_LSP_FLAG_S 0x02 #define OBJECT_LSP_FLAG_R 0x04 diff --git a/pceplib/pcep_msg_tools.c b/pceplib/pcep_msg_tools.c index 8f32f2c537..f7c25f447b 100644 --- a/pceplib/pcep_msg_tools.c +++ b/pceplib/pcep_msg_tools.c @@ -144,14 +144,15 @@ double_linked_list *pcep_msg_read(int sock_fd) "%s: pcep_msg_read: Message not fully read! Trying to read %d bytes more, fd [%d]", __func__, read_len, sock_fd); - if (PCEP_MESSAGE_LENGTH - ret - buffer_read >= read_len ) + if (PCEP_MESSAGE_LENGTH - ret - buffer_read >= read_len) read_ret = read(sock_fd, &buffer[ret], read_len); else { pcep_log( LOG_ERR, "%s: Trying to read size (%d) offset (%d) in a buff of size (%d)", - __func__, read_len, ret, PCEP_MESSAGE_LENGTH); + __func__, read_len, ret, + PCEP_MESSAGE_LENGTH); return msg_list; } diff --git a/pceplib/pcep_pcc.c b/pceplib/pcep_pcc.c index d263f64f39..649704f55b 100644 --- a/pceplib/pcep_pcc.c +++ b/pceplib/pcep_pcc.c @@ -273,7 +273,7 @@ void send_pce_report_message(pcep_session *session) pcep_log(LOG_WARNING, "%s: send_pce_report_message SRP object was NULL", __func__); - dll_destroy_with_data(report_list); + dll_destroy_with_data(report_list); return; } dll_append(report_list, obj); @@ -314,7 +314,7 @@ void send_pce_report_message(pcep_session *session) pcep_log(LOG_WARNING, "%s: send_pce_report_message LSP object was NULL", __func__); - dll_destroy_with_data(report_list); + dll_destroy_with_data(report_list); return; } dll_append(report_list, obj); @@ -351,7 +351,7 @@ void send_pce_report_message(pcep_session *session) pcep_log(LOG_WARNING, "%s: send_pce_report_message ERO object was NULL", __func__); - dll_destroy_with_data(report_list); + dll_destroy_with_data(report_list); return; } dll_append(report_list, obj); diff --git a/pceplib/pcep_session_logic.c b/pceplib/pcep_session_logic.c index ce898d1bf5..78d1072552 100644 --- a/pceplib/pcep_session_logic.c +++ b/pceplib/pcep_session_logic.c @@ -590,12 +590,14 @@ struct pcep_message *create_pcep_open(pcep_session *session) /* I flag */ session->pcc_config .support_pce_lsp_instantiation, - /* T flag */ - session->pcc_config.support_lsp_triggered_resync, - /* D flag */ - session->pcc_config.support_lsp_delta_sync, - /* F flag */ - session->pcc_config.support_pce_triggered_initial_sync)); + /* T flag */ + session->pcc_config + .support_lsp_triggered_resync, + /* D flag */ + session->pcc_config.support_lsp_delta_sync, + /* F flag */ + session->pcc_config + .support_pce_triggered_initial_sync)); } if (session->pcc_config.support_include_db_version) { diff --git a/pceplib/test/pcep_msg_messages_test.c b/pceplib/test/pcep_msg_messages_test.c index 6ae449acd1..3fec24a225 100644 --- a/pceplib/test/pcep_msg_messages_test.c +++ b/pceplib/test/pcep_msg_messages_test.c @@ -119,7 +119,7 @@ void test_pcep_msg_create_request() /* Test IPv4 */ struct pcep_object_rp *rp_obj = pcep_obj_create_rp(0, false, false, false, false, 10, NULL); - struct in_addr src_addr={}, dst_addr={}; + struct in_addr src_addr = {}, dst_addr = {}; struct pcep_object_endpoints_ipv4 *ipv4_obj = pcep_obj_create_endpoint_ipv4(&src_addr, &dst_addr); message = pcep_msg_create_request(rp_obj, ipv4_obj, NULL); diff --git a/pceplib/test/pcep_msg_tools_test.c b/pceplib/test/pcep_msg_tools_test.c index e25ddb2179..ffbe802d34 100644 --- a/pceplib/test/pcep_msg_tools_test.c +++ b/pceplib/test/pcep_msg_tools_test.c @@ -35,6 +35,8 @@ #include <CUnit/CUnit.h> +#include <zebra.h> + #include "pcep_msg_encoding.h" #include "pcep_msg_messages.h" #include "pcep_msg_tools.h" @@ -143,7 +145,7 @@ const char *pcep_initiate_cisco_pcc_hexbyte_strs[] = { struct pcep_message *create_message(uint8_t msg_type, uint8_t obj1_class, uint8_t obj2_class, uint8_t obj3_class, uint8_t obj4_class); -int convert_hexstrs_to_binary(const char *hexbyte_strs[], +int convert_hexstrs_to_binary(char *filename, const char *hexbyte_strs[], uint16_t hexbyte_strs_length); int pcep_tools_test_suite_setup(void) @@ -167,18 +169,23 @@ void pcep_tools_test_teardown(void) { } +static const char BASE_TMPFILE[] = "/tmp/pceplib_XXXXXX"; +static int BASE_TMPFILE_SIZE = sizeof(BASE_TMPFILE); + /* Reads an array of hexbyte strs, and writes them to a temporary file. * The caller should close the returned file. */ -int convert_hexstrs_to_binary(const char *hexbyte_strs[], +int convert_hexstrs_to_binary(char *filename, const char *hexbyte_strs[], uint16_t hexbyte_strs_length) { mode_t oldumask; - oldumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); + oldumask = umask(S_IXUSR | S_IXGRP | S_IWOTH | S_IROTH | S_IXOTH); /* Set umask before anything for security */ umask(0027); - char tmpfile[] = "/tmp/pceplib_XXXXXX"; - int fd = mkstemp(tmpfile); + + strlcpy(filename, BASE_TMPFILE, BASE_TMPFILE_SIZE); + int fd = mkstemp(filename); umask(oldumask); + if (fd == -1) return -1; @@ -206,10 +213,12 @@ static bool pcep_obj_has_tlv(struct pcep_object_header *obj_hdr) void test_pcep_msg_read_pcep_initiate() { - int fd = convert_hexstrs_to_binary(pcep_initiate_hexbyte_strs, + char filename[BASE_TMPFILE_SIZE]; + + int fd = convert_hexstrs_to_binary(filename, pcep_initiate_hexbyte_strs, pcep_initiate_hexbyte_strs_length); - if(fd == -1){ - CU_ASSERT_TRUE(fd>=0); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } double_linked_list *msg_list = pcep_msg_read(fd); @@ -302,15 +311,19 @@ void test_pcep_msg_read_pcep_initiate() pcep_msg_free_message_list(msg_list); close(fd); + unlink(filename); } void test_pcep_msg_read_pcep_initiate2() { - int fd = convert_hexstrs_to_binary(pcep_initiate2_hexbyte_strs, - pcep_initiate2_hexbyte_strs_length); - if(fd == -1){ - CU_ASSERT_TRUE(fd>=0); + char filename[BASE_TMPFILE_SIZE]; + + int fd = + convert_hexstrs_to_binary(filename, pcep_initiate2_hexbyte_strs, + pcep_initiate2_hexbyte_strs_length); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } double_linked_list *msg_list = pcep_msg_read(fd); @@ -392,14 +405,17 @@ void test_pcep_msg_read_pcep_initiate2() pcep_msg_free_message_list(msg_list); close(fd); + unlink(filename); } void test_pcep_msg_read_pcep_open() { - int fd = convert_hexstrs_to_binary(pcep_open_odl_hexbyte_strs, + char filename[BASE_TMPFILE_SIZE]; + + int fd = convert_hexstrs_to_binary(filename, pcep_open_odl_hexbyte_strs, pcep_open_hexbyte_strs_length); - if(fd == -1){ - CU_ASSERT_TRUE(fd>=0); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } double_linked_list *msg_list = pcep_msg_read(fd); @@ -437,14 +453,17 @@ void test_pcep_msg_read_pcep_open() pcep_msg_free_message_list(msg_list); close(fd); + unlink(filename); } void test_pcep_msg_read_pcep_update() { - int fd = convert_hexstrs_to_binary(pcep_update_hexbyte_strs, + char filename[BASE_TMPFILE_SIZE]; + + int fd = convert_hexstrs_to_binary(filename, pcep_update_hexbyte_strs, pcep_update_hexbyte_strs_length); - if(fd == -1){ - CU_ASSERT_TRUE(fd>=0); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } double_linked_list *msg_list = pcep_msg_read(fd); @@ -520,15 +539,18 @@ void test_pcep_msg_read_pcep_update() pcep_msg_free_message_list(msg_list); close(fd); + unlink(filename); } void test_pcep_msg_read_pcep_open_initiate() { + char filename[BASE_TMPFILE_SIZE]; + int fd = convert_hexstrs_to_binary( - pcep_open_initiate_odl_hexbyte_strs, + filename, pcep_open_initiate_odl_hexbyte_strs, pcep_open_initiate_hexbyte_strs_length); - if(fd == -1){ - CU_ASSERT_TRUE(fd>=0); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } double_linked_list *msg_list = pcep_msg_read(fd); @@ -550,15 +572,18 @@ void test_pcep_msg_read_pcep_open_initiate() pcep_msg_free_message_list(msg_list); close(fd); + unlink(filename); } void test_pcep_msg_read_pcep_open_cisco_pce() { + char filename[BASE_TMPFILE_SIZE]; + int fd = convert_hexstrs_to_binary( - pcep_open_cisco_pce_hexbyte_strs, + filename, pcep_open_cisco_pce_hexbyte_strs, pcep_open_cisco_pce_hexbyte_strs_length); - if(fd == -1){ - CU_ASSERT_TRUE(fd>=0); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } double_linked_list *msg_list = pcep_msg_read(fd); @@ -614,15 +639,18 @@ void test_pcep_msg_read_pcep_open_cisco_pce() pcep_msg_free_message_list(msg_list); close(fd); + unlink(filename); } void test_pcep_msg_read_pcep_update_cisco_pce() { + char filename[BASE_TMPFILE_SIZE]; + int fd = convert_hexstrs_to_binary( - pcep_update_cisco_pce_hexbyte_strs, + filename, pcep_update_cisco_pce_hexbyte_strs, pcep_update_cisco_pce_hexbyte_strs_length); - if(fd == -1){ - CU_ASSERT_TRUE(fd>=0); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } double_linked_list *msg_list = pcep_msg_read(fd); @@ -759,15 +787,18 @@ void test_pcep_msg_read_pcep_update_cisco_pce() pcep_msg_free_message_list(msg_list); close(fd); + unlink(filename); } void test_pcep_msg_read_pcep_report_cisco_pcc() { + char filename[BASE_TMPFILE_SIZE]; + int fd = convert_hexstrs_to_binary( - pcep_report_cisco_pcc_hexbyte_strs, + filename, pcep_report_cisco_pcc_hexbyte_strs, pcep_report_cisco_pcc_hexbyte_strs_length); - if(fd == -1){ - CU_ASSERT_TRUE(fd>=0); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } double_linked_list *msg_list = pcep_msg_read(fd); @@ -921,15 +952,18 @@ void test_pcep_msg_read_pcep_report_cisco_pcc() pcep_msg_free_message_list(msg_list); close(fd); + unlink(filename); } void test_pcep_msg_read_pcep_initiate_cisco_pcc() { + char filename[BASE_TMPFILE_SIZE]; + int fd = convert_hexstrs_to_binary( - pcep_initiate_cisco_pcc_hexbyte_strs, + filename, pcep_initiate_cisco_pcc_hexbyte_strs, pcep_initiate_cisco_pcc_hexbyte_strs_length); - if(fd == -1){ - CU_ASSERT_TRUE(fd>=0); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } double_linked_list *msg_list = pcep_msg_read(fd); @@ -1030,6 +1064,7 @@ void test_pcep_msg_read_pcep_initiate_cisco_pcc() pcep_msg_free_message_list(msg_list); close(fd); + unlink(filename); } void test_validate_message_header() diff --git a/pceplib/test/pcep_session_logic_loop_test.c b/pceplib/test/pcep_session_logic_loop_test.c index 4dfed7321f..7a42715283 100644 --- a/pceplib/test/pcep_session_logic_loop_test.c +++ b/pceplib/test/pcep_session_logic_loop_test.c @@ -140,14 +140,14 @@ void test_session_logic_msg_ready_handler() /* Read from an empty file should return 0, thus * session_logic_msg_ready_handler returns -1 */ mode_t oldumask; - oldumask = umask(S_IXUSR|S_IXGRP|S_IWOTH|S_IROTH|S_IXOTH); + oldumask = umask(S_IXUSR | S_IXGRP | S_IWOTH | S_IROTH | S_IXOTH); /* Set umask before anything for security */ umask(0027); char tmpfile[] = "/tmp/pceplib_XXXXXX"; int fd = mkstemp(tmpfile); umask(oldumask); - if (fd == -1){ - CU_ASSERT_TRUE(fd>=0); + if (fd == -1) { + CU_ASSERT_TRUE(fd >= 0); return; } pcep_session session; @@ -191,6 +191,7 @@ void test_session_logic_msg_ready_handler() destroy_pcep_versioning(versioning); pceplib_free(PCEPLIB_INFRA, socket_event); close(fd); + unlink(tmpfile); } diff --git a/pimd/pim_bfd.c b/pimd/pim_bfd.c index c7fcbba71e..696544c8d6 100644 --- a/pimd/pim_bfd.c +++ b/pimd/pim_bfd.c @@ -97,7 +97,7 @@ void pim_bfd_info_nbr_create(struct pim_interface *pim_ifp, pim_ifp->bfd_config.min_rx, pim_ifp->bfd_config.min_tx); bfd_sess_set_ipv4_addrs(neigh->bfd_session, NULL, &neigh->source_addr); bfd_sess_set_interface(neigh->bfd_session, neigh->interface->name); - bfd_sess_set_vrf(neigh->bfd_session, neigh->interface->vrf_id); + bfd_sess_set_vrf(neigh->bfd_session, neigh->interface->vrf->vrf_id); bfd_sess_set_profile(neigh->bfd_session, pim_ifp->bfd_config.profile); bfd_sess_install(neigh->bfd_session); } diff --git a/pimd/pim_bsm.c b/pimd/pim_bsm.c index a3a3426f39..238c19d2cc 100644 --- a/pimd/pim_bsm.c +++ b/pimd/pim_bsm.c @@ -35,6 +35,7 @@ #include "pim_nht.h" #include "pim_bsm.h" #include "pim_time.h" +#include "pim_zebra.h" /* Functions forward declaration */ static void pim_bs_timer_start(struct bsm_scope *scope, int bs_timeout); @@ -70,7 +71,7 @@ static void pim_bsm_rpinfo_free(struct bsm_rpinfo *bsrp_info) XFREE(MTYPE_PIM_BSRP_INFO, bsrp_info); } -void pim_bsm_rpinfos_free(struct bsm_rpinfos_head *head) +static void pim_bsm_rpinfos_free(struct bsm_rpinfos_head *head) { struct bsm_rpinfo *bsrp_info; @@ -78,14 +79,14 @@ void pim_bsm_rpinfos_free(struct bsm_rpinfos_head *head) pim_bsm_rpinfo_free(bsrp_info); } -void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node) +static void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node) { pim_bsm_rpinfos_free(bsgrp_node->bsrp_list); pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list); XFREE(MTYPE_PIM_BSGRP_NODE, bsgrp_node); } -void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp) +static void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp) { struct route_node *rn; @@ -102,7 +103,7 @@ static void pim_bsm_frag_free(struct bsm_frag *bsfrag) XFREE(MTYPE_PIM_BSM_FRAG, bsfrag); } -void pim_bsm_frags_free(struct bsm_scope *scope) +static void pim_bsm_frags_free(struct bsm_scope *scope) { struct bsm_frag *bsfrag; @@ -162,8 +163,6 @@ static int pim_on_bs_timer(struct thread *t) struct bsm_scope *scope; struct bsgrp_node *bsgrp_node; struct bsm_rpinfo *bsrp; - struct prefix nht_p; - bool is_bsr_tracking = true; scope = THREAD_ARG(t); THREAD_OFF(scope->bs_timer); @@ -172,15 +171,7 @@ static int pim_on_bs_timer(struct thread *t) zlog_debug("%s: Bootstrap Timer expired for scope: %d", __func__, scope->sz_id); - /* Remove next hop tracking for the bsr */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = scope->current_bsr; - if (PIM_DEBUG_BSM) - zlog_debug("%s: Deregister BSR addr %pFX with Zebra NHT", - __func__, &nht_p); - pim_delete_tracked_nexthop(scope->pim, &nht_p, NULL, NULL, - is_bsr_tracking); + pim_nht_bsr_del(scope->pim, scope->current_bsr); /* Reset scope zone data */ scope->accept_nofwd_bsm = false; @@ -212,7 +203,7 @@ static int pim_on_bs_timer(struct thread *t) return 0; } -void pim_bs_timer_stop(struct bsm_scope *scope) +static void pim_bs_timer_stop(struct bsm_scope *scope) { if (PIM_DEBUG_BSM) zlog_debug("%s : BS timer being stopped of sz: %d", __func__, @@ -543,35 +534,6 @@ static void pim_instate_pend_list(struct bsgrp_node *bsgrp_node) pim_bsm_rpinfos_free(bsgrp_node->partial_bsrp_list); } -static bool pim_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr, - struct in_addr ip_src_addr) -{ - struct pim_nexthop nexthop; - int result; - - memset(&nexthop, 0, sizeof(nexthop)); - - /* New BSR recived */ - if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) { - result = pim_nexthop_match(pim, bsr, ip_src_addr); - - /* Nexthop lookup pass for the new BSR address */ - if (result) - return true; - - if (PIM_DEBUG_BSM) { - char bsr_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("<bsr?>", bsr, bsr_str, sizeof(bsr_str)); - zlog_debug("%s : No route to BSR address %s", __func__, - bsr_str); - } - return false; - } - - return pim_nexthop_match_nht_cache(pim, bsr, ip_src_addr); -} - static bool is_preferred_bsr(struct pim_instance *pim, struct in_addr bsr, uint32_t bsr_prio) { @@ -594,35 +556,11 @@ static bool is_preferred_bsr(struct pim_instance *pim, struct in_addr bsr, static void pim_bsm_update(struct pim_instance *pim, struct in_addr bsr, uint32_t bsr_prio) { - struct pim_nexthop_cache pnc; - if (bsr.s_addr != pim->global_scope.current_bsr.s_addr) { - struct prefix nht_p; - bool is_bsr_tracking = true; - - /* De-register old BSR and register new BSR with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; + if (pim->global_scope.current_bsr.s_addr) + pim_nht_bsr_del(pim, pim->global_scope.current_bsr); + pim_nht_bsr_add(pim, bsr); - if (pim->global_scope.current_bsr.s_addr != INADDR_ANY) { - nht_p.u.prefix4 = pim->global_scope.current_bsr; - if (PIM_DEBUG_BSM) - zlog_debug( - "%s: Deregister BSR addr %pFX with Zebra NHT", - __func__, &nht_p); - pim_delete_tracked_nexthop(pim, &nht_p, NULL, NULL, - is_bsr_tracking); - } - - nht_p.u.prefix4 = bsr; - if (PIM_DEBUG_BSM) - zlog_debug( - "%s: NHT Register BSR addr %pFX with Zebra NHT", - __func__, &nht_p); - - memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); - pim_find_or_track_nexthop(pim, &nht_p, NULL, NULL, - is_bsr_tracking, &pnc); pim->global_scope.current_bsr = bsr; pim->global_scope.current_bsr_first_ts = pim_time_monotonic_sec(); @@ -632,6 +570,127 @@ static void pim_bsm_update(struct pim_instance *pim, struct in_addr bsr, pim->global_scope.current_bsr_last_ts = pim_time_monotonic_sec(); } +void pim_bsm_clear(struct pim_instance *pim) +{ + struct route_node *rn; + struct route_node *rpnode; + struct bsgrp_node *bsgrp; + struct prefix nht_p; + struct prefix g_all; + struct rp_info *rp_all; + struct pim_upstream *up; + struct rp_info *rp_info; + bool upstream_updated = false; + + if (pim->global_scope.current_bsr.s_addr) + pim_nht_bsr_del(pim, pim->global_scope.current_bsr); + + /* Reset scope zone data */ + pim->global_scope.accept_nofwd_bsm = false; + pim->global_scope.state = ACCEPT_ANY; + pim->global_scope.current_bsr.s_addr = INADDR_ANY; + pim->global_scope.current_bsr_prio = 0; + pim->global_scope.current_bsr_first_ts = 0; + pim->global_scope.current_bsr_last_ts = 0; + pim->global_scope.bsm_frag_tag = 0; + pim_bsm_frags_free(&pim->global_scope); + + pim_bs_timer_stop(&pim->global_scope); + + for (rn = route_top(pim->global_scope.bsrp_table); rn; + rn = route_next(rn)) { + bsgrp = rn->info; + if (!bsgrp) + continue; + + rpnode = route_node_lookup(pim->rp_table, &bsgrp->group); + + if (!rpnode) { + pim_free_bsgrp_node(bsgrp->scope->bsrp_table, + &bsgrp->group); + pim_free_bsgrp_data(bsgrp); + continue; + } + + rp_info = (struct rp_info *)rpnode->info; + + if ((!rp_info) || (rp_info->rp_src != RP_SRC_BSR)) { + pim_free_bsgrp_node(bsgrp->scope->bsrp_table, + &bsgrp->group); + pim_free_bsgrp_data(bsgrp); + continue; + } + + /* Deregister addr with Zebra NHT */ + nht_p.family = AF_INET; + nht_p.prefixlen = IPV4_MAX_BITLEN; + nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; + + if (PIM_DEBUG_PIM_NHT_RP) { + zlog_debug("%s: Deregister RP addr %pFX with Zebra ", + __func__, &nht_p); + } + + pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info); + + if (!str2prefix("224.0.0.0/4", &g_all)) + return; + + rp_all = pim_rp_find_match_group(pim, &g_all); + + if (rp_all == rp_info) { + rp_all->rp.rpf_addr.family = AF_INET; + rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; + rp_all->i_am_rp = 0; + } else { + /* Delete the rp_info from rp-list */ + listnode_delete(pim->rp_list, rp_info); + + /* Delete the rp node from rp_table */ + rpnode->info = NULL; + route_unlock_node(rpnode); + route_unlock_node(rpnode); + XFREE(MTYPE_PIM_RP, rp_info); + } + + pim_free_bsgrp_node(bsgrp->scope->bsrp_table, &bsgrp->group); + pim_free_bsgrp_data(bsgrp); + } + pim_rp_refresh_group_to_rp_mapping(pim); + + + frr_each (rb_pim_upstream, &pim->upstream_head, up) { + /* Find the upstream (*, G) whose upstream address is same as + * the RP + */ + if (up->sg.src.s_addr != INADDR_ANY) + continue; + + struct prefix grp; + struct rp_info *trp_info; + + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = up->sg.grp; + + trp_info = pim_rp_find_match_group(pim, &grp); + + /* RP not found for the group grp */ + if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) { + pim_upstream_rpf_clear(pim, up); + pim_rp_set_upstream_addr(pim, &up->upstream_addr, + up->sg.src, up->sg.grp); + } else { + /* RP found for the group grp */ + pim_upstream_update(pim, up); + upstream_updated = true; + } + } + + if (upstream_updated) + pim_zebra_update_all_interfaces(pim); +} + static bool pim_bsm_send_intf(uint8_t *buf, int len, struct interface *ifp, struct in_addr dst_addr) { @@ -1115,18 +1174,6 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, buf += sizeof(struct bsmmsg_grpinfo); offset += sizeof(struct bsmmsg_grpinfo); - if (grpinfo.rp_count == 0) { - if (PIM_DEBUG_BSM) { - char grp_str[INET_ADDRSTRLEN]; - - pim_inet4_dump("<Group?>", grpinfo.group.addr, - grp_str, sizeof(grp_str)); - zlog_debug("%s, Rp count is zero for group: %s", - __func__, grp_str); - } - return false; - } - group.family = AF_INET; if (grpinfo.group.mask > IPV4_MAX_BITLEN) { if (PIM_DEBUG_BSM) @@ -1141,6 +1188,32 @@ static bool pim_bsm_parse_install_g2rp(struct bsm_scope *scope, uint8_t *buf, /* Get the Group node for the BSM rp table */ bsgrp = pim_bsm_get_bsgrp_node(scope, &group); + if (grpinfo.rp_count == 0) { + struct bsm_rpinfo *old_rpinfo; + + /* BSR explicitly no longer has RPs for this group */ + if (!bsgrp) + continue; + + if (PIM_DEBUG_BSM) { + char grp_str[INET_ADDRSTRLEN]; + + pim_inet4_dump("<Group?>", grpinfo.group.addr, + grp_str, sizeof(grp_str)); + zlog_debug("%s, Rp count is zero for group: %s", + __func__, grp_str); + } + + old_rpinfo = bsm_rpinfos_first(bsgrp->bsrp_list); + if (old_rpinfo) + pim_rp_del(scope->pim, old_rpinfo->rp_address, + group, NULL, RP_SRC_BSR); + + pim_free_bsgrp_node(scope->bsrp_table, &bsgrp->group); + pim_free_bsgrp_data(bsgrp); + continue; + } + if (!bsgrp) { if (PIM_DEBUG_BSM) zlog_debug("%s, Create new BSM Group node.", @@ -1310,21 +1383,23 @@ int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, uint8_t *buf, } } - /* Mulicast BSM received */ if (ip_hdr->ip_dst.s_addr == qpim_all_pim_routers_addr.s_addr) { - if (!no_fwd) { - if (!pim_bsr_rpf_check(pim, bshdr->bsr_addr.addr, - ip_hdr->ip_src)) { - if (PIM_DEBUG_BSM) - zlog_debug( - "%s : RPF check fail for BSR address %s", - __func__, bsr_str); - pim->bsm_dropped++; - return -1; - } + /* Multicast BSMs are only accepted if source interface & IP + * match RPF towards the BSR's IP address, or they have + * no-forward set + */ + if (!no_fwd + && !pim_nht_bsr_rpf_check(pim, bshdr->bsr_addr.addr, ifp, + ip_hdr->ip_src)) { + if (PIM_DEBUG_BSM) + zlog_debug( + "BSM check: RPF to BSR %s is not %pI4%%%s", + bsr_str, &ip_hdr->ip_src, ifp->name); + pim->bsm_dropped++; + return -1; } - } else if (if_lookup_exact_address(&ip_hdr->ip_dst, AF_INET, - pim->vrf->vrf_id)) { + } else if (if_address_is_local(&ip_hdr->ip_dst, AF_INET, + pim->vrf->vrf_id)) { /* Unicast BSM received - if ucast bsm not enabled on * the interface, drop it */ diff --git a/pimd/pim_bsm.h b/pimd/pim_bsm.h index dbfeeceec8..a536b50688 100644 --- a/pimd/pim_bsm.h +++ b/pimd/pim_bsm.h @@ -205,6 +205,7 @@ struct bsmmsg_rpinfo { /* API */ void pim_bsm_proc_init(struct pim_instance *pim); void pim_bsm_proc_free(struct pim_instance *pim); +void pim_bsm_clear(struct pim_instance *pim); void pim_bsm_write_config(struct vty *vty, struct interface *ifp); int pim_bsm_process(struct interface *ifp, struct ip *ip_hdr, @@ -214,9 +215,4 @@ int pim_bsm_process(struct interface *ifp, bool pim_bsm_new_nbr_fwd(struct pim_neighbor *neigh, struct interface *ifp); struct bsgrp_node *pim_bsm_get_bsgrp_node(struct bsm_scope *scope, struct prefix *grp); -void pim_bs_timer_stop(struct bsm_scope *scope); -void pim_bsm_frags_free(struct bsm_scope *scope); -void pim_bsm_rpinfos_free(struct bsm_rpinfos_head *head); -void pim_free_bsgrp_data(struct bsgrp_node *bsgrp_node); -void pim_free_bsgrp_node(struct route_table *rt, struct prefix *grp); #endif diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 4cd94e0df9..86a09f72f9 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -308,14 +308,12 @@ static void json_object_pim_ifp_add(struct json_object *json, struct interface *ifp) { struct pim_interface *pim_ifp; - char buf[PREFIX_STRLEN]; pim_ifp = ifp->info; json_object_string_add(json, "name", ifp->name); json_object_string_add(json, "state", if_is_up(ifp) ? "up" : "down"); - json_object_string_add(json, "address", - inet_ntop(AF_INET, &pim_ifp->primary_address, - buf, sizeof(buf))); + json_object_string_addf(json, "address", "%pI4", + &pim_ifp->primary_address); json_object_int_add(json, "index", ifp->ifindex); if (if_is_multicast(ifp)) @@ -489,7 +487,6 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, struct interface *ifp; time_t now; char buf[PREFIX_STRLEN]; - char quer_buf[PREFIX_STRLEN]; json_object *json = NULL; json_object *json_row = NULL; @@ -504,7 +501,7 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; struct listnode *sock_node; - struct igmp_sock *igmp; + struct gm_sock *igmp; pim_ifp = ifp->info; @@ -537,10 +534,9 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, "queryTimer", query_hhmmss); } - json_object_string_add( - json_row, "querierIp", - inet_ntop(AF_INET, &igmp->querier_addr, - quer_buf, sizeof(quer_buf))); + json_object_string_addf(json_row, "querierIp", + "%pI4", + &igmp->querier_addr); json_object_object_add(json, ifp->name, json_row); @@ -579,12 +575,11 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, struct vty *vty, const char *ifname, bool uj) { - struct igmp_sock *igmp; + struct gm_sock *igmp; struct interface *ifp; struct listnode *sock_node; struct pim_interface *pim_ifp; char uptime[10]; - char quer_buf[PREFIX_STRLEN]; char query_hhmmss[10]; char other_hhmmss[10]; int found_ifname = 0; @@ -669,10 +664,9 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, igmp->t_igmp_query_timer ? "local" : "other"); - json_object_string_add( - json_row, "querierIp", - inet_ntop(AF_INET, &igmp->querier_addr, - quer_buf, sizeof(quer_buf))); + json_object_string_addf(json_row, "querierIp", + "%pI4", + &igmp->querier_addr); json_object_int_add(json_row, "queryStartCount", igmp->startup_query_count); json_object_string_add(json_row, @@ -830,7 +824,7 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty, FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; struct listnode *join_node; - struct igmp_join *ij; + struct gm_join *ij; struct in_addr pri_addr; char pri_addr_str[INET_ADDRSTRLEN]; @@ -928,7 +922,6 @@ static void pim_show_interfaces_single(struct pim_instance *pim, int mloop = 0; int found_ifname = 0; int print_header; - char buf[PREFIX_STRLEN]; json_object *json = NULL; json_object *json_row = NULL; json_object *json_pim_neighbor = NULL; @@ -979,11 +972,9 @@ static void pim_show_interfaces_single(struct pim_instance *pim, json_object_pim_ifp_add(json_row, ifp); if (pim_ifp->update_source.s_addr != INADDR_ANY) { - json_object_string_add( - json_row, "useSource", - inet_ntop(AF_INET, - &pim_ifp->update_source, - buf, sizeof(buf))); + json_object_string_addf( + json_row, "useSource", "%pI4", + &pim_ifp->update_source); } if (pim_ifp->sec_addr_list) { json_object *sec_list = NULL; @@ -1339,7 +1330,7 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty, FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp; struct listnode *sock_node; - struct igmp_sock *igmp; + struct gm_sock *igmp; pim_ifp = ifp->info; @@ -1407,7 +1398,6 @@ static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, int fhr = 0; int pim_nbrs = 0; int pim_ifchannels = 0; - char buf[PREFIX_STRLEN]; json_object *json = NULL; json_object *json_row = NULL; json_object *json_tmp; @@ -1437,10 +1427,8 @@ static void pim_show_interfaces(struct pim_instance *pim, struct vty *vty, json_object_int_add(json_row, "pimNeighbors", pim_nbrs); json_object_int_add(json_row, "pimIfChannels", pim_ifchannels); json_object_int_add(json_row, "firstHopRouterCount", fhr); - json_object_string_add(json_row, "pimDesignatedRouter", - inet_ntop(AF_INET, - &pim_ifp->pim_dr_addr, buf, - sizeof(buf))); + json_object_string_addf(json_row, "pimDesignatedRouter", "%pI4", + &pim_ifp->pim_dr_addr); if (pim_ifp->pim_dr_addr.s_addr == pim_ifp->primary_address.s_addr) @@ -2446,8 +2434,6 @@ static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state, case PIM_REG_PRUNE: strlcpy(state_str, "RegP", state_str_len); break; - default: - strlcpy(state_str, "Unk", state_str_len); } return state_str; } @@ -3437,7 +3423,7 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj) FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp = ifp->info; struct listnode *grpnode; - struct igmp_group *grp; + struct gm_group *grp; if (!pim_ifp) continue; @@ -3531,7 +3517,7 @@ static void igmp_show_group_retransmission(struct pim_instance *pim, FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp = ifp->info; struct listnode *grpnode; - struct igmp_group *grp; + struct gm_group *grp; if (!pim_ifp) continue; @@ -3542,7 +3528,7 @@ static void igmp_show_group_retransmission(struct pim_instance *pim, char group_str[INET_ADDRSTRLEN]; char grp_retr_mmss[10]; struct listnode *src_node; - struct igmp_source *src; + struct gm_source *src; int grp_retr_sources = 0; pim_inet4_dump("<group?>", grp->group_addr, group_str, @@ -3584,7 +3570,7 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp = ifp->info; struct listnode *grpnode; - struct igmp_group *grp; + struct gm_group *grp; if (!pim_ifp) continue; @@ -3594,7 +3580,7 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) grp)) { char group_str[INET_ADDRSTRLEN]; struct listnode *srcnode; - struct igmp_source *src; + struct gm_source *src; pim_inet4_dump("<group?>", grp->group_addr, group_str, sizeof(group_str)); @@ -3640,7 +3626,7 @@ static void igmp_show_source_retransmission(struct pim_instance *pim, FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp = ifp->info; struct listnode *grpnode; - struct igmp_group *grp; + struct gm_group *grp; if (!pim_ifp) continue; @@ -3650,7 +3636,7 @@ static void igmp_show_source_retransmission(struct pim_instance *pim, grp)) { char group_str[INET_ADDRSTRLEN]; struct listnode *srcnode; - struct igmp_source *src; + struct gm_source *src; pim_inet4_dump("<group?>", grp->group_addr, group_str, sizeof(group_str)); @@ -3922,7 +3908,7 @@ static void clear_mroute(struct pim_instance *pim) /* scan interfaces */ FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp = ifp->info; - struct igmp_group *grp; + struct gm_group *grp; struct pim_ifchannel *ch; if (!pim_ifp) @@ -4053,131 +4039,6 @@ DEFUN (clear_ip_pim_oil, return CMD_SUCCESS; } -static void clear_pim_bsr_db(struct pim_instance *pim) -{ - struct route_node *rn; - struct route_node *rpnode; - struct bsgrp_node *bsgrp; - struct prefix nht_p; - struct prefix g_all; - struct rp_info *rp_all; - struct pim_upstream *up; - struct rp_info *rp_info; - bool is_bsr_tracking = true; - - /* Remove next hop tracking for the bsr */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = pim->global_scope.current_bsr; - if (PIM_DEBUG_BSM) { - zlog_debug("%s: Deregister BSR addr %pFX with Zebra NHT", - __func__, &nht_p); - } - pim_delete_tracked_nexthop(pim, &nht_p, NULL, NULL, is_bsr_tracking); - - /* Reset scope zone data */ - pim->global_scope.accept_nofwd_bsm = false; - pim->global_scope.state = ACCEPT_ANY; - pim->global_scope.current_bsr.s_addr = INADDR_ANY; - pim->global_scope.current_bsr_prio = 0; - pim->global_scope.current_bsr_first_ts = 0; - pim->global_scope.current_bsr_last_ts = 0; - pim->global_scope.bsm_frag_tag = 0; - pim_bsm_frags_free(&pim->global_scope); - - pim_bs_timer_stop(&pim->global_scope); - - for (rn = route_top(pim->global_scope.bsrp_table); rn; - rn = route_next(rn)) { - bsgrp = rn->info; - if (!bsgrp) - continue; - - rpnode = route_node_lookup(pim->rp_table, &bsgrp->group); - - if (!rpnode) { - pim_free_bsgrp_node(bsgrp->scope->bsrp_table, - &bsgrp->group); - pim_free_bsgrp_data(bsgrp); - continue; - } - - rp_info = (struct rp_info *)rpnode->info; - - if ((!rp_info) || (rp_info->rp_src != RP_SRC_BSR)) { - pim_free_bsgrp_node(bsgrp->scope->bsrp_table, - &bsgrp->group); - pim_free_bsgrp_data(bsgrp); - continue; - } - - /* Deregister addr with Zebra NHT */ - nht_p.family = AF_INET; - nht_p.prefixlen = IPV4_MAX_BITLEN; - nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; - - if (PIM_DEBUG_PIM_NHT_RP) { - zlog_debug("%s: Deregister RP addr %pFX with Zebra ", - __func__, &nht_p); - } - - pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info, false); - - if (!str2prefix("224.0.0.0/4", &g_all)) - return; - - rp_all = pim_rp_find_match_group(pim, &g_all); - - if (rp_all == rp_info) { - rp_all->rp.rpf_addr.family = AF_INET; - rp_all->rp.rpf_addr.u.prefix4.s_addr = INADDR_NONE; - rp_all->i_am_rp = 0; - } else { - /* Delete the rp_info from rp-list */ - listnode_delete(pim->rp_list, rp_info); - - /* Delete the rp node from rp_table */ - rpnode->info = NULL; - route_unlock_node(rpnode); - route_unlock_node(rpnode); - XFREE(MTYPE_PIM_RP, rp_info); - } - - pim_free_bsgrp_node(bsgrp->scope->bsrp_table, &bsgrp->group); - pim_free_bsgrp_data(bsgrp); - } - pim_rp_refresh_group_to_rp_mapping(pim); - - - frr_each (rb_pim_upstream, &pim->upstream_head, up) { - /* Find the upstream (*, G) whose upstream address is same as - * the RP - */ - if (up->sg.src.s_addr != INADDR_ANY) - continue; - - struct prefix grp; - struct rp_info *trp_info; - - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = up->sg.grp; - - trp_info = pim_rp_find_match_group(pim, &grp); - - /* RP not found for the group grp */ - if (pim_rpf_addr_is_inaddr_none(&trp_info->rp)) { - pim_upstream_rpf_clear(pim, up); - pim_rp_set_upstream_addr(pim, &up->upstream_addr, - up->sg.src, up->sg.grp); - } else { - /* RP found for the group grp */ - pim_upstream_update(pim, up); - } - } -} - - DEFUN (clear_ip_pim_bsr_db, clear_ip_pim_bsr_db_cmd, "clear ip pim [vrf NAME] bsr-data", @@ -4193,7 +4054,7 @@ DEFUN (clear_ip_pim_bsr_db, if (!vrf) return CMD_WARNING; - clear_pim_bsr_db(vrf->info); + pim_bsm_clear(vrf->info); return CMD_SUCCESS; } @@ -5842,10 +5703,8 @@ static void show_multicast_interfaces(struct pim_instance *pim, struct vty *vty, json_object_string_add(json_row, "name", ifp->name); json_object_string_add(json_row, "state", if_is_up(ifp) ? "up" : "down"); - json_object_string_add( - json_row, "address", - inet_ntop(AF_INET, &pim_ifp->primary_address, - buf, sizeof(buf))); + json_object_string_addf(json_row, "address", "%pI4", + &pim_ifp->primary_address); json_object_int_add(json_row, "ifIndex", ifp->ifindex); json_object_int_add(json_row, "vif", pim_ifp->mroute_vif_index); diff --git a/pimd/pim_hello.c b/pimd/pim_hello.c index e48a4bdd4d..45ea6a9562 100644 --- a/pimd/pim_hello.c +++ b/pimd/pim_hello.c @@ -545,7 +545,7 @@ void pim_hello_require(struct interface *ifp) assert(pim_ifp); - if (pim_ifp->pim_ifstat_hello_sent) + if (PIM_IF_FLAG_TEST_HELLO_SENT(pim_ifp->flags)) return; pim_hello_restart_now(ifp); /* Send hello and restart timer */ diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index eb19cf4ddf..5afd5cd2fe 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -121,7 +121,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, pim_ifp = XCALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp)); pim_ifp->options = 0; - pim_ifp->pim = pim_get_pim_instance(ifp->vrf_id); + pim_ifp->pim = ifp->vrf->info; pim_ifp->mroute_vif_index = -1; pim_ifp->igmp_version = IGMP_DEFAULT_VERSION; @@ -160,7 +160,7 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, pim_ifp->upstream_switch_list = NULL; pim_ifp->pim_generation_id = 0; - /* list of struct igmp_sock */ + /* list of struct gm_sock */ pim_igmp_if_init(pim_ifp, ifp); /* list of struct pim_neighbor */ @@ -289,7 +289,7 @@ static void pim_addr_change(struct interface *ifp) HoldTime should be sent immediately. -- FIXME See TODO T31 */ - pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */ + PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags); if (pim_ifp->pim_sock_fd < 0) return; pim_hello_restart_now(ifp); /* send hello and restart timer */ @@ -532,7 +532,7 @@ void pim_if_addr_add(struct connected *ifc) // return; if (PIM_IF_TEST_IGMP(pim_ifp->options)) { - struct igmp_sock *igmp; + struct gm_sock *igmp; /* lookup IGMP socket */ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, @@ -552,7 +552,7 @@ void pim_if_addr_add(struct connected *ifc) if (pim_ifp->igmp_join_list) { struct listnode *node; struct listnode *nextnode; - struct igmp_join *ij; + struct gm_join *ij; int join_fd; for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, @@ -583,7 +583,7 @@ void pim_if_addr_add(struct connected *ifc) } } /* igmp */ else { - struct igmp_sock *igmp; + struct gm_sock *igmp; /* lookup IGMP socket */ igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, @@ -648,7 +648,7 @@ void pim_if_addr_add(struct connected *ifc) static void pim_if_addr_del_igmp(struct connected *ifc) { struct pim_interface *pim_ifp = ifc->ifp->info; - struct igmp_sock *igmp; + struct gm_sock *igmp; struct in_addr ifaddr; if (ifc->address->family != AF_INET) { @@ -785,12 +785,11 @@ void pim_if_addr_del_all(struct interface *ifp) struct connected *ifc; struct listnode *node; struct listnode *nextnode; - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); struct pim_instance *pim; - if (!vrf) + pim = ifp->vrf->info; + if (!pim) return; - pim = vrf->info; /* PIM/IGMP enabled ? */ if (!ifp->info) @@ -829,26 +828,6 @@ void pim_if_addr_del_all_igmp(struct interface *ifp) } } -void pim_if_addr_del_all_pim(struct interface *ifp) -{ - struct connected *ifc; - struct listnode *node; - struct listnode *nextnode; - - /* PIM/IGMP enabled ? */ - if (!ifp->info) - return; - - for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) { - struct prefix *p = ifc->address; - - if (p->family != AF_INET) - continue; - - pim_if_addr_del_pim(ifc); - } -} - struct in_addr pim_find_primary_addr(struct interface *ifp) { struct connected *ifc; @@ -857,10 +836,6 @@ struct in_addr pim_find_primary_addr(struct interface *ifp) int v4_addrs = 0; int v6_addrs = 0; struct pim_interface *pim_ifp = ifp->info; - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - - if (!vrf) - return addr; if (pim_ifp && PIM_INADDR_ISNOT_ANY(pim_ifp->update_source)) { return pim_ifp->update_source; @@ -899,10 +874,11 @@ struct in_addr pim_find_primary_addr(struct interface *ifp) struct interface *lo_ifp; // DBS - Come back and check here - if (ifp->vrf_id == VRF_DEFAULT) - lo_ifp = if_lookup_by_name("lo", vrf->vrf_id); + if (ifp->vrf->vrf_id == VRF_DEFAULT) + lo_ifp = if_lookup_by_name("lo", ifp->vrf->vrf_id); else - lo_ifp = if_lookup_by_name(vrf->name, vrf->vrf_id); + lo_ifp = if_lookup_by_name(ifp->vrf->name, + ifp->vrf->vrf_id); if (lo_ifp && (lo_ifp != ifp)) return pim_find_primary_addr(lo_ifp); @@ -1183,17 +1159,17 @@ long pim_if_t_suppressed_msec(struct interface *ifp) return t_suppressed_msec; } -static void igmp_join_free(struct igmp_join *ij) +static void igmp_join_free(struct gm_join *ij) { XFREE(MTYPE_PIM_IGMP_JOIN, ij); } -static struct igmp_join *igmp_join_find(struct list *join_list, - struct in_addr group_addr, - struct in_addr source_addr) +static struct gm_join *igmp_join_find(struct list *join_list, + struct in_addr group_addr, + struct in_addr source_addr) { struct listnode *node; - struct igmp_join *ij; + struct gm_join *ij; assert(join_list); @@ -1235,12 +1211,12 @@ static int igmp_join_sock(const char *ifname, ifindex_t ifindex, return join_fd; } -static struct igmp_join *igmp_join_new(struct interface *ifp, - struct in_addr group_addr, - struct in_addr source_addr) +static struct gm_join *igmp_join_new(struct interface *ifp, + struct in_addr group_addr, + struct in_addr source_addr) { struct pim_interface *pim_ifp; - struct igmp_join *ij; + struct gm_join *ij; int join_fd; pim_ifp = ifp->info; @@ -1278,7 +1254,7 @@ ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr) { struct pim_interface *pim_ifp; - struct igmp_join *ij; + struct gm_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { @@ -1321,7 +1297,7 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, struct in_addr source_addr) { struct pim_interface *pim_ifp; - struct igmp_join *ij; + struct gm_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { @@ -1378,7 +1354,7 @@ static void pim_if_igmp_join_del_all(struct interface *ifp) struct pim_interface *pim_ifp; struct listnode *node; struct listnode *nextnode; - struct igmp_join *ij; + struct gm_join *ij; pim_ifp = ifp->info; if (!pim_ifp) { @@ -1482,7 +1458,8 @@ void pim_if_create_pimreg(struct pim_instance *pim) snprintf(pimreg_name, sizeof(pimreg_name), "pimreg%u", pim->vrf->data.l.table_id); - pim->regiface = if_create_name(pimreg_name, pim->vrf->vrf_id); + pim->regiface = if_get_by_name(pimreg_name, pim->vrf->vrf_id, + pim->vrf->name); pim->regiface->ifindex = PIM_OIF_PIM_REGISTER_VIF; pim_if_new(pim->regiface, false, false, true, @@ -1549,13 +1526,13 @@ int pim_ifp_create(struct interface *ifp) { struct pim_instance *pim; - pim = pim_get_pim_instance(ifp->vrf_id); + pim = ifp->vrf->info; if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - __func__, ifp->name, ifp->ifindex, ifp->vrf_id, - (long)ifp->flags, ifp->metric, ifp->mtu, - if_is_operative(ifp)); + "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d", + __func__, ifp->name, ifp->ifindex, ifp->vrf->name, + ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric, + ifp->mtu, if_is_operative(ifp)); } if (if_is_operative(ifp)) { @@ -1621,13 +1598,13 @@ int pim_ifp_up(struct interface *ifp) if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - __func__, ifp->name, ifp->ifindex, ifp->vrf_id, - (long)ifp->flags, ifp->metric, ifp->mtu, - if_is_operative(ifp)); + "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d", + __func__, ifp->name, ifp->ifindex, ifp->vrf->name, + ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric, + ifp->mtu, if_is_operative(ifp)); } - pim = pim_get_pim_instance(ifp->vrf_id); + pim = ifp->vrf->info; pim_ifp = ifp->info; /* @@ -1652,7 +1629,7 @@ int pim_ifp_up(struct interface *ifp) struct vrf *vrf; RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { if ((table_id == vrf->data.l.table_id) - && (ifp->vrf_id != vrf->vrf_id)) { + && (ifp->vrf->vrf_id != vrf->vrf_id)) { struct interface *master = if_lookup_by_name( vrf->name, vrf->vrf_id); @@ -1673,10 +1650,10 @@ int pim_ifp_down(struct interface *ifp) { if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - __func__, ifp->name, ifp->ifindex, ifp->vrf_id, - (long)ifp->flags, ifp->metric, ifp->mtu, - if_is_operative(ifp)); + "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d", + __func__, ifp->name, ifp->ifindex, ifp->vrf->name, + ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric, + ifp->mtu, if_is_operative(ifp)); } if (!if_is_operative(ifp)) { @@ -1697,8 +1674,10 @@ int pim_ifp_down(struct interface *ifp) } } - if (ifp->info) + if (ifp->info) { pim_if_del_vif(ifp); + pim_ifstat_reset(ifp); + } return 0; } @@ -1709,16 +1688,16 @@ int pim_ifp_destroy(struct interface *ifp) if (PIM_DEBUG_ZEBRA) { zlog_debug( - "%s: %s index %d(%u) flags %ld metric %d mtu %d operative %d", - __func__, ifp->name, ifp->ifindex, ifp->vrf_id, - (long)ifp->flags, ifp->metric, ifp->mtu, - if_is_operative(ifp)); + "%s: %s index %d vrf %s(%u) flags %ld metric %d mtu %d operative %d", + __func__, ifp->name, ifp->ifindex, ifp->vrf->name, + ifp->vrf->vrf_id, (long)ifp->flags, ifp->metric, + ifp->mtu, if_is_operative(ifp)); } if (!if_is_operative(ifp)) pim_if_addr_del_all(ifp); - pim = pim_get_pim_instance(ifp->vrf_id); + pim = ifp->vrf->info; if (pim && pim->vxlan.term_if == ifp) pim_vxlan_del_term_dev(pim); diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 55c278d6e2..72168b690a 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -61,6 +61,20 @@ #define PIM_I_am_DR(pim_ifp) (pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr #define PIM_I_am_DualActive(pim_ifp) (pim_ifp)->activeactive == true +/* Macros for interface flags */ + +/* + * PIM needs to know if hello is required to send before other PIM messages + * like Join, prune, assert would go out + */ +#define PIM_IF_FLAG_HELLO_SENT (1 << 0) + +#define PIM_IF_FLAG_TEST_HELLO_SENT(flags) ((flags)&PIM_IF_FLAG_HELLO_SENT) + +#define PIM_IF_FLAG_SET_HELLO_SENT(flags) ((flags) |= PIM_IF_FLAG_HELLO_SENT) + +#define PIM_IF_FLAG_UNSET_HELLO_SENT(flags) ((flags) &= ~PIM_IF_FLAG_HELLO_SENT) + struct pim_iface_upstream_switch { struct in_addr address; struct list *us; @@ -161,6 +175,7 @@ struct pim_interface { uint32_t pim_ifstat_bsm_cfg_miss; uint32_t pim_ifstat_ucast_bsm_cfg_miss; uint32_t pim_ifstat_bsm_invalid_sz; + uint8_t flags; bool bsm_enable; /* bsm processing enable */ bool ucast_bsm_accept; /* ucast bsm processing */ @@ -193,7 +208,6 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any); void pim_if_addr_add_all(struct interface *ifp); void pim_if_addr_del_all(struct interface *ifp); void pim_if_addr_del_all_igmp(struct interface *ifp); -void pim_if_addr_del_all_pim(struct interface *ifp); int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term); int pim_if_del_vif(struct interface *ifp); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 3f985e64b4..a17e8e89b2 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -651,18 +651,17 @@ struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, return ch; } -static void ifjoin_to_noinfo(struct pim_ifchannel *ch, bool ch_del) +static void ifjoin_to_noinfo(struct pim_ifchannel *ch) { - pim_forward_stop(ch, !ch_del); pim_ifchannel_ifjoin_switch(__func__, ch, PIM_IFJOIN_NOINFO); + pim_forward_stop(ch); if (ch->upstream) PIM_UPSTREAM_FLAG_UNSET_SRC_PIM(ch->upstream->flags); PIM_IF_FLAG_UNSET_PROTO_PIM(ch->flags); - if (ch_del) - delete_on_noinfo(ch); + delete_on_noinfo(ch); } static int on_ifjoin_expiry_timer(struct thread *t) @@ -675,7 +674,7 @@ static int on_ifjoin_expiry_timer(struct thread *t) zlog_debug("%s: ifchannel %s expiry timer", __func__, ch->sg_str); - ifjoin_to_noinfo(ch, true); + ifjoin_to_noinfo(ch); /* ch may have been deleted */ return 0; @@ -714,7 +713,7 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) &rpf, ch->upstream, 0); } - ifjoin_to_noinfo(ch, true); + ifjoin_to_noinfo(ch); } else { /* If SGRpt flag is set on ifchannel, Trigger SGRpt * message on RP path upon prune timer expiry. @@ -1021,6 +1020,7 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, if (remain > holdtime) return; } + THREAD_OFF(ch->t_ifjoin_expiry_timer); break; case PIM_IFJOIN_PRUNE_TMP: @@ -1567,10 +1567,3 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, if (send_upstream_starg) pim_jp_agg_single_upstream_send(&starup->rpf, starup, true); } - -unsigned int pim_ifchannel_hash_key(const void *arg) -{ - const struct pim_ifchannel *ch = arg; - - return jhash_2words(ch->sg.src.s_addr, ch->sg.grp.s_addr, 0); -} diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index 52f02a660b..332d40d926 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -160,6 +160,5 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, int pim_ifchannel_compare(const struct pim_ifchannel *ch1, const struct pim_ifchannel *ch2); -unsigned int pim_ifchannel_hash_key(const void *arg); void delete_on_noinfo(struct pim_ifchannel *ch); #endif /* PIM_IFCHANNEL_H */ diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 795c96c838..49ec804df5 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -39,7 +39,7 @@ #include "pim_time.h" #include "pim_zebra.h" -static void group_timer_off(struct igmp_group *group); +static void group_timer_off(struct gm_group *group); static int pim_igmp_general_query(struct thread *t); /* This socket is used for TXing IGMP packets only, IGMP RX happens @@ -115,7 +115,7 @@ static void igmp_sock_dump(array_t *igmp_sock_array) int size = array_size(igmp_sock_array); for (int i = 0; i < size; ++i) { - struct igmp_sock *igmp = array_get(igmp_sock_array, i); + struct gm_sock *igmp = array_get(igmp_sock_array, i); zlog_debug("%s %s: [%d/%d] igmp_addr=%pI4 fd=%d", __FILE__, __func__, i, size, &igmp->ifaddr, @@ -124,11 +124,11 @@ static void igmp_sock_dump(array_t *igmp_sock_array) } #endif -struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, - struct in_addr ifaddr) +struct gm_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, + struct in_addr ifaddr) { struct listnode *sock_node; - struct igmp_sock *igmp; + struct gm_sock *igmp; #ifdef IGMP_SOCK_DUMP igmp_sock_dump(igmp_sock_list); @@ -141,21 +141,9 @@ struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, return NULL; } -struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, int fd) -{ - struct listnode *sock_node; - struct igmp_sock *igmp; - - for (ALL_LIST_ELEMENTS_RO(igmp_sock_list, sock_node, igmp)) - if (fd == igmp->fd) - return igmp; - - return NULL; -} - static int pim_igmp_other_querier_expire(struct thread *t) { - struct igmp_sock *igmp; + struct gm_sock *igmp; igmp = THREAD_ARG(t); @@ -182,7 +170,7 @@ static int pim_igmp_other_querier_expire(struct thread *t) return 0; } -void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp) +void pim_igmp_other_querier_timer_on(struct gm_sock *igmp) { long other_querier_present_interval_msec; struct pim_interface *pim_ifp; @@ -255,7 +243,7 @@ void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp) &igmp->t_other_querier_timer); } -void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp) +void pim_igmp_other_querier_timer_off(struct gm_sock *igmp) { assert(igmp); @@ -293,7 +281,7 @@ int igmp_validate_checksum(char *igmp_msg, int igmp_msg_len) return 0; } -static int igmp_recv_query(struct igmp_sock *igmp, int query_version, +static int igmp_recv_query(struct gm_sock *igmp, int query_version, int max_resp_code, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) @@ -324,7 +312,7 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version, return 0; } - if (if_lookup_exact_address(&from, AF_INET, ifp->vrf_id)) { + if (if_address_is_local(&from, AF_INET, ifp->vrf->vrf_id)) { if (PIM_DEBUG_IGMP_PACKETS) zlog_debug("Recv IGMP query on interface: %s from ourself %s", ifp->name, from_str); @@ -423,12 +411,12 @@ static void on_trace(const char *label, struct interface *ifp, } } -static int igmp_v1_recv_report(struct igmp_sock *igmp, struct in_addr from, +static int igmp_v1_recv_report(struct gm_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp = igmp->interface; - struct igmp_group *group; + struct gm_group *group; struct in_addr group_addr; on_trace(__func__, igmp->interface, from); @@ -530,7 +518,7 @@ bool pim_igmp_verify_header(struct ip *ip_hdr, size_t len, size_t *hlen) return true; } -int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) +int pim_igmp_packet(struct gm_sock *igmp, char *buf, size_t len) { struct ip *ip_hdr = (struct ip *)buf; size_t ip_hlen; /* ip header length in bytes */ @@ -619,7 +607,7 @@ int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len) return -1; } -void pim_igmp_general_query_on(struct igmp_sock *igmp) +void pim_igmp_general_query_on(struct gm_sock *igmp) { struct pim_interface *pim_ifp; int startup_mode; @@ -675,7 +663,7 @@ void pim_igmp_general_query_on(struct igmp_sock *igmp) query_interval, &igmp->t_igmp_query_timer); } -void pim_igmp_general_query_off(struct igmp_sock *igmp) +void pim_igmp_general_query_off(struct gm_sock *igmp) { assert(igmp); @@ -695,7 +683,7 @@ void pim_igmp_general_query_off(struct igmp_sock *igmp) /* Issue IGMP general query */ static int pim_igmp_general_query(struct thread *t) { - struct igmp_sock *igmp; + struct gm_sock *igmp; struct in_addr dst_addr; struct in_addr group_addr; struct pim_interface *pim_ifp; @@ -751,7 +739,7 @@ static int pim_igmp_general_query(struct thread *t) return 0; } -static void sock_close(struct igmp_sock *igmp) +static void sock_close(struct gm_sock *igmp) { pim_igmp_other_querier_timer_off(igmp); pim_igmp_general_query_off(igmp); @@ -781,7 +769,7 @@ static void sock_close(struct igmp_sock *igmp) } } -void igmp_startup_mode_on(struct igmp_sock *igmp) +void igmp_startup_mode_on(struct gm_sock *igmp) { struct pim_interface *pim_ifp; @@ -802,7 +790,7 @@ void igmp_startup_mode_on(struct igmp_sock *igmp) igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; } -static void igmp_group_free(struct igmp_group *group) +static void igmp_group_free(struct gm_group *group) { list_delete(&group->group_source_list); @@ -832,11 +820,11 @@ static void igmp_group_count_decr(struct pim_interface *pim_ifp) --pim_ifp->pim->igmp_group_count; } -void igmp_group_delete(struct igmp_group *group) +void igmp_group_delete(struct gm_group *group) { struct listnode *src_node; struct listnode *src_nextnode; - struct igmp_source *src; + struct gm_source *src; struct pim_interface *pim_ifp = group->interface->info; if (PIM_DEBUG_IGMP_TRACE) { @@ -862,7 +850,7 @@ void igmp_group_delete(struct igmp_group *group) igmp_group_free(group); } -void igmp_group_delete_empty_include(struct igmp_group *group) +void igmp_group_delete_empty_include(struct gm_group *group) { assert(!group->group_filtermode_isexcl); assert(!listcount(group->group_source_list)); @@ -870,7 +858,7 @@ void igmp_group_delete_empty_include(struct igmp_group *group) igmp_group_delete(group); } -void igmp_sock_free(struct igmp_sock *igmp) +void igmp_sock_free(struct gm_sock *igmp) { assert(!igmp->t_igmp_read); assert(!igmp->t_igmp_query_timer); @@ -879,7 +867,7 @@ void igmp_sock_free(struct igmp_sock *igmp) XFREE(MTYPE_PIM_IGMP_SOCKET, igmp); } -void igmp_sock_delete(struct igmp_sock *igmp) +void igmp_sock_delete(struct gm_sock *igmp) { struct pim_interface *pim_ifp; @@ -899,7 +887,7 @@ void igmp_sock_delete_all(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *igmp_node, *igmp_nextnode; - struct igmp_sock *igmp; + struct gm_sock *igmp; pim_ifp = ifp->info; @@ -911,15 +899,15 @@ void igmp_sock_delete_all(struct interface *ifp) static unsigned int igmp_group_hash_key(const void *arg) { - const struct igmp_group *group = arg; + const struct gm_group *group = arg; return jhash_1word(group->group_addr.s_addr, 0); } static bool igmp_group_hash_equal(const void *arg1, const void *arg2) { - const struct igmp_group *g1 = (const struct igmp_group *)arg1; - const struct igmp_group *g2 = (const struct igmp_group *)arg2; + const struct gm_group *g1 = (const struct gm_group *)arg1; + const struct gm_group *g2 = (const struct gm_group *)arg2; if (g1->group_addr.s_addr == g2->group_addr.s_addr) return true; @@ -945,7 +933,7 @@ void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp) void pim_igmp_if_reset(struct pim_interface *pim_ifp) { struct listnode *grp_node, *grp_nextnode; - struct igmp_group *grp; + struct gm_group *grp; for (ALL_LIST_ELEMENTS(pim_ifp->igmp_group_list, grp_node, grp_nextnode, grp)) { @@ -966,11 +954,11 @@ void pim_igmp_if_fini(struct pim_interface *pim_ifp) list_delete(&pim_ifp->igmp_socket_list); } -static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, - struct interface *ifp, int mtrace_only) +static struct gm_sock *igmp_sock_new(int fd, struct in_addr ifaddr, + struct interface *ifp, int mtrace_only) { struct pim_interface *pim_ifp; - struct igmp_sock *igmp; + struct gm_sock *igmp; pim_ifp = ifp->info; @@ -1013,12 +1001,12 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, return igmp; } -static void igmp_read_on(struct igmp_sock *igmp); +static void igmp_read_on(struct gm_sock *igmp); static int pim_igmp_read(struct thread *t) { uint8_t buf[10000]; - struct igmp_sock *igmp = (struct igmp_sock *)THREAD_ARG(t); + struct gm_sock *igmp = (struct gm_sock *)THREAD_ARG(t); struct sockaddr_in from; struct sockaddr_in to; socklen_t fromlen = sizeof(from); @@ -1044,7 +1032,7 @@ done: return 0; } -static void igmp_read_on(struct igmp_sock *igmp) +static void igmp_read_on(struct gm_sock *igmp) { if (PIM_DEBUG_IGMP_TRACE_DETAIL) { @@ -1055,13 +1043,12 @@ static void igmp_read_on(struct igmp_sock *igmp) &igmp->t_igmp_read); } -struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, - struct in_addr ifaddr, - struct interface *ifp, - bool mtrace_only) +struct gm_sock *pim_igmp_sock_add(struct list *igmp_sock_list, + struct in_addr ifaddr, struct interface *ifp, + bool mtrace_only) { struct pim_interface *pim_ifp; - struct igmp_sock *igmp; + struct gm_sock *igmp; struct sockaddr_in sin; int fd; @@ -1114,7 +1101,7 @@ struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, */ static int igmp_group_timer(struct thread *t) { - struct igmp_group *group; + struct gm_group *group; group = THREAD_ARG(t); @@ -1150,7 +1137,7 @@ static int igmp_group_timer(struct thread *t) return 0; } -static void group_timer_off(struct igmp_group *group) +static void group_timer_off(struct gm_group *group) { if (!group->t_group_timer) return; @@ -1165,7 +1152,7 @@ static void group_timer_off(struct igmp_group *group) THREAD_OFF(group->t_group_timer); } -void igmp_group_timer_on(struct igmp_group *group, long interval_msec, +void igmp_group_timer_on(struct gm_group *group, long interval_msec, const char *ifname) { group_timer_off(group); @@ -1193,10 +1180,10 @@ void igmp_group_timer_on(struct igmp_group *group, long interval_msec, interval_msec, &group->t_group_timer); } -struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, - struct in_addr group_addr) +struct gm_group *find_group_by_addr(struct gm_sock *igmp, + struct in_addr group_addr) { - struct igmp_group lookup; + struct gm_group lookup; struct pim_interface *pim_ifp = igmp->interface->info; lookup.group_addr.s_addr = group_addr.s_addr; @@ -1204,10 +1191,10 @@ struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, return hash_lookup(pim_ifp->igmp_group_hash, &lookup); } -struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, - struct in_addr group_addr) +struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp, + struct in_addr group_addr) { - struct igmp_group *group; + struct gm_group *group; struct pim_interface *pim_ifp = igmp->interface->info; group = find_group_by_addr(igmp, group_addr); @@ -1289,7 +1276,7 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, return group; } -void igmp_send_query(int igmp_version, struct igmp_group *group, int fd, +void igmp_send_query(int igmp_version, struct gm_group *group, int fd, const char *ifname, char *query_buf, int query_buf_size, int num_sources, struct in_addr dst_addr, struct in_addr group_addr, @@ -1313,7 +1300,7 @@ void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver) { struct pim_interface *pim_ifp = ifp->info; struct listnode *sock_node = NULL; - struct igmp_sock *igmp = NULL; + struct gm_sock *igmp = NULL; struct in_addr dst_addr; struct in_addr group_addr; int query_buf_size; diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index dfe986e8f5..0a7e0605a5 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -75,14 +75,14 @@ output |= *((ptr) + 1); \ } while (0) -struct igmp_join { +struct gm_join { struct in_addr group_addr; struct in_addr source_addr; int sock_fd; time_t sock_creation; }; -struct igmp_sock { +struct gm_sock { int fd; struct interface *interface; struct in_addr ifaddr; @@ -108,22 +108,20 @@ void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp); void pim_igmp_if_reset(struct pim_interface *pim_ifp); void pim_igmp_if_fini(struct pim_interface *pim_ifp); -struct igmp_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, - struct in_addr ifaddr); -struct igmp_sock *igmp_sock_lookup_by_fd(struct list *igmp_sock_list, int fd); -struct igmp_sock *pim_igmp_sock_add(struct list *igmp_sock_list, - struct in_addr ifaddr, - struct interface *ifp, - bool mtrace_only); -void igmp_sock_delete(struct igmp_sock *igmp); -void igmp_sock_free(struct igmp_sock *igmp); +struct gm_sock *pim_igmp_sock_lookup_ifaddr(struct list *igmp_sock_list, + struct in_addr ifaddr); +struct gm_sock *pim_igmp_sock_add(struct list *igmp_sock_list, + struct in_addr ifaddr, struct interface *ifp, + bool mtrace_only); +void igmp_sock_delete(struct gm_sock *igmp); +void igmp_sock_free(struct gm_sock *igmp); void igmp_sock_delete_all(struct interface *ifp); -int pim_igmp_packet(struct igmp_sock *igmp, char *buf, size_t len); +int pim_igmp_packet(struct gm_sock *igmp, char *buf, size_t len); bool pim_igmp_verify_header(struct ip *ip_hdr, size_t len, size_t *ip_hlen); -void pim_igmp_general_query_on(struct igmp_sock *igmp); -void pim_igmp_general_query_off(struct igmp_sock *igmp); -void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp); -void pim_igmp_other_querier_timer_off(struct igmp_sock *igmp); +void pim_igmp_general_query_on(struct gm_sock *igmp); +void pim_igmp_general_query_off(struct gm_sock *igmp); +void pim_igmp_other_querier_timer_on(struct gm_sock *igmp); +void pim_igmp_other_querier_timer_off(struct gm_sock *igmp); int igmp_validate_checksum(char *igmp_msg, int igmp_msg_len); @@ -140,10 +138,10 @@ int igmp_validate_checksum(char *igmp_msg, int igmp_msg_len); #define IGMP_SOURCE_DONT_DELETE(flags) ((flags) &= ~IGMP_SOURCE_MASK_DELETE) #define IGMP_SOURCE_DONT_SEND(flags) ((flags) &= ~IGMP_SOURCE_MASK_SEND) -struct igmp_source { +struct gm_source { struct in_addr source_addr; struct thread *t_source_timer; - struct igmp_group *source_group; /* back pointer */ + struct gm_group *source_group; /* back pointer */ time_t source_creation; uint32_t source_flags; struct channel_oil *source_channel_oil; @@ -155,7 +153,7 @@ struct igmp_source { int source_query_retransmit_count; }; -struct igmp_group { +struct gm_group { /* RFC 3376: 6.2.2. Definition of Group Timers @@ -179,37 +177,37 @@ struct igmp_group { struct in_addr group_addr; int group_filtermode_isexcl; /* 0=INCLUDE, 1=EXCLUDE */ - struct list *group_source_list; /* list of struct igmp_source */ + struct list *group_source_list; /* list of struct gm_source */ time_t group_creation; struct interface *interface; int64_t last_igmp_v1_report_dsec; int64_t last_igmp_v2_report_dsec; }; -struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, - struct in_addr group_addr); -struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, - struct in_addr group_addr); +struct gm_group *find_group_by_addr(struct gm_sock *igmp, + struct in_addr group_addr); +struct gm_group *igmp_add_group_by_addr(struct gm_sock *igmp, + struct in_addr group_addr); -struct igmp_source *igmp_get_source_by_addr(struct igmp_group *group, - struct in_addr src_addr, - bool *created); +struct gm_source *igmp_get_source_by_addr(struct gm_group *group, + struct in_addr src_addr, + bool *created); -void igmp_group_delete_empty_include(struct igmp_group *group); +void igmp_group_delete_empty_include(struct gm_group *group); -void igmp_startup_mode_on(struct igmp_sock *igmp); +void igmp_startup_mode_on(struct gm_sock *igmp); -void igmp_group_timer_on(struct igmp_group *group, long interval_msec, +void igmp_group_timer_on(struct gm_group *group, long interval_msec, const char *ifname); -void igmp_send_query(int igmp_version, struct igmp_group *group, int fd, +void igmp_send_query(int igmp_version, struct gm_group *group, int fd, const char *ifname, char *query_buf, int query_buf_size, int num_sources, struct in_addr dst_addr, struct in_addr group_addr, int query_max_response_time_dsec, uint8_t s_flag, uint8_t querier_robustness_variable, uint16_t querier_query_interval); -void igmp_group_delete(struct igmp_group *group); +void igmp_group_delete(struct gm_group *group); void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver); #endif /* PIM_IGMP_H */ diff --git a/pimd/pim_igmp_mtrace.c b/pimd/pim_igmp_mtrace.c index 73af44fc46..65a8ca4e40 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -564,7 +564,7 @@ static int mtrace_send_response(struct pim_instance *pim, mtracep->rsp_addr, mtracep->grp_addr); } -int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr, +int igmp_mtrace_recv_qry_req(struct gm_sock *igmp, struct ip *ip_hdr, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { @@ -596,8 +596,8 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr, * if applicable */ if (!IPV4_CLASS_DE(ntohl(ip_hdr->ip_dst.s_addr))) - if (!if_lookup_exact_address(&ip_hdr->ip_dst, AF_INET, - pim->vrf->vrf_id)) + if (!if_address_is_local(&ip_hdr->ip_dst, AF_INET, + pim->vrf->vrf_id)) return mtrace_forward_packet(pim, ip_hdr); if (igmp_msg_len < (int)sizeof(struct igmp_mtrace)) { @@ -799,7 +799,7 @@ int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr, } /* 6.3. Traceroute responses */ -int igmp_mtrace_recv_response(struct igmp_sock *igmp, struct ip *ip_hdr, +int igmp_mtrace_recv_response(struct gm_sock *igmp, struct ip *ip_hdr, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { diff --git a/pimd/pim_igmp_mtrace.h b/pimd/pim_igmp_mtrace.h index 4ab562ed97..760b2e417b 100644 --- a/pimd/pim_igmp_mtrace.h +++ b/pimd/pim_igmp_mtrace.h @@ -94,11 +94,11 @@ struct igmp_mtrace { #define MTRACE_HDR_SIZE (sizeof(struct igmp_mtrace)) #define MTRACE_RSP_SIZE (sizeof(struct igmp_mtrace_rsp)) -int igmp_mtrace_recv_qry_req(struct igmp_sock *igmp, struct ip *ip_hdr, +int igmp_mtrace_recv_qry_req(struct gm_sock *igmp, struct ip *ip_hdr, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len); -int igmp_mtrace_recv_response(struct igmp_sock *igmp, struct ip *ip_hdr, +int igmp_mtrace_recv_response(struct gm_sock *igmp, struct ip *ip_hdr, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len); diff --git a/pimd/pim_igmpv2.c b/pimd/pim_igmpv2.c index 6eadf87c83..2616afca69 100644 --- a/pimd/pim_igmpv2.c +++ b/pimd/pim_igmpv2.c @@ -39,7 +39,7 @@ static void on_trace(const char *label, struct interface *ifp, } } -void igmp_v2_send_query(struct igmp_group *group, int fd, const char *ifname, +void igmp_v2_send_query(struct gm_group *group, int fd, const char *ifname, char *query_buf, struct in_addr dst_addr, struct in_addr group_addr, int query_max_response_time_dsec) @@ -102,7 +102,7 @@ void igmp_v2_send_query(struct igmp_group *group, int fd, const char *ifname, } } -int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from, +int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp = igmp->interface; @@ -158,7 +158,7 @@ int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from, return 0; } -int igmp_v2_recv_leave(struct igmp_sock *igmp, struct ip *ip_hdr, +int igmp_v2_recv_leave(struct gm_sock *igmp, struct ip *ip_hdr, const char *from_str, char *igmp_msg, int igmp_msg_len) { struct interface *ifp = igmp->interface; diff --git a/pimd/pim_igmpv2.h b/pimd/pim_igmpv2.h index 29591ff16c..4e6dc6995c 100644 --- a/pimd/pim_igmpv2.h +++ b/pimd/pim_igmpv2.h @@ -21,15 +21,15 @@ #ifndef PIM_IGMPV2_H #define PIM_IGMPV2_H -void igmp_v2_send_query(struct igmp_group *group, int fd, const char *ifname, +void igmp_v2_send_query(struct gm_group *group, int fd, const char *ifname, char *query_buf, struct in_addr dst_addr, struct in_addr group_addr, int query_max_response_time_dsec); -int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from, +int igmp_v2_recv_report(struct gm_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len); -int igmp_v2_recv_leave(struct igmp_sock *igmp, struct ip *ip_hdr, +int igmp_v2_recv_leave(struct gm_sock *igmp, struct ip *ip_hdr, const char *from_str, char *igmp_msg, int igmp_msg_len); #endif /* PIM_IGMPV2_H */ diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 13db11fa80..614213bfa5 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -33,11 +33,11 @@ #include "pim_zebra.h" #include "pim_oil.h" -static void group_retransmit_timer_on(struct igmp_group *group); -static long igmp_group_timer_remain_msec(struct igmp_group *group); -static long igmp_source_timer_remain_msec(struct igmp_source *source); -static void group_query_send(struct igmp_group *group); -static void source_query_send_by_flag(struct igmp_group *group, +static void group_retransmit_timer_on(struct gm_group *group); +static long igmp_group_timer_remain_msec(struct gm_group *group); +static long igmp_source_timer_remain_msec(struct gm_source *source); +static void group_query_send(struct gm_group *group); +static void source_query_send_by_flag(struct gm_group *group, int num_sources_tosend); static void on_trace(const char *label, struct interface *ifp, @@ -57,10 +57,10 @@ static void on_trace(const char *label, struct interface *ifp, } } -static inline long igmp_gmi_msec(struct igmp_group *group) +static inline long igmp_gmi_msec(struct gm_group *group) { struct pim_interface *pim_ifp = group->interface->info; - struct igmp_sock *igmp; + struct gm_sock *igmp; struct listnode *sock_node; long qrv = 0, qqi = 0; @@ -73,7 +73,7 @@ static inline long igmp_gmi_msec(struct igmp_group *group) pim_ifp->igmp_query_max_response_time_dsec); } -void igmp_group_reset_gmi(struct igmp_group *group) +void igmp_group_reset_gmi(struct gm_group *group) { long group_membership_interval_msec; struct interface *ifp; @@ -120,8 +120,8 @@ void igmp_group_reset_gmi(struct igmp_group *group) static int igmp_source_timer(struct thread *t) { - struct igmp_source *source; - struct igmp_group *group; + struct gm_source *source; + struct gm_group *group; source = THREAD_ARG(t); @@ -183,8 +183,7 @@ static int igmp_source_timer(struct thread *t) return 0; } -static void source_timer_off(struct igmp_group *group, - struct igmp_source *source) +static void source_timer_off(struct gm_group *group, struct gm_source *source) { if (!source->t_source_timer) return; @@ -204,8 +203,8 @@ static void source_timer_off(struct igmp_group *group, THREAD_OFF(source->t_source_timer); } -static void igmp_source_timer_on(struct igmp_group *group, - struct igmp_source *source, long interval_msec) +static void igmp_source_timer_on(struct gm_group *group, + struct gm_source *source, long interval_msec) { source_timer_off(group, source); struct pim_interface *pim_ifp = group->interface->info; @@ -234,7 +233,7 @@ static void igmp_source_timer_on(struct igmp_group *group, igmp_source_forward_start(pim_ifp->pim, source); } -void igmp_source_reset_gmi(struct igmp_group *group, struct igmp_source *source) +void igmp_source_reset_gmi(struct gm_group *group, struct gm_source *source) { long group_membership_interval_msec; struct interface *ifp; @@ -262,30 +261,30 @@ void igmp_source_reset_gmi(struct igmp_group *group, struct igmp_source *source) igmp_source_timer_on(group, source, group_membership_interval_msec); } -static void source_mark_delete_flag(struct igmp_group *group) +static void source_mark_delete_flag(struct gm_group *group) { struct listnode *src_node; - struct igmp_source *src; + struct gm_source *src; for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) { IGMP_SOURCE_DO_DELETE(src->source_flags); } } -static void source_mark_send_flag(struct igmp_group *group) +static void source_mark_send_flag(struct gm_group *group) { struct listnode *src_node; - struct igmp_source *src; + struct gm_source *src; for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) { IGMP_SOURCE_DO_SEND(src->source_flags); } } -static int source_mark_send_flag_by_timer(struct igmp_group *group) +static int source_mark_send_flag_by_timer(struct gm_group *group) { struct listnode *src_node; - struct igmp_source *src; + struct gm_source *src; int num_marked_sources = 0; for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) { @@ -304,7 +303,7 @@ static int source_mark_send_flag_by_timer(struct igmp_group *group) static void source_clear_send_flag(struct list *source_list) { struct listnode *src_node; - struct igmp_source *src; + struct gm_source *src; for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) { IGMP_SOURCE_DONT_SEND(src->source_flags); @@ -314,7 +313,7 @@ static void source_clear_send_flag(struct list *source_list) /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ -static void group_exclude_fwd_anysrc_ifempty(struct igmp_group *group) +static void group_exclude_fwd_anysrc_ifempty(struct gm_group *group) { struct pim_interface *pim_ifp = group->interface->info; @@ -325,7 +324,7 @@ static void group_exclude_fwd_anysrc_ifempty(struct igmp_group *group) } } -void igmp_source_free(struct igmp_source *source) +void igmp_source_free(struct gm_source *source) { /* make sure there is no source timer running */ assert(!source->t_source_timer); @@ -333,7 +332,7 @@ void igmp_source_free(struct igmp_source *source) XFREE(MTYPE_PIM_IGMP_GROUP_SOURCE, source); } -static void source_channel_oil_detach(struct igmp_source *source) +static void source_channel_oil_detach(struct gm_source *source) { if (source->source_channel_oil) { pim_channel_oil_del(source->source_channel_oil, __func__); @@ -345,9 +344,9 @@ static void source_channel_oil_detach(struct igmp_source *source) igmp_source_delete: stop fowarding, and delete the source igmp_source_forward_stop: stop fowarding, but keep the source */ -void igmp_source_delete(struct igmp_source *source) +void igmp_source_delete(struct gm_source *source) { - struct igmp_group *group; + struct gm_group *group; struct in_addr src; group = source->source_group; @@ -410,7 +409,7 @@ static void source_delete_by_flag(struct list *source_list) { struct listnode *src_node; struct listnode *src_nextnode; - struct igmp_source *src; + struct gm_source *src; for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src)) if (IGMP_SOURCE_TEST_DELETE(src->source_flags)) @@ -421,18 +420,18 @@ void igmp_source_delete_expired(struct list *source_list) { struct listnode *src_node; struct listnode *src_nextnode; - struct igmp_source *src; + struct gm_source *src; for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src)) if (!src->t_source_timer) igmp_source_delete(src); } -struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, - struct in_addr src_addr) +struct gm_source *igmp_find_source_by_addr(struct gm_group *group, + struct in_addr src_addr) { struct listnode *src_node; - struct igmp_source *src; + struct gm_source *src; for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) if (src_addr.s_addr == src->source_addr.s_addr) @@ -441,10 +440,10 @@ struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, return 0; } -struct igmp_source *igmp_get_source_by_addr(struct igmp_group *group, - struct in_addr src_addr, bool *new) +struct gm_source *igmp_get_source_by_addr(struct gm_group *group, + struct in_addr src_addr, bool *new) { - struct igmp_source *src; + struct gm_source *src; if (new) *new = false; @@ -482,12 +481,12 @@ struct igmp_source *igmp_get_source_by_addr(struct igmp_group *group, return src; } -static void allow(struct igmp_sock *igmp, struct in_addr from, +static void allow(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { - struct igmp_source *source; - struct igmp_group *group; + struct gm_source *source; + struct gm_group *group; int i; if (num_sources == 0) { @@ -549,7 +548,7 @@ static void allow(struct igmp_sock *igmp, struct in_addr from, } /* scan received sources */ } -void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_isin(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { @@ -559,10 +558,10 @@ void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, allow(igmp, from, group_addr, num_sources, sources); } -static void isex_excl(struct igmp_group *group, int num_sources, +static void isex_excl(struct gm_group *group, int num_sources, struct in_addr *sources) { - struct igmp_source *source; + struct gm_source *source; int i; /* EXCLUDE mode */ @@ -614,7 +613,7 @@ static void isex_excl(struct igmp_group *group, int num_sources, source_delete_by_flag(group->group_source_list); } -static void isex_incl(struct igmp_group *group, int num_sources, +static void isex_incl(struct gm_group *group, int num_sources, struct in_addr *sources) { int i; @@ -627,7 +626,7 @@ static void isex_incl(struct igmp_group *group, int num_sources, /* scan received sources (B) */ for (i = 0; i < num_sources; ++i) { - struct igmp_source *source; + struct gm_source *source; struct in_addr *src_addr; bool new; @@ -659,12 +658,12 @@ static void isex_incl(struct igmp_group *group, int num_sources, group_exclude_fwd_anysrc_ifempty(group); } -void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_isex(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources, int from_igmp_v2_report) { struct interface *ifp = igmp->interface; - struct igmp_group *group; + struct gm_group *group; on_trace(__func__, ifp, from, group_addr, num_sources, sources); @@ -696,7 +695,7 @@ void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, igmp_group_reset_gmi(group); } -static void toin_incl(struct igmp_group *group, int num_sources, +static void toin_incl(struct gm_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = listcount(group->group_source_list); @@ -707,7 +706,7 @@ static void toin_incl(struct igmp_group *group, int num_sources, /* Scan received sources (B) */ for (i = 0; i < num_sources; ++i) { - struct igmp_source *source; + struct gm_source *source; struct in_addr *src_addr; bool new; @@ -734,7 +733,7 @@ static void toin_incl(struct igmp_group *group, int num_sources, } } -static void toin_excl(struct igmp_group *group, int num_sources, +static void toin_excl(struct gm_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend; @@ -745,7 +744,7 @@ static void toin_excl(struct igmp_group *group, int num_sources, /* Scan received sources (A) */ for (i = 0; i < num_sources; ++i) { - struct igmp_source *source; + struct gm_source *source; struct in_addr *src_addr; bool new; @@ -776,12 +775,12 @@ static void toin_excl(struct igmp_group *group, int num_sources, group_query_send(group); } -void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_toin(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; - struct igmp_group *group; + struct gm_group *group; on_trace(__func__, ifp, from, group_addr, num_sources, sources); @@ -812,7 +811,7 @@ void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, } } -static void toex_incl(struct igmp_group *group, int num_sources, +static void toex_incl(struct gm_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; @@ -828,7 +827,7 @@ static void toex_incl(struct igmp_group *group, int num_sources, /* Scan received sources (B) */ for (i = 0; i < num_sources; ++i) { - struct igmp_source *source; + struct gm_source *source; struct in_addr *src_addr; bool new; @@ -861,7 +860,7 @@ static void toex_incl(struct igmp_group *group, int num_sources, group_exclude_fwd_anysrc_ifempty(group); } -static void toex_excl(struct igmp_group *group, int num_sources, +static void toex_excl(struct gm_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; @@ -874,7 +873,7 @@ static void toex_excl(struct igmp_group *group, int num_sources, source_clear_send_flag(group->group_source_list); if (num_sources == 0) { - struct igmp_source *source; + struct gm_source *source; struct in_addr any = {.s_addr = INADDR_ANY}; source = igmp_find_source_by_addr(group, any); @@ -884,7 +883,7 @@ static void toex_excl(struct igmp_group *group, int num_sources, /* scan received sources (A) */ for (i = 0; i < num_sources; ++i) { - struct igmp_source *source; + struct gm_source *source; struct in_addr *src_addr; bool new; @@ -937,12 +936,12 @@ static void toex_excl(struct igmp_group *group, int num_sources, } } -void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_toex(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; - struct igmp_group *group; + struct gm_group *group; on_trace(__func__, ifp, from, group_addr, num_sources, sources); @@ -966,7 +965,7 @@ void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, igmp_group_reset_gmi(group); } -void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_allow(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { @@ -976,13 +975,13 @@ void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from, allow(igmp, from, group_addr, num_sources, sources); } -static void igmp_send_query_group(struct igmp_group *group, char *query_buf, +static void igmp_send_query_group(struct gm_group *group, char *query_buf, size_t query_buf_size, int num_sources, int s_flag) { struct interface *ifp = group->interface; struct pim_interface *pim_ifp = ifp->info; - struct igmp_sock *igmp; + struct gm_sock *igmp; struct listnode *sock_node; for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { @@ -1003,7 +1002,7 @@ static void igmp_send_query_group(struct igmp_group *group, char *query_buf, larger than LMQT, the "Suppress Router-Side Processing" bit is set in the query message. */ -static void group_retransmit_group(struct igmp_group *group) +static void group_retransmit_group(struct gm_group *group) { struct pim_interface *pim_ifp; long lmqc; /* Last Member Query Count */ @@ -1068,7 +1067,7 @@ static void group_retransmit_group(struct igmp_group *group) or equal to LMQT. If either of the two calculated messages does not contain any sources, then its transmission is suppressed. */ -static int group_retransmit_sources(struct igmp_group *group, +static int group_retransmit_sources(struct gm_group *group, int send_with_sflag_set) { struct pim_interface *pim_ifp; @@ -1084,7 +1083,7 @@ static int group_retransmit_sources(struct igmp_group *group, int num_sources_tosend1; int num_sources_tosend2; struct listnode *src_node; - struct igmp_source *src; + struct gm_source *src; int num_retransmit_sources_left = 0; source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET); @@ -1215,7 +1214,7 @@ static int group_retransmit_sources(struct igmp_group *group, static int igmp_group_retransmit(struct thread *t) { - struct igmp_group *group; + struct gm_group *group; int num_retransmit_sources_left; int send_with_sflag_set; /* boolean */ @@ -1272,7 +1271,7 @@ static int igmp_group_retransmit(struct thread *t) if group retransmit timer isn't running, starts it; otherwise, do nothing */ -static void group_retransmit_timer_on(struct igmp_group *group) +static void group_retransmit_timer_on(struct gm_group *group) { struct pim_interface *pim_ifp; long lmqi_msec; /* Last Member Query Interval */ @@ -1301,12 +1300,12 @@ static void group_retransmit_timer_on(struct igmp_group *group) &group->t_group_query_retransmit_timer); } -static long igmp_group_timer_remain_msec(struct igmp_group *group) +static long igmp_group_timer_remain_msec(struct gm_group *group) { return pim_time_timer_remain_msec(group->t_group_timer); } -static long igmp_source_timer_remain_msec(struct igmp_source *source) +static long igmp_source_timer_remain_msec(struct gm_source *source) { return pim_time_timer_remain_msec(source->t_source_timer); } @@ -1314,7 +1313,7 @@ static long igmp_source_timer_remain_msec(struct igmp_source *source) /* RFC3376: 6.6.3.1. Building and Sending Group Specific Queries */ -static void group_query_send(struct igmp_group *group) +static void group_query_send(struct gm_group *group) { struct pim_interface *pim_ifp; long lmqc; /* Last Member Query Count */ @@ -1339,12 +1338,12 @@ static void group_query_send(struct igmp_group *group) /* RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries */ -static void source_query_send_by_flag(struct igmp_group *group, +static void source_query_send_by_flag(struct gm_group *group, int num_sources_tosend) { struct pim_interface *pim_ifp; struct listnode *src_node; - struct igmp_source *src; + struct gm_source *src; long lmqc; /* Last Member Query Count */ long lmqi_msec; /* Last Member Query Interval */ long lmqt_msec; /* Last Member Query Time */ @@ -1385,7 +1384,7 @@ static void source_query_send_by_flag(struct igmp_group *group, group_retransmit_timer_on(group); } -static void block_excl(struct igmp_group *group, int num_sources, +static void block_excl(struct gm_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; @@ -1396,7 +1395,7 @@ static void block_excl(struct igmp_group *group, int num_sources, /* 2. scan received sources (A) */ for (i = 0; i < num_sources; ++i) { - struct igmp_source *source; + struct gm_source *source; struct in_addr *src_addr; bool new; @@ -1431,7 +1430,7 @@ static void block_excl(struct igmp_group *group, int num_sources, } } -static void block_incl(struct igmp_group *group, int num_sources, +static void block_incl(struct gm_group *group, int num_sources, struct in_addr *sources) { int num_sources_tosend = 0; @@ -1442,7 +1441,7 @@ static void block_incl(struct igmp_group *group, int num_sources, /* 2. scan received sources (A) */ for (i = 0; i < num_sources; ++i) { - struct igmp_source *source; + struct gm_source *source; struct in_addr *src_addr; src_addr = sources + i; @@ -1462,12 +1461,12 @@ static void block_incl(struct igmp_group *group, int num_sources, } } -void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_block(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources) { struct interface *ifp = igmp->interface; - struct igmp_group *group; + struct gm_group *group; on_trace(__func__, ifp, from, group_addr, num_sources, sources); @@ -1486,7 +1485,7 @@ void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, } } -void igmp_group_timer_lower_to_lmqt(struct igmp_group *group) +void igmp_group_timer_lower_to_lmqt(struct gm_group *group) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1530,9 +1529,9 @@ void igmp_group_timer_lower_to_lmqt(struct igmp_group *group) igmp_group_timer_on(group, lmqt_msec, ifname); } -void igmp_source_timer_lower_to_lmqt(struct igmp_source *source) +void igmp_source_timer_lower_to_lmqt(struct gm_source *source) { - struct igmp_group *group; + struct gm_group *group; struct interface *ifp; struct pim_interface *pim_ifp; char *ifname; @@ -1566,7 +1565,7 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source) igmp_source_timer_on(group, source, lmqt_msec); } -void igmp_v3_send_query(struct igmp_group *group, int fd, const char *ifname, +void igmp_v3_send_query(struct gm_group *group, int fd, const char *ifname, char *query_buf, int query_buf_size, int num_sources, struct in_addr dst_addr, struct in_addr group_addr, int query_max_response_time_dsec, uint8_t s_flag, @@ -1691,7 +1690,7 @@ void igmp_v3_send_query(struct igmp_group *group, int fd, const char *ifname, } } -void igmp_v3_recv_query(struct igmp_sock *igmp, const char *from_str, +void igmp_v3_recv_query(struct gm_sock *igmp, const char *from_str, char *igmp_msg) { struct interface *ifp; @@ -1770,7 +1769,7 @@ void igmp_v3_recv_query(struct igmp_sock *igmp, const char *from_str, "General IGMP query v3 from %s on %s: Suppress Router-Side Processing flag is clear", from_str, ifp->name); } else { - struct igmp_group *group; + struct gm_group *group; /* this is a non-general query: perform timer updates */ @@ -1804,7 +1803,7 @@ void igmp_v3_recv_query(struct igmp_sock *igmp, const char *from_str, + IGMP_V3_SOURCES_OFFSET); for (i = 0; i < recv_num_sources; ++i) { struct in_addr src_addr; - struct igmp_source *src; + struct gm_source *src; memcpy(&src_addr, sources + i, sizeof(struct in_addr)); src = igmp_find_source_by_addr( @@ -1827,7 +1826,7 @@ void igmp_v3_recv_query(struct igmp_sock *igmp, const char *from_str, } /* s_flag is clear: timer updates */ } -int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from, +int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len) { int num_groups; diff --git a/pimd/pim_igmpv3.h b/pimd/pim_igmpv3.h index 273f944b3c..7449e420e4 100644 --- a/pimd/pim_igmpv3.h +++ b/pimd/pim_igmpv3.h @@ -53,50 +53,49 @@ /* OHPI: Older Host Present Interval */ #define PIM_IGMP_OHPI_DSEC(qrv,qqi,qri_dsec) ((qrv) * (10 * (qqi)) + (qri_dsec)) -void igmp_group_reset_gmi(struct igmp_group *group); -void igmp_source_reset_gmi(struct igmp_group *group, - struct igmp_source *source); +void igmp_group_reset_gmi(struct gm_group *group); +void igmp_source_reset_gmi(struct gm_group *group, struct gm_source *source); -void igmp_source_free(struct igmp_source *source); -void igmp_source_delete(struct igmp_source *source); +void igmp_source_free(struct gm_source *source); +void igmp_source_delete(struct gm_source *source); void igmp_source_delete_expired(struct list *source_list); -void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_isin(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); -void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_isex(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources, int from_igmp_v2_report); -void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_toin(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); -void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_toex(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); -void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_allow(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); -void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from, +void igmpv3_report_block(struct gm_sock *igmp, struct in_addr from, struct in_addr group_addr, int num_sources, struct in_addr *sources); -void igmp_group_timer_lower_to_lmqt(struct igmp_group *group); -void igmp_source_timer_lower_to_lmqt(struct igmp_source *source); +void igmp_group_timer_lower_to_lmqt(struct gm_group *group); +void igmp_source_timer_lower_to_lmqt(struct gm_source *source); -struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group, - struct in_addr src_addr); +struct gm_source *igmp_find_source_by_addr(struct gm_group *group, + struct in_addr src_addr); -void igmp_v3_send_query(struct igmp_group *group, int fd, const char *ifname, +void igmp_v3_send_query(struct gm_group *group, int fd, const char *ifname, char *query_buf, int query_buf_size, int num_sources, struct in_addr dst_addr, struct in_addr group_addr, int query_max_response_time_dsec, uint8_t s_flag, uint8_t querier_robustness_variable, uint16_t querier_query_interval); -void igmp_v3_recv_query(struct igmp_sock *igmp, const char *from_str, +void igmp_v3_recv_query(struct gm_sock *igmp, const char *from_str, char *igmp_msg); -int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from, +int igmp_v3_recv_report(struct gm_sock *igmp, struct in_addr from, const char *from_str, char *igmp_msg, int igmp_msg_len); #endif /* PIM_IGMPV3_H */ diff --git a/pimd/pim_join.c b/pimd/pim_join.c index c7a80ca8e0..4606aec6a1 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -1,3 +1,5 @@ + + /* * PIM for Quagga * Copyright (C) 2008 Everton da Silva Marques @@ -39,6 +41,7 @@ #include "pim_rp.h" #include "pim_jp_agg.h" #include "pim_util.h" +#include "pim_ssm.h" static void on_trace(const char *label, struct interface *ifp, struct in_addr src) @@ -105,6 +108,13 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, return; } + if (pim_is_grp_ssm(pim_ifp->pim, sg->grp)) { + zlog_warn( + "%s: Specified Group(%pI4) in join is now in SSM, not allowed to create PIM state", + __func__, &sg->grp); + return; + } + sg->src.s_addr = INADDR_ANY; } diff --git a/pimd/pim_jp_agg.c b/pimd/pim_jp_agg.c index d95d9dd25d..5c6f55e99d 100644 --- a/pimd/pim_jp_agg.c +++ b/pimd/pim_jp_agg.c @@ -368,7 +368,7 @@ void pim_jp_agg_single_upstream_send(struct pim_rpf *rpf, if (!up || !rpf->source_nexthop.interface || pim_if_connected_to_source(rpf->source_nexthop.interface, up->sg.src) || - if_is_loopback_or_vrf(rpf->source_nexthop.interface)) + if_is_loopback(rpf->source_nexthop.interface)) return; memset(&groups, 0, sizeof(groups)); diff --git a/pimd/pim_mlag.c b/pimd/pim_mlag.c index a06c0a6f4e..55d6e7e0fd 100644 --- a/pimd/pim_mlag.c +++ b/pimd/pim_mlag.c @@ -791,8 +791,10 @@ static void pim_mlag_process_mroute_del(struct mlag_mroute_del msg) pim_mlag_up_peer_del(&msg); } -int pim_zebra_mlag_handle_msg(struct stream *s, int len) +int pim_zebra_mlag_handle_msg(int cmd, struct zclient *zclient, + uint16_t zapi_length, vrf_id_t vrf_id) { + struct stream *s = zclient->ibuf; struct mlag_msg mlag_msg; char buf[80]; int rc = 0; @@ -880,7 +882,7 @@ int pim_zebra_mlag_handle_msg(struct stream *s, int len) /****************End of PIM Mesasge processing handler********************/ -int pim_zebra_mlag_process_up(void) +int pim_zebra_mlag_process_up(ZAPI_CALLBACK_ARGS) { if (PIM_DEBUG_MLAG) zlog_debug("%s: Received Process-Up from Mlag", __func__); @@ -908,7 +910,7 @@ static void pim_mlag_param_reset(void) router->peerlink_rif[0] = '\0'; } -int pim_zebra_mlag_process_down(void) +int pim_zebra_mlag_process_down(ZAPI_CALLBACK_ARGS) { if (PIM_DEBUG_MLAG) zlog_debug("%s: Received Process-Down from Mlag", __func__); diff --git a/pimd/pim_mlag.h b/pimd/pim_mlag.h index b044c31c44..996e4d473f 100644 --- a/pimd/pim_mlag.h +++ b/pimd/pim_mlag.h @@ -24,6 +24,7 @@ #ifndef __PIM_MLAG_H__ #define __PIM_MLAG_H__ +#include "zclient.h" #include "mlag.h" #include "pim_iface.h" @@ -33,9 +34,9 @@ extern void pim_instance_mlag_init(struct pim_instance *pim); extern void pim_instance_mlag_terminate(struct pim_instance *pim); extern void pim_if_configure_mlag_dualactive(struct pim_interface *pim_ifp); extern void pim_if_unconfigure_mlag_dualactive(struct pim_interface *pim_ifp); -extern int pim_zebra_mlag_process_up(void); -extern int pim_zebra_mlag_process_down(void); -extern int pim_zebra_mlag_handle_msg(struct stream *msg, int len); +extern int pim_zebra_mlag_process_up(ZAPI_CALLBACK_ARGS); +extern int pim_zebra_mlag_process_down(ZAPI_CALLBACK_ARGS); +extern int pim_zebra_mlag_handle_msg(ZAPI_CALLBACK_ARGS); /* pm_zpthread.c */ extern int pim_mlag_signal_zpthread(void); diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 7743bcc510..ad21178849 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -593,7 +593,7 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf, const struct ip *ip_hdr; const struct igmpmsg *msg; struct in_addr ifaddr; - struct igmp_sock *igmp; + struct gm_sock *igmp; const struct prefix *connected_src; if (buf_size < (int)sizeof(struct ip)) diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index ddba33ff9d..fa7f1da79a 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -1304,7 +1304,6 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, struct pim_msdp_mg *mg; struct listnode *mbrnode; struct pim_msdp_mg_mbr *mbr; - char mbr_str[INET_ADDRSTRLEN]; char src_str[INET_ADDRSTRLEN]; int count = 0; @@ -1321,10 +1320,8 @@ int pim_msdp_config_write(struct pim_instance *pim, struct vty *vty, } for (ALL_LIST_ELEMENTS_RO(mg->mbr_list, mbrnode, mbr)) { - pim_inet4_dump("<mbr?>", mbr->mbr_ip, mbr_str, - sizeof(mbr_str)); - vty_out(vty, "%sip msdp mesh-group %s member %s\n", - spaces, mg->mesh_group_name, mbr_str); + vty_out(vty, "%sip msdp mesh-group %s member %pI4\n", + spaces, mg->mesh_group_name, &mbr->mbr_ip); ++count; } } diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h index f5af8d1140..10b7ca4198 100644 --- a/pimd/pim_msdp_packet.h +++ b/pimd/pim_msdp_packet.h @@ -58,7 +58,8 @@ * fragmentation */ #define PIM_MSDP_SA_MAX_ENTRY_CNT 120 -#define PIM_MSDP_MAX_PACKET_SIZE max(PIM_MSDP_SA_TLV_MAX_SIZE, PIM_MSDP_KA_TLV_MAX_SIZE) +#define PIM_MSDP_MAX_PACKET_SIZE \ + MAX(PIM_MSDP_SA_TLV_MAX_SIZE, PIM_MSDP_KA_TLV_MAX_SIZE) #define PIM_MSDP_PKT_TYPE_STRLEN 16 diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index b9da8ec068..9b79646daf 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -62,7 +62,7 @@ static void pim_if_membership_refresh(struct interface *ifp) { struct pim_interface *pim_ifp; struct listnode *grpnode; - struct igmp_group *grp; + struct gm_group *grp; pim_ifp = ifp->info; @@ -88,7 +88,7 @@ static void pim_if_membership_refresh(struct interface *ifp) /* scan igmp groups */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, grp)) { struct listnode *srcnode; - struct igmp_source *src; + struct gm_source *src; /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, @@ -365,20 +365,12 @@ static int pim_cmd_igmp_start(struct interface *ifp) * This function propagates the reconfiguration to every active socket * for that interface. */ -static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) +static void igmp_sock_query_interval_reconfig(struct gm_sock *igmp) { struct interface *ifp; struct pim_interface *pim_ifp; assert(igmp); - - /* other querier present? */ - - if (igmp->t_other_querier_timer) - return; - - /* this is the querier */ - assert(igmp->interface); assert(igmp->interface->info); @@ -403,7 +395,7 @@ static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) igmp_startup_mode_on(igmp); } -static void igmp_sock_query_reschedule(struct igmp_sock *igmp) +static void igmp_sock_query_reschedule(struct gm_sock *igmp) { if (igmp->mtrace_only) return; @@ -436,7 +428,7 @@ static void change_query_interval(struct pim_interface *pim_ifp, int query_interval) { struct listnode *sock_node; - struct igmp_sock *igmp; + struct gm_sock *igmp; pim_ifp->igmp_default_query_interval = query_interval; @@ -450,9 +442,9 @@ static void change_query_max_response_time(struct pim_interface *pim_ifp, int query_max_response_time_dsec) { struct listnode *sock_node; - struct igmp_sock *igmp; + struct gm_sock *igmp; struct listnode *grp_node; - struct igmp_group *grp; + struct gm_group *grp; if (pim_ifp->igmp_query_max_response_time_dsec == query_max_response_time_dsec) @@ -476,7 +468,7 @@ static void change_query_max_response_time(struct pim_interface *pim_ifp, /* scan socket groups */ for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grp_node, grp)) { struct listnode *src_node; - struct igmp_source *src; + struct gm_source *src; /* reset group timers for groups in EXCLUDE mode */ if (grp->group_filtermode_isexcl) diff --git a/pimd/pim_neighbor.c b/pimd/pim_neighbor.c index 571173c62a..530c2e429b 100644 --- a/pimd/pim_neighbor.c +++ b/pimd/pim_neighbor.c @@ -341,7 +341,7 @@ pim_neighbor_new(struct interface *ifp, struct in_addr source_addr, * reset the value so that we can know to hurry up and * hello */ - pim_ifp->pim_ifstat_hello_sent = 0; + PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags); pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str)); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 23ba3498ae..cd6f4c45fa 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -54,7 +54,8 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, int ret; p = &(pnc->rpf.rpf_addr); - ret = zclient_send_rnh(zclient, command, p, false, pim->vrf->vrf_id); + ret = zclient_send_rnh(zclient, command, p, false, false, + pim->vrf->vrf_id); if (ret == ZCLIENT_SEND_FAILURE) zlog_warn("sendmsg_nexthop: zclient_send_message() failed"); @@ -109,22 +110,11 @@ static struct pim_nexthop_cache *pim_nexthop_cache_add(struct pim_instance *pim, return pnc; } -/* - * pim_find_or_track_nexthop - * - * This API is used to Register an address with Zebra - * - * 1 -> Success - * 0 -> Failure - */ -int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, - struct pim_upstream *up, struct rp_info *rp, - bool bsr_track_needed, - struct pim_nexthop_cache *out_pnc) +static struct pim_nexthop_cache *pim_nht_get(struct pim_instance *pim, + struct prefix *addr) { struct pim_nexthop_cache *pnc = NULL; struct pim_rpf rpf; - struct listnode *ch_node = NULL; struct zclient *zclient = NULL; zclient = pim_zebra_zclient_get(); @@ -144,6 +134,23 @@ int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, __func__, addr, pim->vrf->name); } + return pnc; +} + +/* TBD: this does several distinct things and should probably be split up. + * (checking state vs. returning pnc vs. adding upstream vs. adding rp) + */ +int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, + struct pim_upstream *up, struct rp_info *rp, + struct pim_nexthop_cache *out_pnc) +{ + struct pim_nexthop_cache *pnc; + struct listnode *ch_node = NULL; + + pnc = pim_nht_get(pim, addr); + + assertf(up || rp, "addr=%pFX", addr); + if (rp != NULL) { ch_node = listnode_lookup(pnc->rp_list, rp); if (ch_node == NULL) @@ -153,9 +160,6 @@ int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, if (up != NULL) hash_get(pnc->upstream_hash, up, hash_alloc_intern); - if (bsr_track_needed) - pnc->bsr_tracking = true; - if (CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID)) { if (out_pnc) memcpy(out_pnc, pnc, sizeof(struct pim_nexthop_cache)); @@ -165,232 +169,226 @@ int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, return 0; } +void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr addr) +{ + struct pim_nexthop_cache *pnc; + struct prefix pfx; + + pfx.family = AF_INET; + pfx.prefixlen = IPV4_MAX_BITLEN; + pfx.u.prefix4 = addr; + + pnc = pim_nht_get(pim, &pfx); + + pnc->bsr_count++; +} + +static void pim_nht_drop_maybe(struct pim_instance *pim, + struct pim_nexthop_cache *pnc) +{ + if (PIM_DEBUG_PIM_NHT) + zlog_debug( + "%s: NHT %pFX(%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); + + if (pnc->rp_list->count == 0 && pnc->upstream_hash->count == 0 + && pnc->bsr_count == 0) { + struct zclient *zclient = pim_zebra_zclient_get(); + + pim_sendmsg_zebra_rnh(pim, zclient, pnc, + ZEBRA_NEXTHOP_UNREGISTER); + + list_delete(&pnc->rp_list); + hash_free(pnc->upstream_hash); + + hash_release(pim->rpf_hash, pnc); + if (pnc->nexthop) + nexthops_free(pnc->nexthop); + XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc); + } +} + void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, - struct pim_upstream *up, struct rp_info *rp, - bool del_bsr_tracking) + struct pim_upstream *up, struct rp_info *rp) { struct pim_nexthop_cache *pnc = NULL; struct pim_nexthop_cache lookup; - struct zclient *zclient = NULL; struct pim_upstream *upstream = NULL; - zclient = pim_zebra_zclient_get(); - /* Remove from RPF hash if it is the last entry */ lookup.rpf.rpf_addr = *addr; pnc = hash_lookup(pim->rpf_hash, &lookup); - if (pnc) { - if (rp) { - /* Release the (*, G)upstream from pnc->upstream_hash, - * whose Group belongs to the RP getting deleted - */ - frr_each (rb_pim_upstream, &pim->upstream_head, - upstream) { - struct prefix grp; - struct rp_info *trp_info; - - if (upstream->sg.src.s_addr != INADDR_ANY) - continue; - - grp.family = AF_INET; - grp.prefixlen = IPV4_MAX_BITLEN; - grp.u.prefix4 = upstream->sg.grp; - - trp_info = pim_rp_find_match_group(pim, &grp); - if (trp_info == rp) - hash_release(pnc->upstream_hash, - upstream); - } - listnode_delete(pnc->rp_list, rp); - } + if (!pnc) { + zlog_warn("attempting to delete nonexistent NHT entry %pFX", + addr); + return; + } - if (up) - hash_release(pnc->upstream_hash, up); + if (rp) { + /* Release the (*, G)upstream from pnc->upstream_hash, + * whose Group belongs to the RP getting deleted + */ + frr_each (rb_pim_upstream, &pim->upstream_head, upstream) { + struct prefix grp; + struct rp_info *trp_info; - if (del_bsr_tracking) - pnc->bsr_tracking = false; + if (upstream->sg.src.s_addr != INADDR_ANY) + continue; - if (PIM_DEBUG_PIM_NHT) - zlog_debug( - "%s: NHT %pFX(%s) rp_list count:%d upstream count:%ld", - __func__, addr, pim->vrf->name, - pnc->rp_list->count, pnc->upstream_hash->count); - - if (pnc->rp_list->count == 0 - && pnc->upstream_hash->count == 0 - && pnc->bsr_tracking == false) { - pim_sendmsg_zebra_rnh(pim, zclient, pnc, - ZEBRA_NEXTHOP_UNREGISTER); - - list_delete(&pnc->rp_list); - hash_free(pnc->upstream_hash); - - hash_release(pim->rpf_hash, pnc); - if (pnc->nexthop) - nexthops_free(pnc->nexthop); - XFREE(MTYPE_PIM_NEXTHOP_CACHE, pnc); + grp.family = AF_INET; + grp.prefixlen = IPV4_MAX_BITLEN; + grp.u.prefix4 = upstream->sg.grp; + + trp_info = pim_rp_find_match_group(pim, &grp); + if (trp_info == rp) + hash_release(pnc->upstream_hash, upstream); } + listnode_delete(pnc->rp_list, rp); } + + if (up) + hash_release(pnc->upstream_hash, up); + + pim_nht_drop_maybe(pim, pnc); } -/* Given a source address and a neighbor address, check if the neighbor is one - * of the next hop to reach the source. search from zebra route database - */ -bool pim_nexthop_match(struct pim_instance *pim, struct in_addr addr, - struct in_addr ip_src) +void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr addr) { - struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM]; - int i = 0; - ifindex_t first_ifindex = 0; - struct interface *ifp = NULL; - struct pim_neighbor *nbr = NULL; - int num_ifindex; + struct pim_nexthop_cache *pnc = NULL; + struct pim_nexthop_cache lookup; - if (addr.s_addr == INADDR_NONE) - return false; + lookup.rpf.rpf_addr.family = AF_INET; + lookup.rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN; + lookup.rpf.rpf_addr.u.prefix4 = addr; - memset(nexthop_tab, 0, - sizeof(struct pim_zlookup_nexthop) * MULTIPATH_NUM); - num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, MULTIPATH_NUM, - addr, PIM_NEXTHOP_LOOKUP_MAX); - if (num_ifindex < 1) { - char addr_str[INET_ADDRSTRLEN]; + pnc = hash_lookup(pim->rpf_hash, &lookup); - pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str)); - zlog_warn( - "%s %s: could not find nexthop ifindex for address %s", - __FILE__, __func__, addr_str); - return false; + if (!pnc) { + zlog_warn("attempting to delete nonexistent NHT BSR entry %pI4", + &addr); + return; } - while (i < num_ifindex) { - first_ifindex = nexthop_tab[i].ifindex; + assertf(pnc->bsr_count > 0, "addr=%pI4", &addr); + pnc->bsr_count--; - ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id); - if (!ifp) { - if (PIM_DEBUG_ZEBRA) { - char addr_str[INET_ADDRSTRLEN]; + pim_nht_drop_maybe(pim, pnc); +} - pim_inet4_dump("<addr?>", addr, addr_str, - sizeof(addr_str)); - zlog_debug( - "%s %s: could not find interface for ifindex %d (address %s)", - __FILE__, __func__, first_ifindex, - addr_str); - } - i++; - continue; - } +bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, + struct interface *src_ifp, struct in_addr src_ip) +{ + struct pim_nexthop_cache *pnc = NULL; + struct pim_nexthop_cache lookup; + struct pim_neighbor *nbr = NULL; + struct nexthop *nh; + struct interface *ifp; - if (!ifp->info) { - if (PIM_DEBUG_ZEBRA) { - char addr_str[INET_ADDRSTRLEN]; + lookup.rpf.rpf_addr.family = AF_INET; + lookup.rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN; + lookup.rpf.rpf_addr.u.prefix4 = bsr_addr; - pim_inet4_dump("<addr?>", addr, addr_str, - sizeof(addr_str)); - zlog_debug( - "%s: multicast not enabled on input interface %s (ifindex=%d, RPF for source %s)", - __func__, ifp->name, first_ifindex, - addr_str); - } - i++; - continue; - } + pnc = hash_lookup(pim->rpf_hash, &lookup); + if (!pnc || !CHECK_FLAG(pnc->flags, PIM_NEXTHOP_ANSWER_RECEIVED)) { + /* BSM from a new freshly registered BSR - do a synchronous + * zebra query since otherwise we'd drop the first packet, + * leading to additional delay in picking up BSM data + */ - if (!pim_if_connected_to_source(ifp, addr)) { - nbr = pim_neighbor_find( - ifp, nexthop_tab[i].nexthop_addr.u.prefix4); - if (PIM_DEBUG_PIM_TRACE_DETAIL) - zlog_debug("ifp name: %s, pim nbr: %p", - ifp->name, nbr); - if (!nbr && !if_is_loopback(ifp)) { - i++; + /* FIXME: this should really be moved into a generic NHT + * function that does "add and get immediate result" or maybe + * "check cache or get immediate result." But until that can + * be worked in, here's a copy of the code below :( + */ + struct pim_zlookup_nexthop nexthop_tab[MULTIPATH_NUM]; + ifindex_t i; + struct interface *ifp = NULL; + int num_ifindex; + + memset(nexthop_tab, 0, sizeof(nexthop_tab)); + num_ifindex = zclient_lookup_nexthop(pim, nexthop_tab, + MULTIPATH_NUM, bsr_addr, + PIM_NEXTHOP_LOOKUP_MAX); + + if (num_ifindex <= 0) + return false; + + for (i = 0; i < num_ifindex; i++) { + struct pim_zlookup_nexthop *znh = &nexthop_tab[i]; + + /* pim_zlookup_nexthop has no ->type */ + + /* 1:1 match code below with znh instead of nh */ + ifp = if_lookup_by_index(znh->ifindex, + pim->vrf->vrf_id); + + if (!ifp || !ifp->info) continue; - } - } - if (nexthop_tab[i].nexthop_addr.u.prefix4.s_addr - == ip_src.s_addr) - return true; + if (if_is_loopback(ifp) && if_is_loopback(src_ifp)) + return true; - i++; + nbr = pim_neighbor_find(ifp, + znh->nexthop_addr.u.prefix4); + if (!nbr) + continue; + + return znh->ifindex == src_ifp->ifindex + && znh->nexthop_addr.u.prefix4.s_addr + == src_ip.s_addr; + } + return false; } - return false; -} + if (!CHECK_FLAG(pnc->flags, PIM_NEXTHOP_VALID)) + return false; -/* Given a source address and a neighbor address, check if the neighbor is one - * of the next hop to reach the source. search from pim next hop cache - */ -bool pim_nexthop_match_nht_cache(struct pim_instance *pim, struct in_addr addr, - struct in_addr ip_src) -{ - struct pim_rpf rpf; - ifindex_t first_ifindex; - struct interface *ifp = NULL; - uint8_t nh_iter = 0; - struct pim_neighbor *nbr = NULL; - struct nexthop *nh_node = NULL; - struct pim_nexthop_cache *pnc = NULL; + /* if we accept BSMs from more than one ECMP nexthop, this will cause + * BSM message "multiplication" for each ECMP hop. i.e. if you have + * 4-way ECMP and 4 hops you end up with 256 copies of each BSM + * message. + * + * so... only accept the first (IPv4) valid nexthop as source. + */ - memset(&rpf, 0, sizeof(struct pim_rpf)); - rpf.rpf_addr.family = AF_INET; - rpf.rpf_addr.prefixlen = IPV4_MAX_BITLEN; - rpf.rpf_addr.u.prefix4 = addr; + for (nh = pnc->nexthop; nh; nh = nh->next) { + struct in_addr nhaddr; - pnc = pim_nexthop_cache_find(pim, &rpf); - if (!pnc || !pnc->nexthop_num) - return false; + switch (nh->type) { + case NEXTHOP_TYPE_IPV4: + if (nh->ifindex == IFINDEX_INTERNAL) + continue; - for (nh_node = pnc->nexthop; nh_node; nh_node = nh_node->next) { - first_ifindex = nh_node->ifindex; - ifp = if_lookup_by_index(first_ifindex, pim->vrf->vrf_id); - if (!ifp) { - if (PIM_DEBUG_PIM_NHT) { - char addr_str[INET_ADDRSTRLEN]; + /* fallthru */ + case NEXTHOP_TYPE_IPV4_IFINDEX: + nhaddr = nh->gate.ipv4; + break; - pim_inet4_dump("<addr?>", addr, addr_str, - sizeof(addr_str)); - zlog_debug( - "%s %s: could not find interface for ifindex %d (address %s(%s))", - __FILE__, __func__, first_ifindex, - addr_str, pim->vrf->name); - } - nh_iter++; - continue; - } - if (!ifp->info) { - if (PIM_DEBUG_PIM_NHT) { - char addr_str[INET_ADDRSTRLEN]; + case NEXTHOP_TYPE_IFINDEX: + nhaddr = bsr_addr; + break; - pim_inet4_dump("<addr?>", addr, addr_str, - sizeof(addr_str)); - zlog_debug( - "%s: multicast not enabled on input interface %s(%s) (ifindex=%d, RPF for source %s)", - __func__, ifp->name, pim->vrf->name, - first_ifindex, addr_str); - } - nh_iter++; + default: continue; } - if (!pim_if_connected_to_source(ifp, addr)) { - nbr = pim_neighbor_find(ifp, nh_node->gate.ipv4); - if (!nbr && !if_is_loopback(ifp)) { - if (PIM_DEBUG_PIM_NHT) - zlog_debug( - "%s: pim nbr not found on input interface %s(%s)", - __func__, ifp->name, - pim->vrf->name); - nh_iter++; - continue; - } - } + ifp = if_lookup_by_index(nh->ifindex, pim->vrf->vrf_id); + if (!ifp || !ifp->info) + continue; - if (nh_node->gate.ipv4.s_addr == ip_src.s_addr) + if (if_is_loopback(ifp) && if_is_loopback(src_ifp)) return true; - } + /* MRIB (IGP) may be pointing at a router where PIM is down */ + nbr = pim_neighbor_find(ifp, nhaddr); + if (!nbr) + continue; + + return nh->ifindex == src_ifp->ifindex + && nhaddr.s_addr == src_ip.s_addr; + } return false; } diff --git a/pimd/pim_nht.h b/pimd/pim_nht.h index 12dbf167d1..568c2eb232 100644 --- a/pimd/pim_nht.h +++ b/pimd/pim_nht.h @@ -45,22 +45,20 @@ struct pim_nexthop_cache { struct list *rp_list; struct hash *upstream_hash; - /* Ideally this has to be list of scope zone. But for now we can just - * have as a bool variable to say bsr_tracking. - * Later this variable can be changed as a list of scope zones for - * tracking same bsr for multiple scope zones. + + /* bsr_count won't currently go above 1 as we only have global_scope, + * but if anyone adds scope support multiple scopes may NHT-track the + * same BSR */ - bool bsr_tracking; + uint32_t bsr_count; }; int pim_parse_nexthop_update(ZAPI_CALLBACK_ARGS); int pim_find_or_track_nexthop(struct pim_instance *pim, struct prefix *addr, struct pim_upstream *up, struct rp_info *rp, - bool bsr_track_needed, struct pim_nexthop_cache *out_pnc); void pim_delete_tracked_nexthop(struct pim_instance *pim, struct prefix *addr, - struct pim_upstream *up, struct rp_info *rp, - bool del_bsr_tracking); + struct pim_upstream *up, struct rp_info *rp); struct pim_nexthop_cache *pim_nexthop_cache_find(struct pim_instance *pim, struct pim_rpf *rpf); uint32_t pim_compute_ecmp_hash(struct prefix *src, struct prefix *grp); @@ -72,9 +70,12 @@ void pim_sendmsg_zebra_rnh(struct pim_instance *pim, struct zclient *zclient, int pim_ecmp_fib_lookup_if_vif_index(struct pim_instance *pim, struct prefix *src, struct prefix *grp); void pim_rp_nexthop_del(struct rp_info *rp_info); -bool pim_nexthop_match(struct pim_instance *pim, struct in_addr addr, - struct in_addr ip_src); -bool pim_nexthop_match_nht_cache(struct pim_instance *pim, struct in_addr addr, - struct in_addr ip_src); + +/* for RPF check on BSM message receipt */ +void pim_nht_bsr_add(struct pim_instance *pim, struct in_addr bsr_addr); +void pim_nht_bsr_del(struct pim_instance *pim, struct in_addr bsr_addr); +/* RPF(bsr_addr) == src_ip%src_ifp? */ +bool pim_nht_bsr_rpf_check(struct pim_instance *pim, struct in_addr bsr_addr, + struct interface *src_ifp, struct in_addr src_ip); #endif diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 3df7dc41ce..351b906d24 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -454,6 +454,21 @@ void pim_ifstat_reset(struct interface *ifp) pim_ifp->pim_ifstat_hello_sendfail = 0; pim_ifp->pim_ifstat_hello_recv = 0; pim_ifp->pim_ifstat_hello_recvfail = 0; + pim_ifp->pim_ifstat_bsm_rx = 0; + pim_ifp->pim_ifstat_bsm_tx = 0; + pim_ifp->pim_ifstat_join_recv = 0; + pim_ifp->pim_ifstat_join_send = 0; + pim_ifp->pim_ifstat_prune_recv = 0; + pim_ifp->pim_ifstat_prune_send = 0; + pim_ifp->pim_ifstat_reg_recv = 0; + pim_ifp->pim_ifstat_reg_send = 0; + pim_ifp->pim_ifstat_reg_stop_recv = 0; + pim_ifp->pim_ifstat_reg_stop_send = 0; + pim_ifp->pim_ifstat_assert_recv = 0; + pim_ifp->pim_ifstat_assert_send = 0; + pim_ifp->pim_ifstat_bsm_cfg_miss = 0; + pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0; + pim_ifp->pim_ifstat_bsm_invalid_sz = 0; } void pim_sock_reset(struct interface *ifp) @@ -692,7 +707,7 @@ int pim_hello_send(struct interface *ifp, uint16_t holdtime) { struct pim_interface *pim_ifp = ifp->info; - if (if_is_loopback_or_vrf(ifp)) + if (if_is_loopback(ifp)) return 0; if (hello_send(ifp, holdtime)) { @@ -706,6 +721,7 @@ int pim_hello_send(struct interface *ifp, uint16_t holdtime) } ++pim_ifp->pim_ifstat_hello_sent; + PIM_IF_FLAG_SET_HELLO_SENT(pim_ifp->flags); return 0; } @@ -794,7 +810,7 @@ void pim_hello_restart_triggered(struct interface *ifp) /* * No need to ever start loopback or vrf device hello's */ - if (if_is_loopback_or_vrf(ifp)) + if (if_is_loopback(ifp)) return; /* diff --git a/pimd/pim_register.c b/pimd/pim_register.c index 9d5b864ab0..cc0dace7c2 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -327,7 +327,7 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, #define PIM_MSG_REGISTER_BIT_RESERVED_LEN 4 ip_hdr = (struct ip *)(tlv_buf + PIM_MSG_REGISTER_BIT_RESERVED_LEN); - if (!pim_rp_check_is_my_ip_address(pim, dest_addr)) { + if (!if_address_is_local(&dest_addr, AF_INET, pim->vrf->vrf_id)) { if (PIM_DEBUG_PIM_REG) { char dest[INET_ADDRSTRLEN]; @@ -381,6 +381,16 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, pim_str_sg_dump(&sg), src_str, ifp->name, i_am_rp); } + if (pim_is_grp_ssm(pim_ifp->pim, sg.grp)) { + if (sg.src.s_addr == INADDR_ANY) { + zlog_warn( + "%s: Received Register message for Group(%pI4) is now in SSM, dropping the packet", + __func__, &sg.grp); + /* Drop Packet Silently */ + return 0; + } + } + if (i_am_rp && (dest_addr.s_addr == ((RP(pim, sg.grp))->rpf_addr.u.prefix4.s_addr))) { diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index f2a969e04a..d356aff9f1 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -38,7 +38,6 @@ #include "pim_str.h" #include "pim_iface.h" #include "pim_rp.h" -#include "pim_str.h" #include "pim_rpf.h" #include "pim_sock.h" #include "pim_memory.h" @@ -392,7 +391,7 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) zlog_debug( "%s: Deregister upstream %s addr %pFX with Zebra NHT", __func__, up->sg_str, &nht_p); - pim_delete_tracked_nexthop(pim, &nht_p, up, NULL, false); + pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); } /* Update the upstream address */ @@ -413,7 +412,6 @@ void pim_upstream_update(struct pim_instance *pim, struct pim_upstream *up) old_rpf.source_nexthop.interface)) pim_zebra_upstream_rpf_changed(pim, up, &old_rpf); - pim_zebra_update_all_interfaces(pim); } int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, @@ -431,6 +429,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, struct prefix nht_p; struct route_node *rn; struct pim_upstream *up; + bool upstream_updated = false; if (rp_addr.s_addr == INADDR_ANY || rp_addr.s_addr == INADDR_NONE) @@ -547,15 +546,19 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, grp.u.prefix4 = up->sg.grp; trp_info = pim_rp_find_match_group( pim, &grp); - if (trp_info == rp_all) + if (trp_info == rp_all) { pim_upstream_update(pim, up); + upstream_updated = true; + } } } + if (upstream_updated) + pim_zebra_update_all_interfaces(pim); pim_rp_check_interfaces(pim, rp_all); pim_rp_refresh_group_to_rp_mapping(pim); pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_all, - false, NULL); + NULL); if (!pim_ecmp_nexthop_lookup(pim, &rp_all->rp.source_nexthop, @@ -634,11 +637,16 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, grp.u.prefix4 = up->sg.grp; trp_info = pim_rp_find_match_group(pim, &grp); - if (trp_info == rp_info) + if (trp_info == rp_info) { pim_upstream_update(pim, up); + upstream_updated = true; + } } } + if (upstream_updated) + pim_zebra_update_all_interfaces(pim); + pim_rp_check_interfaces(pim, rp_info); pim_rp_refresh_group_to_rp_mapping(pim); @@ -649,7 +657,7 @@ int pim_rp_new(struct pim_instance *pim, struct in_addr rp_addr, if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ", __func__, &nht_p, &rp_info->group); - pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false, NULL); + pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL); if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p, &rp_info->group, 1)) return PIM_RP_NO_PATH; @@ -695,6 +703,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, struct bsgrp_node *bsgrp = NULL; struct bsm_rpinfo *bsrp = NULL; char rp_str[INET_ADDRSTRLEN]; + bool upstream_updated = false; if (!inet_ntop(AF_INET, &rp_addr, rp_str, sizeof(rp_str))) snprintf(rp_str, sizeof(rp_str), "<rp?>"); @@ -757,7 +766,7 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__, &nht_p); - pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info, false); + pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info); if (!str2prefix("224.0.0.0/4", &g_all)) return PIM_RP_BAD_ADDRESS; @@ -837,11 +846,16 @@ int pim_rp_del(struct pim_instance *pim, struct in_addr rp_addr, } /* RP found for the group grp */ - else + else { pim_upstream_update(pim, up); + upstream_updated = true; + } } } + if (upstream_updated) + pim_zebra_update_all_interfaces(pim); + XFREE(MTYPE_PIM_RP, rp_info); return PIM_SUCCESS; } @@ -854,6 +868,7 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, int result = 0; struct rp_info *rp_info = NULL; struct pim_upstream *up; + bool upstream_updated = false; rn = route_node_lookup(pim->rp_table, &group); if (!rn) { @@ -886,7 +901,7 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: Deregister RP addr %pFX with Zebra ", __func__, &nht_p); - pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info, false); + pim_delete_tracked_nexthop(pim, &nht_p, NULL, rp_info); } pim_rp_nexthop_del(rp_info); @@ -908,18 +923,23 @@ int pim_rp_change(struct pim_instance *pim, struct in_addr new_rp_addr, grp.u.prefix4 = up->sg.grp; trp_info = pim_rp_find_match_group(pim, &grp); - if (trp_info == rp_info) + if (trp_info == rp_info) { pim_upstream_update(pim, up); + upstream_updated = true; + } } } + if (upstream_updated) + pim_zebra_update_all_interfaces(pim); + /* Register new RP addr with Zebra NHT */ nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; if (PIM_DEBUG_PIM_NHT_RP) zlog_debug("%s: NHT Register RP addr %pFX grp %pFX with Zebra ", __func__, &nht_p, &rp_info->group); - pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false, NULL); + pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL); if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p, &rp_info->group, 1)) { route_unlock_node(rn); @@ -949,8 +969,7 @@ void pim_rp_setup(struct pim_instance *pim) nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; - pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false, - NULL); + pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL); if (!pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p, &rp_info->group, 1)) if (PIM_DEBUG_PIM_NHT_RP) @@ -1097,8 +1116,7 @@ struct pim_rpf *pim_rp_g(struct pim_instance *pim, struct in_addr group) zlog_debug( "%s: NHT Register RP addr %pFX grp %pFX with Zebra", __func__, &nht_p, &rp_info->group); - pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, false, - NULL); + pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, NULL); pim_rpf_set_refresh_time(pim); (void)pim_ecmp_nexthop_lookup(pim, &rp_info->rp.source_nexthop, &nht_p, &rp_info->group, 1); @@ -1178,15 +1196,6 @@ int pim_rp_config_write(struct pim_instance *pim, struct vty *vty, return count; } -bool pim_rp_check_is_my_ip_address(struct pim_instance *pim, - struct in_addr dest_addr) -{ - if (if_lookup_exact_address(&dest_addr, AF_INET, pim->vrf->vrf_id)) - return true; - - return false; -} - void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) { struct rp_info *rp_info; @@ -1239,12 +1248,9 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) json_rp_rows = json_object_new_array(); json_row = json_object_new_object(); - json_object_string_add( - json_row, "rpAddress", - inet_ntop(AF_INET, - &rp_info->rp.rpf_addr.u - .prefix4, - buf, sizeof(buf))); + json_object_string_addf( + json_row, "rpAddress", "%pI4", + &rp_info->rp.rpf_addr.u.prefix4); if (rp_info->rp.source_nexthop.interface) json_object_string_add( json_row, "outboundInterface", @@ -1266,10 +1272,9 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) "prefixList", rp_info->plist); else - json_object_string_add( - json_row, "group", - prefix2str(&rp_info->group, buf, - 48)); + json_object_string_addf( + json_row, "group", "%pFX", + &rp_info->group); json_object_string_add(json_row, "source", source); @@ -1314,9 +1319,7 @@ void pim_rp_show_information(struct pim_instance *pim, struct vty *vty, bool uj) buf, sizeof(buf)), json_rp_rows); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } } @@ -1337,7 +1340,7 @@ void pim_resolve_rp_nh(struct pim_instance *pim, struct pim_neighbor *nbr) nht_p.u.prefix4 = rp_info->rp.rpf_addr.u.prefix4; memset(&pnc, 0, sizeof(struct pim_nexthop_cache)); if (!pim_find_or_track_nexthop(pim, &nht_p, NULL, rp_info, - false, &pnc)) + &pnc)) continue; for (nh_node = pnc.nexthop; nh_node; nh_node = nh_node->next) { diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index b93f85e48c..aa89431d32 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -262,7 +262,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, if ((up->sg.src.s_addr == INADDR_ANY && I_am_RP(pim, up->sg.grp)) || PIM_UPSTREAM_FLAG_TEST_FHR(up->flags)) neigh_needed = false; - pim_find_or_track_nexthop(pim, &nht_p, up, NULL, false, NULL); + pim_find_or_track_nexthop(pim, &nht_p, up, NULL, NULL); if (!pim_ecmp_nexthop_lookup(pim, &rpf->source_nexthop, &src, &grp, neigh_needed)) { /* Route is Deleted in Zebra, reset the stored NH data */ diff --git a/pimd/pim_signals.c b/pimd/pim_signals.c index 38387d38c3..47220ccac7 100644 --- a/pimd/pim_signals.c +++ b/pimd/pim_signals.c @@ -57,7 +57,7 @@ static void pim_sigusr1(void) zlog_rotate(); } -struct quagga_signal_t pimd_signals[] = { +struct frr_signal_t pimd_signals[] = { { .signal = SIGHUP, .handler = &pim_sighup, diff --git a/pimd/pim_signals.h b/pimd/pim_signals.h index a82915691b..ebc5b8eb21 100644 --- a/pimd/pim_signals.h +++ b/pimd/pim_signals.h @@ -21,6 +21,6 @@ #define PIM_SIGNALS_H #include "sigevent.h" -extern struct quagga_signal_t pimd_signals[]; +extern struct frr_signal_t pimd_signals[]; #endif /* PIM_SIGNALS_H */ diff --git a/pimd/pim_static.c b/pimd/pim_static.c index 63a9a00659..be06a25bea 100644 --- a/pimd/pim_static.c +++ b/pimd/pim_static.c @@ -92,7 +92,7 @@ int pim_static_add(struct pim_instance *pim, struct interface *iif, return -4; } #endif - if (iif->vrf_id != oif->vrf_id) { + if (iif->vrf->vrf_id != oif->vrf->vrf_id) { return -3; } diff --git a/pimd/pim_time.c b/pimd/pim_time.c index c88ee7554b..93aaffb6a4 100644 --- a/pimd/pim_time.c +++ b/pimd/pim_time.c @@ -171,9 +171,7 @@ void pim_time_uptime_begin(char *buf, int buf_size, int64_t now, int64_t begin) long pim_time_timer_remain_msec(struct thread *t_timer) { - /* FIXME: Actually fetch msec resolution from thread */ - /* no timer thread running means timer has expired: return 0 */ - return t_timer ? 1000 * thread_timer_remain_second(t_timer) : 0; + return t_timer ? thread_timer_remain_msec(t_timer) : 0; } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index d21c7b4008..05da3cb7c2 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -271,7 +271,7 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, zlog_debug( "%s: Deregister upstream %s addr %pFX with Zebra NHT", __func__, up->sg_str, &nht_p); - pim_delete_tracked_nexthop(pim, &nht_p, up, NULL, false); + pim_delete_tracked_nexthop(pim, &nht_p, up, NULL); } XFREE(MTYPE_PIM_UPSTREAM, up); @@ -561,7 +561,7 @@ static void forward_off(struct pim_upstream *up) /* scan per-interface (S,G) state */ for (ALL_LIST_ELEMENTS(up->ifchannels, chnode, chnextnode, ch)) { - pim_forward_stop(ch, false); + pim_forward_stop(ch); } /* scan iface channel list */ } @@ -803,9 +803,8 @@ void pim_upstream_switch(struct pim_instance *pim, struct pim_upstream *up, if (pim_upstream_is_sg_rpt(up) && up->parent && !I_am_RP(pim, up->sg.grp)) send_xg_jp = true; - else - pim_jp_agg_single_upstream_send(&up->rpf, up, - 0 /* prune */); + + pim_jp_agg_single_upstream_send(&up->rpf, up, 0 /* prune */); if (send_xg_jp) { if (PIM_DEBUG_PIM_TRACE_DETAIL) @@ -1720,8 +1719,6 @@ const char *pim_reg_state2str(enum pim_reg_state reg_state, char *state_str, case PIM_REG_PRUNE: strlcpy(state_str, "RegPrune", state_str_len); break; - default: - strlcpy(state_str, "RegUnknown", state_str_len); } return state_str; } @@ -1785,7 +1782,7 @@ static int pim_upstream_register_stop_timer(struct thread *t) } pim_null_register_send(up); break; - default: + case PIM_REG_NOINFO: break; } @@ -1865,6 +1862,8 @@ int pim_upstream_inherited_olist_decide(struct pim_instance *pim, flag = PIM_OIF_FLAG_PROTO_IGMP; if (PIM_IF_FLAG_TEST_PROTO_PIM(ch->flags)) flag |= PIM_OIF_FLAG_PROTO_PIM; + if (starch) + flag |= PIM_OIF_FLAG_PROTO_STAR; } pim_channel_add_oif(up->channel_oil, ifp, flag, diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index e4dec9ee8e..5c6d32714f 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -404,7 +404,7 @@ int pim_interface_config_write(struct vty *vty) /* IF ip igmp join */ if (pim_ifp->igmp_join_list) { struct listnode *node; - struct igmp_join *ij; + struct gm_join *ij; for (ALL_LIST_ELEMENTS_RO( pim_ifp->igmp_join_list, node, ij)) { diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index 5d5ea1bfe6..edd41bc44d 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -357,8 +357,8 @@ static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg *vxlan_sg) nht_p.family = AF_INET; nht_p.prefixlen = IPV4_MAX_BITLEN; nht_p.u.prefix4 = up->upstream_addr; - pim_delete_tracked_nexthop(vxlan_sg->pim, - &nht_p, up, NULL, false); + pim_delete_tracked_nexthop(vxlan_sg->pim, &nht_p, up, + NULL); } /* We are acting FHR; clear out use_rpt setting if any */ pim_upstream_update_use_rpt(up, false /*update_mroute*/); @@ -390,9 +390,25 @@ static void pim_vxlan_orig_mr_up_add(struct pim_vxlan_sg *vxlan_sg) pim_upstream_keep_alive_timer_start(up, vxlan_sg->pim->keep_alive_time); /* register the source with the RP */ - if (up->reg_state == PIM_REG_NOINFO) { + switch (up->reg_state) { + + case PIM_REG_NOINFO: pim_register_join(up); pim_null_register_send(up); + break; + + case PIM_REG_JOIN: + /* if the pim upstream entry is already in reg-join state + * send null_register right away and add to the register + * worklist + */ + pim_null_register_send(up); + pim_vxlan_update_sg_reg_state(pim, up, true); + break; + + case PIM_REG_JOIN_PENDING: + case PIM_REG_PRUNE: + break; } /* update the inherited OIL */ @@ -1079,7 +1095,7 @@ void pim_vxlan_add_vif(struct interface *ifp) if (pim->vrf->vrf_id != VRF_DEFAULT) return; - if (if_is_loopback_or_vrf(ifp)) + if (if_is_loopback(ifp)) pim_vxlan_set_default_iif(pim, ifp); if (vxlan_mlag.flags & PIM_VXLAN_MLAGF_ENABLED && diff --git a/pimd/pim_vxlan.h b/pimd/pim_vxlan.h index ce9054cd26..d17de8e3d0 100644 --- a/pimd/pim_vxlan.h +++ b/pimd/pim_vxlan.h @@ -116,7 +116,7 @@ static inline bool pim_vxlan_is_local_sip(struct pim_upstream *up) { return (up->sg.src.s_addr != INADDR_ANY) && up->rpf.source_nexthop.interface && - if_is_loopback_or_vrf(up->rpf.source_nexthop.interface); + if_is_loopback(up->rpf.source_nexthop.interface); } static inline bool pim_vxlan_is_term_dev_cfg(struct pim_instance *pim, diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index aa041df857..5708c35751 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -164,7 +164,7 @@ static int pim_zebra_if_address_add(ZAPI_CALLBACK_ARGS) } if (if_is_loopback(c->ifp)) { - struct vrf *vrf = vrf_lookup_by_id(VRF_DEFAULT); + struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct interface *ifp; FOR_ALL_INTERFACES (vrf, ifp) { @@ -439,23 +439,29 @@ static void pim_zebra_capabilities(struct zclient_capabilities *cap) router->mlag_role = cap->role; } +static zclient_handler *const pim_handlers[] = { + [ZEBRA_ROUTER_ID_UPDATE] = pim_router_id_update_zebra, + [ZEBRA_INTERFACE_ADDRESS_ADD] = pim_zebra_if_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = pim_zebra_if_address_del, + [ZEBRA_INTERFACE_VRF_UPDATE] = pim_zebra_interface_vrf_update, + [ZEBRA_NEXTHOP_UPDATE] = pim_parse_nexthop_update, + + [ZEBRA_VXLAN_SG_ADD] = pim_zebra_vxlan_sg_proc, + [ZEBRA_VXLAN_SG_DEL] = pim_zebra_vxlan_sg_proc, + + [ZEBRA_MLAG_PROCESS_UP] = pim_zebra_mlag_process_up, + [ZEBRA_MLAG_PROCESS_DOWN] = pim_zebra_mlag_process_down, + [ZEBRA_MLAG_FORWARD_MSG] = pim_zebra_mlag_handle_msg, +}; + void pim_zebra_init(void) { /* Socket for receiving updates from Zebra daemon */ - zclient = zclient_new(router->master, &zclient_options_default); + zclient = zclient_new(router->master, &zclient_options_default, + pim_handlers, array_size(pim_handlers)); zclient->zebra_capabilities = pim_zebra_capabilities; zclient->zebra_connected = pim_zebra_connected; - zclient->router_id_update = pim_router_id_update_zebra; - zclient->interface_address_add = pim_zebra_if_address_add; - zclient->interface_address_delete = pim_zebra_if_address_del; - zclient->interface_vrf_update = pim_zebra_interface_vrf_update; - zclient->nexthop_update = pim_parse_nexthop_update; - zclient->vxlan_sg_add = pim_zebra_vxlan_sg_proc; - zclient->vxlan_sg_del = pim_zebra_vxlan_sg_proc; - zclient->mlag_process_up = pim_zebra_mlag_process_up; - zclient->mlag_process_down = pim_zebra_mlag_process_down; - zclient->mlag_handle_msg = pim_zebra_mlag_handle_msg; zclient_init(zclient, ZEBRA_ROUTE_PIM, 0, &pimd_privs); if (PIM_DEBUG_PIM_TRACE) { @@ -466,9 +472,9 @@ void pim_zebra_init(void) } void igmp_anysource_forward_start(struct pim_instance *pim, - struct igmp_group *group) + struct gm_group *group) { - struct igmp_source *source; + struct gm_source *source; struct in_addr src_addr = {.s_addr = 0}; /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */ assert(group->group_filtermode_isexcl); @@ -483,9 +489,9 @@ void igmp_anysource_forward_start(struct pim_instance *pim, igmp_source_forward_start(pim, source); } -void igmp_anysource_forward_stop(struct igmp_group *group) +void igmp_anysource_forward_stop(struct gm_group *group) { - struct igmp_source *source; + struct gm_source *source; struct in_addr star = {.s_addr = 0}; source = igmp_find_source_by_addr(group, star); @@ -494,10 +500,10 @@ void igmp_anysource_forward_stop(struct igmp_group *group) } static void igmp_source_forward_reevaluate_one(struct pim_instance *pim, - struct igmp_source *source) + struct gm_source *source) { struct prefix_sg sg; - struct igmp_group *group = source->source_group; + struct gm_group *group = source->source_group; struct pim_ifchannel *ch; if ((source->source_addr.s_addr != INADDR_ANY) @@ -541,7 +547,8 @@ void igmp_source_forward_reevaluate_all(struct pim_instance *pim) FOR_ALL_INTERFACES (pim->vrf, ifp) { struct pim_interface *pim_ifp = ifp->info; struct listnode *grpnode; - struct igmp_group *grp; + struct gm_group *grp; + struct pim_ifchannel *ch, *ch_temp; if (!pim_ifp) continue; @@ -550,22 +557,30 @@ void igmp_source_forward_reevaluate_all(struct pim_instance *pim) for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, grp)) { struct listnode *srcnode; - struct igmp_source *src; + struct gm_source *src; /* scan group sources */ for (ALL_LIST_ELEMENTS_RO(grp->group_source_list, srcnode, src)) { igmp_source_forward_reevaluate_one(pim, src); - } /* scan group sources */ - } /* scan igmp groups */ - } /* scan interfaces */ + } /* scan group sources */ + } /* scan igmp groups */ + + RB_FOREACH_SAFE (ch, pim_ifchannel_rb, &pim_ifp->ifchannel_rb, + ch_temp) { + if (pim_is_grp_ssm(pim, ch->sg.grp)) { + if (ch->sg.src.s_addr == INADDR_ANY) + pim_ifchannel_delete(ch); + } + } + } /* scan interfaces */ } void igmp_source_forward_start(struct pim_instance *pim, - struct igmp_source *source) + struct gm_source *source) { struct pim_interface *pim_oif; - struct igmp_group *group; + struct gm_group *group; struct prefix_sg sg; int result; int input_iface_vif_index = 0; @@ -743,9 +758,9 @@ void igmp_source_forward_start(struct pim_instance *pim, igmp_source_forward_stop: stop fowarding, but keep the source igmp_source_delete: stop fowarding, and delete the source */ -void igmp_source_forward_stop(struct igmp_source *source) +void igmp_source_forward_stop(struct gm_source *source) { - struct igmp_group *group; + struct gm_group *group; struct prefix_sg sg; int result; @@ -830,14 +845,14 @@ void pim_forward_start(struct pim_ifchannel *ch) mask, __func__); } -void pim_forward_stop(struct pim_ifchannel *ch, bool install_it) +void pim_forward_stop(struct pim_ifchannel *ch) { struct pim_upstream *up = ch->upstream; if (PIM_DEBUG_PIM_TRACE) { - zlog_debug("%s: (S,G)=%s oif=%s install_it: %d installed: %d", + zlog_debug("%s: (S,G)=%s oif=%s installed: %d", __func__, ch->sg_str, ch->interface->name, - install_it, up->channel_oil->installed); + up->channel_oil->installed); } /* @@ -850,9 +865,6 @@ void pim_forward_stop(struct pim_ifchannel *ch, bool install_it) else pim_channel_del_oif(up->channel_oil, ch->interface, PIM_OIF_FLAG_PROTO_PIM, __func__); - - if (install_it && !up->channel_oil->installed) - pim_upstream_mroute_add(up->channel_oil, __func__); } void pim_zebra_zclient_update(struct vty *vty) diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index 0f216cf5c9..8656d7563d 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -33,16 +33,16 @@ void pim_scan_individual_oil(struct channel_oil *c_oil, int in_vif_index); void pim_scan_oil(struct pim_instance *pim_matcher); void igmp_anysource_forward_start(struct pim_instance *pim, - struct igmp_group *group); -void igmp_anysource_forward_stop(struct igmp_group *group); + struct gm_group *group); +void igmp_anysource_forward_stop(struct gm_group *group); void igmp_source_forward_start(struct pim_instance *pim, - struct igmp_source *source); -void igmp_source_forward_stop(struct igmp_source *source); + struct gm_source *source); +void igmp_source_forward_stop(struct gm_source *source); void igmp_source_forward_reevaluate_all(struct pim_instance *pim); void pim_forward_start(struct pim_ifchannel *ch); -void pim_forward_stop(struct pim_ifchannel *ch, bool install_it); +void pim_forward_stop(struct pim_ifchannel *ch); void sched_rpf_cache_refresh(struct pim_instance *pim); struct zclient *pim_zebra_zclient_get(void); diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index abf9577bd5..abf1119ac5 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -137,7 +137,7 @@ void zclient_lookup_new(void) struct zclient_options options = zclient_options_default; options.synchronous = true; - zlookup = zclient_new(router->master, &options); + zlookup = zclient_new(router->master, &options, NULL, 0); if (!zlookup) { flog_err(EC_LIB_ZAPI_SOCKET, "%s: zclient_new() failure", __func__); diff --git a/pimd/pimd.h b/pimd/pimd.h index 4cb860a6b7..675c0ebc6b 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -85,8 +85,6 @@ #define PIM_INADDR_IS_ANY(addr) (addr).s_addr == PIM_NET_INADDR_ANY #define PIM_INADDR_ISNOT_ANY(addr) ((addr).s_addr != PIM_NET_INADDR_ANY) /* struct in_addr addr */ -#define max(x,y) ((x) > (y) ? (x) : (y)) - #define PIM_MASK_PIM_EVENTS (1 << 0) #define PIM_MASK_PIM_EVENTS_DETAIL (1 << 1) #define PIM_MASK_PIM_PACKETS (1 << 2) diff --git a/pimd/subdir.am b/pimd/subdir.am index 9910642ffa..f8bc0ff081 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -3,7 +3,6 @@ # if PIMD -noinst_LIBRARIES += pimd/libpim.a sbin_PROGRAMS += pimd/pimd bin_PROGRAMS += pimd/mtracebis noinst_PROGRAMS += pimd/test_igmpv3_join @@ -13,7 +12,7 @@ man8 += $(MANBUILD)/frr-pimd.8 man8 += $(MANBUILD)/mtracebis.8 endif -pimd_libpim_a_SOURCES = \ +pimd_pimd_SOURCES = \ pimd/pim_assert.c \ pimd/pim_bfd.c \ pimd/pim_br.c \ @@ -33,6 +32,7 @@ pimd_libpim_a_SOURCES = \ pimd/pim_join.c \ pimd/pim_jp_agg.c \ pimd/pim_macro.c \ + pimd/pim_main.c \ pimd/pim_memory.c \ pimd/pim_mlag.c \ pimd/pim_mroute.c \ @@ -66,6 +66,9 @@ pimd_libpim_a_SOURCES = \ pimd/pim_vxlan.c \ pimd/pim_zpthread.c \ pimd/pimd.c \ + # end + +nodist_pimd_pimd_SOURCES = \ yang/frr-pim.yang.c \ yang/frr-pim-rp.yang.c \ yang/frr-igmp.yang.c \ @@ -131,14 +134,7 @@ clippy_scan += \ pimd/pim_cmd.c \ # end -nodist_pimd_pimd_SOURCES = \ - yang/frr-igmp.yang.c \ - yang/frr-pim.yang.c \ - yang/frr-pim-rp.yang.c \ - # end - -pimd_pimd_LDADD = pimd/libpim.a lib/libfrr.la $(LIBCAP) -pimd_pimd_SOURCES = pimd/pim_main.c +pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP) pimd_test_igmpv3_join_LDADD = lib/libfrr.la pimd_test_igmpv3_join_SOURCES = pimd/test_igmpv3_join.c diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in index 066c45f55c..7f8e89de16 100644 --- a/redhat/frr.spec.in +++ b/redhat/frr.spec.in @@ -199,6 +199,8 @@ Requires: initscripts BuildRequires: pam-devel %endif %if "%{initsystem}" == "systemd" +BuildRequires: systemd +BuildRequires: systemd-devel Requires(post): systemd Requires(preun): systemd Requires(postun): systemd @@ -394,6 +396,9 @@ routing state through standard SNMP MIBs. --disable-bgp-vnc \ %endif --enable-isisd \ +%if "%{initsystem}" == "systemd" + --enable-systemd \ +%endif --enable-rpki \ %if %{with_bfdd} --enable-bfdd \ @@ -559,8 +564,8 @@ zebra_spec_add_service fabricd 2618/tcp "Fabricd vty" /sbin/install-info %{_infodir}/frr.info.gz %{_infodir}/dir # Create dummy config file if they don't exist so basic functions can be used. -if [ ! -e %{configdir}/zebra.conf ]; then - # per daemon configs exist +if [ ! -e %{configdir}/frr.conf ] && [ ! -e %{configdir}/zebra.conf ]; then + # No frr.conf and per daemon configs exist mv %{configdir}/frr.conf.template %{configdir}/frr.conf %if 0%{?frr_user:1} chown %{frr_user}:%{frr_user} %{configdir}/frr.conf @@ -717,6 +722,7 @@ fi %files pythontools %{_sbindir}/generate_support_bundle.py %{_sbindir}/frr-reload.py +%{_sbindir}/frr_babeltrace.py %if 0%{?rhel} > 7 || 0%{?fedora} > 29 %{_sbindir}/__pycache__/* %else @@ -724,6 +730,8 @@ fi %{_sbindir}/generate_support_bundle.pyo %{_sbindir}/frr-reload.pyc %{_sbindir}/frr-reload.pyo +%{_sbindir}/frr_babeltrace.pyc +%{_sbindir}/frr_babeltrace.pyo %endif @@ -765,9 +773,428 @@ sed -i 's/ -M rpki//' %{_sysconfdir}/frr/daemons %changelog -* Fri Oct 30 2020 Martin Winter <mwinter@opensourcerouting.org> - %{version} -- Moved RPKI to subpackage -- Added SNMP subpackage +* Tue Nov 4 2021 Martin Winter <mwinter@opensourcerouting.org> - %{version} + +* Tue Nov 2 2021 Jafar Al-Gharaibeh <jafar@atcorp.com> - 8.1 +- FRR 8.1 brings a long list of enhancements and fixes with 1200 commits from +- 75 developers. Thanks to all contributers. +- New Features: +- Lua hooks are now feature complete, with one hook available for use (http://docs.frrouting.org/en/latest/scripting.html) +- Improvements to SRv6 (Segment Routing over IPv6) (http://docs.frrouting.org/en/latest/zebra.html#segment-routing-ipv6) +- Improvements to Prefix-SID (Type 5) +- EVPN route type-5 gateway IP overlay Index (http://docs.frrouting.org/en/latest/bgp.html#evpn-overlay-index-gateway-ip) +- OSPFv3 NSSA and NSSA totally stub areas (http://docs.frrouting.org/en/latest/ospf6d.html#ospf6-area) +- OSPFv3 ASBR summarization (http://docs.frrouting.org/en/latest/ospf6d.html#asbr-summarisation-support-in-ospfv3) +- OSPFv3 Graceful Restart (http://docs.frrouting.org/en/latest/ospf6d.html#graceful-restart) +- OSPFv2 Graceful Restart (restarting mode added, helper was already implemented) (http://docs.frrouting.org/en/latest/ospfd.html#graceful-restart) +- Behavior Changes +- Every node in running config now has an explicit "exit" tag +- Link bandwidth in BGP is now correctly encoded according to IEEE 754. To stay with old incorrect encoding use: +- `neighbor PEER disable-link-bw-encoding-ieee` +- Changelog +- alpine: + Fix path for daemons file install +- BGP: +- Add "json" option to "show bgp as-path-access-list" +- Add `disable-addpath-rx` knob +- Add an ability to set extcommunity to none in route-maps +- Add counter of displayed show bgp summary when filtering +- Add knob to config cond-adv scanner period +- Add route-map `match alias` command +- Add rpki source address configuration +- Add show bgp summary filter by neighbor or as +- Add terse display option on show bgp summary +- Allow for auto-completion of community alias's created +- Bgp knob to teardown session immediately when peer is unreachable +- Expand 'bgp default <afi>-<safi>' cmds +- Extend evpn next hop tracking to type-1 and type-4 routes +- Fix "no router bgp x vrf default" +- Flowspec redirect vrf uses vrf table instead of allocated table id +- Handle quick flaps of an evpn prefix properly +- Initial batch of evpn lttng tracepoints +- Limit processing to what is needed in rpki validation +- Modify vrf/view display in show bgp summary +- Set 4096 instead of 65535 as new max packet size for a new peer +- Set extended msg size only if we advertised and received capability +- Show bgp community alias in json community list output +- Show bgp prefixes by community alias +- Show max packet size per update-group +- Split soft reconfigure table task into several jobs to not block vtysh +- Store distance received from a redistribute statement +- Update route-type-1 legend to match output +- ISIS: +- Fix sending of lsp with null seqno +- lib: +- Add "json" option to "show ip[v6] access-list" +- Add "json" option to "show ip[v6] prefix-list" +- Add "json" option to "show route-map" +- Prevent grpc assert on missing yang node +- NHRP: +- Clear cache when shortcuts are cleared +- Fix corrupt address being shown for shortcuts with no cache entry +- Set prefix correctly in resolution request +- OSPF6: +- Add debug commands for lsa all and route all +- Add warning log for late hello packets +- Add write-multiplier configuration +- Don't update router-id if at least one adjacency is full +- Extend the "redistribute" command with more options +- Fix issue when displaying the redistribute command +- Fix logging of border router routes +- Json output for database dump show command +- Link state id in lsa database json output +- Send lsa update immediately when ospf instance is deleted +- OSPF: +- Fix crash when creating vlink in unknown vrf +- Gr conformance fix for hello packet dr election +- Print extra lsa information in some log messages +- Rfc conformance test case 25.23 issue fix +- Show ip ospf route json does not shown metric and tag +- Summary lsa is not originated when process is reset +- pathd: +- Handle pcinitiated configuration, main thread +- Handle pcinitiated messages, thread controller +- Handle srp_id correctly +- If pce ret no-path to pcreq don't retry pcreq nor delegate +- PBR: +- Add `match ip-protocol [tcp|udp]` +- Add ability to set/unset src and dest ports +- Nhg "add" edge case for last in table range +- Start inclusion of src and dst ports for pbrd +- PIM: +- Add tos/ttl check for igmp conformance +- Allow join prune intervals to be as small as 5 seconds +- Allow msdp group name 'default' +- Fix register suppress timer code +- Fix uaf/heap corruption in bsm code +- Fix command "no ip msdp mesh-group member" +- Igmp groups are not getting timeout +- Igmp memberships are not querier specific +- Igmp sockets need to be iface-bound too +- Prevent uninited usage of nexthop +- Support msdp global timers configuration +- vtysh +- Add cli timestamp '-t' flag +- Add error code if daemon is not running +- Fix searching commands in parent nodes +- yang: +- Add msdp timer configuration +- Fix bgp multicast prefix type +- Mark a couple of prefix-list/access-list leafs as mandatory +- Move multicast prefix type definition +- Replace an empty pattern with a zero-length restriction +- Rework pim msdp mesh group +- Simplify msdp peer handling +- zebra : +- Add "json" option to "show interface" +- Various improvment to dataplane interface +- Add message counts for `show zebra client` +- Add nhg id to show ip route json +- Add show command for ra interface lists +- Fix ipv4 routes with ipv6 link local next hops install in fpm +- Handle bridge mac address update in evpn contexts +- Move individual lines to table in `show zebra client` command +- Refresh vxlan evpn contexts, when bridge interface goes up +- Update zl3vni when bridge link refreshed in other namespaces + +* Wed Jul 21 2021 Martin Winter <mwinter@opensourcerouting.org> - 8.0 +- Major changes +- New daemon pathd for segment routing +- EVPN Multihoming is now fully supported +- OSPFv3 now supports VRFs +- TI-LFA has been implemented in IS-IS and OSPF +- Ability for Zebra to dump netlink messages in a human-friendly format +- LDP gained SNMP support +- libyang minimun version is now 2.0 +- BABEL: +- Add `distribute-list` commands +- Fix memory leak in connected route handling +- BGP: +- Add support for use of aliases with communities +- Add support of tcp-mss for neighbors +- Add support for EVPN Multihoming +- Add ability to show BGP routes from a particular table version +- Add support for for RFC 8050 (MRT add-path) +- Add SNMP support for MPLS VPN +- Add `show bgp summary wide` command to show more detailed output + on wide terminals +- Add ability for peer-groups to have `ttl-security hops` configured +- Add support for conditional Advertisement +- Add support for RFC 4271 Delay Open Timer +- Add a knob to not advertise until route is installed in fib +- Add BGP-wide configuration for graceful shutdown +- Add support for RFC 8654 extended messages +- Improve RPKI reporting as well as new show commands +- Improve handling of VRF route leaking +- Improve scaling behavior for dynamic neighbors +- Improve LL nexthop tracking to be interface based +- Improve route reachability handling with respect to blackhole routes +- Improve SNMP traps to RFC 4273 notifications +- Improve EVPN routes to use L3 NHG's where applicable +- Improvements to EVPN +- Improvements to update behavior +- Fix various issues with connection resolution +- Fix statistics commands in some situations +- Fix non-determistic locally-originated paths in bestpath selection +- Continue working on transitioning to YANG/Northbound configuration +- Various bug fixes and performance improvements +- EIGRP: +- Add `distribute-list` commands +- Ensure received AS number is the same as ours in all situations +- Properly validate TLV lengths in some situations +- IS-IS: +- Add ldb-sync functionality +- Add TI-LFA functionality +- Add support for Anycast-SID's +- Add support for classic LFA RFC 5286 +- Add `show isis fast-reroute summary` command +- Add support for Remote LFA RFC 7490 +- Fix Attach-bit processing in some scenarios +- Cleanup BFD integration +- Various bug fixes and performance improvements +- LDP: +- Add SNMP support +- Support for LDP IGP Synchronization +- Support for RLFA clients +- Various bug fixes and performance improvements +- LIBFRR: +- Various bugfixes and performance improvements +- NHRP: +- Add `nhrp multicast-nflog-group (1-65535)` command +- Add configuration options for vici socket path +- Add support for forwarding multicast packets +- Fix handling of MTU +- Fix handling of NAT extension +- Retry IPsec under some conditions +- OSPFv2: +- Add OSPF GR helper support +- Add JSON support for various commands +- Add `summary-address A.B.C.D/M ...` commands +- Add `area X nssa suppress-fa` command +- Add support for TI-LFA +- Add support for BFD profiles +- Add support for Traffic Engineering database +- Add support for usage of DMPVPN with OSPF +- Add `clear ip ospf neighbor` commands +- Add YANG support for route-maps +- Improvements to SNMP +- Fixes for type 5 and type 7 LSA handling +- Various bug fixes and performance improvements +- OSPFv3: +- Add support for VRFs +- Add JSON support to a bunch of commands +- Add ability to control maximum paths for routes +- Add `show ipv6 ospf6 vrfs` command +- Add support for BFD profiles +- Fix to not send hellos on loopbacks +- Cleanup area handling around interfaces +- YANG support for route-maps +- Various bug fixes and performance improvements +- OSPFCLIENT: +- Cleanup trust of user input +- PATHd: +- Add support of SR-TE policy management daemon +- Add optional support for PCEP to pathd +- Integrate PCEP-LIB into FRR +- PBR: +- Add `set installable` nhg command +- Improve interface up/down event handling +- PIM: +- Add YANG integration +- Add JSON support to various commands +- Add BFD profile support +- Fixes to IGMP conformance +- Fixes to behavior surrounding Prune and Prune-pending +- Various bug fixes and performance improvements +- RIPNG: +- Fix interface wakeup after shutdown +- SHARP: +- Add ability to use Nexthop Groups +- Add v4 redistribute watching +- Add TED support +- Various bug fixes +- STATIC: +- Fix nexthop handling in some situations +- Forbid blackhole and non-blackhole nexthops in a single route +- VRRP: +- printf formatting cleanups +- VTYSH: +- Add a `show history` command +- Add `show memory <daemon>` support +- Start deprecation cycle for `address-family evpn` +- Display version with --help +- Various bug fixes +- WATCHFRR: +- Fix some crashes +- ZEBRA: +- Add JSON support to various commands +- Add Human readable netlink dumps +- Add L2 NHG support +- Add support for LSPs to FPM dataplane +- Add ability for other protocol daemons to install nexthop groups into the kernel +- Add YANG support for route-maps +- Improve scale performance when handling a large number of VRF's +- Improve network namespace handling +- Improve asic-offload handling +- Improve FreeBSD interface and route handling +- Improve handling of neighbors in kernel dataplane plugin +- Improve label manager +- Improve route-map processing +- Improve debug-ability of routes and VRFs +- Improve FPM dataplane plugin +- Improve handling of reachability / nexthop tracking on shutdown interfaces +- Improve EVPN support +- Fix startup handling of `set src X` +- Various bug fixes and performance improvements + +* Wed Mar 3 2021 Martin Winter <mwinter@opensourcerouting.org> - 7.5.1 +- BABEL: +- Fix connected route leak on change +- BFD: +- Session lookup was sometimes wrong +- Memory leak and handling cleanups +- In some situations handle vrf appropriately when receiving packets +- BGP: +- Peer Group Inheritance Fixes +- Dissallow attempt to peer peers reachable via blackholes +- Send BMP down message when reachability fails +- Cleanup handling of aggregator data when the AGG AS is 0 +- Handle `neighbor <peer-group allowas-in` config changes properly +- Properly parse community and lcommunity values in some circumstances +- Allow peer-groups to configure `ttl-security hops` +- Prevent v6 routes with v4 nexthops from being installed +- Allow `default-originate` to be cleared from a peer group +- Fix evpn route-map vni filter at origin +- local routes were using non-default distance +- Properly track if the nexthop was updated in some circumstances +- Cleanup `show running` when running bgp with `-e X` values +- Various Memory leaks in show commands +- Properly withdraw exported routes when deleting a VRF +- Avoid resetting ebgp-multihop if peer setting is the same as peer-group +- Properly encode flowspec rules to zebra in some rare circumstances +- Generate statistics for routes in bgp when we have exactly 1 route +- Properly apply route-map for the default-originate command +- EIGRP: +- Properly set MTU for eigrp packets sent +- Various memory leaks and using uninited data fixes +- ISIS: +- When last area address is removed, resign if we were the DR +- Various memory leaks and using uninited data fixes +- LDP: +- Various memory leaks and using uninited data fixes +- NHRP: +- Use onlink routes when prefix == nh +- Shortcut routes are installed with proper nexthop +- OSPF: +- Prevent duplicate packet read in multiple vrf situation +- Fix area removal at interface level +- Restore Point to MultiPoint interface types +- Correctly handle MTU change on startup +- Multi Instance initialization sometimes was not successful +- NSSA translate-always was not working properly +- OSPFv3: +- Don't send hellos on loopback interfaces +- Handle ECMP better when a sub-path is removed +- Memory leak and handling fixes +- Fix Link LSA not updating when router priority is modified +- Some output from show commands was wrong +- Intra area remote connected prefixes sometimes not installed +- PBR: +- Various memory leaks and using uninited data fixes +- PIM: +- SGRpt prune received during prune didn't override holdtime +- Various memory leaks and using uninited data fixes +- STATIC: +- Fix VRF and usage on startup in some instances +- Tableid was being mishandled in some cases +- VTYSH: +- Disable bracketed paste in readline. +- WATCHFRR: +- Various memory leaks and using uninited data fixes +- ZEBRA: +- Always install blackhole routes using kernel routes instead of nexthops +- Various memory leaks and using uninited data fixes +- Dissallow resolution to duplicate nexthops that created infinite nexthops +- Apply the route-map delay-timer globally +- Some routes were stuck in Queued state when using the FPM +- Better handle vrf creation when using namespaces +- Set NUD_NOARP on sticky mac entries in addtion to NTF_STICKY +- Allow `set src X` to work on startup +- FRR Library: +- Fix a variety of memory leaks +- Fix VRF Creation in some instances +- RPKI context editing was not properly handled in reload situations +- routemap code was not properly handling modification of CLI in some instances +- SNAPCRAFT: +- Update to using rtrlib 0.7.0 +- Fix passthrough path for Libyang 1.x +- ALPINE: +- Remove old docker deps + +* Mon Nov 2 2020 Donald Sharp <sharpd@nvidia.com> - 7.5 +- BFD +- Profile support +- Minimum ttl support +- BGP +- rpki VRF support +- GR fixes +- Add wide option to display of routes +- Add `maximum-prefix <num> force` +- Add `bestpath-routes` to neighbor command +- Add `bgp shutdown message MSG...` command +- Add v6 Flowspec support +- Add `neighbor <neigh> shutdown rtt` command +- Allow update-delay to be applied globaly +- EVPN +- Beginning of MultiHoming Support +- ISIS +- Segment Routing Support +- VRF Support +- Guard against adj timer display overflow +- Add support for Anycast-SIDs +- Add support for Topology Independent LFA (TI-LFA) +- Add `lsp-gen-interval 2` to isis configuration +- OSPF +- Segment Routing support for ECMP +- Various LSA fixes +- Prevent crash if transferring config amongst instances +- PBR +- Adding json support to commands +- DSCP/ECN based PBR Matching +- PIM +- Add more json support to commands +- Fix missing mesh-group commands +- MSDP SA forwarding +- Clear (s,g,rpt) ifchannel on (*, G) prune received +- Fix igmp querier election and IP address mapping +- Crash fix when RP is removed +- STATIC +- Northbound Support +- YANG +- Filter and route-map Support +- OSPF model definition +- BGP model definition +- VTYSH +- Speed up output across daemons +- Fix build-time errors for some --enable flags +- Speed up output of configuration across daemons +- ZEBRA +- nexthop group support for FPM +- northbound support for rib model +- Backup nexthop support +- netlink batching support +- Allow upper level protocols to request ARP +- Add json output for zebra ES, ES-EVI and access vlan dumps +- +- Upgrade to using libyang1.0.184 +- +- RPM +- Moved RPKI to subpackage +- Added SNMP subpackage +- +- As always there are too many bugfixes to list individually. This release +- compromises just over 1k of commits by the community, with contributors from +- 70 people. * Tue Jun 30 2020 Martin Winter <mwinter@opensourcerouting.org> - 7.4 - BGPd diff --git a/ripd/rip_cli.c b/ripd/rip_cli.c index 8a3ce24f5e..58c28e54c0 100644 --- a/ripd/rip_cli.c +++ b/ripd/rip_cli.c @@ -83,7 +83,7 @@ DEFPY_YANG (no_router_rip, return nb_cli_apply_changes_clear_pending(vty, NULL); } -void cli_show_router_rip(struct vty *vty, struct lyd_node *dnode, +void cli_show_router_rip(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrf_name; @@ -112,7 +112,7 @@ DEFPY_YANG (rip_allow_ecmp, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_allow_ecmp(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_allow_ecmp(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -138,7 +138,7 @@ DEFPY_YANG (rip_default_information_originate, } void cli_show_rip_default_information_originate(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -174,7 +174,7 @@ DEFPY_YANG (no_rip_default_metric, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_default_metric(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_default_metric(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " default-metric %s\n", @@ -208,7 +208,7 @@ DEFPY_YANG (no_rip_distance, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_distance(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_distance(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (yang_dnode_is_default(dnode, NULL)) @@ -243,7 +243,7 @@ DEFPY_YANG (rip_distance_source, prefix_str); } -void cli_show_rip_distance_source(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_distance_source(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " distance %s %s", @@ -271,7 +271,7 @@ DEFPY_YANG (rip_neighbor, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_neighbor(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_neighbor(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " neighbor %s\n", yang_dnode_get_string(dnode, NULL)); @@ -293,7 +293,7 @@ DEFPY_YANG (rip_network_prefix, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_network_prefix(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_network_prefix(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " network %s\n", yang_dnode_get_string(dnode, NULL)); @@ -315,7 +315,8 @@ DEFPY_YANG (rip_network_if, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_network_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_network_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " network %s\n", yang_dnode_get_string(dnode, NULL)); @@ -326,7 +327,7 @@ void cli_show_rip_network_interface(struct vty *vty, struct lyd_node *dnode, */ DEFPY_YANG (rip_offset_list, rip_offset_list_cmd, - "[no] offset-list WORD$acl <in|out>$direction (0-16)$metric [IFNAME]", + "[no] offset-list ACCESSLIST4_NAME$acl <in|out>$direction (0-16)$metric [IFNAME]", NO_STR "Modify RIP metric\n" "Access-list name\n" @@ -348,7 +349,7 @@ DEFPY_YANG (rip_offset_list, ifname ? ifname : "*", direction); } -void cli_show_rip_offset_list(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_offset_list(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *interface; @@ -380,7 +381,7 @@ DEFPY_YANG (rip_passive_default, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_passive_default(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_passive_default(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -417,14 +418,16 @@ DEFPY_YANG (rip_passive_interface, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_passive_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_passive_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " passive-interface %s\n", yang_dnode_get_string(dnode, NULL)); } -void cli_show_rip_non_passive_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_non_passive_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " no passive-interface %s\n", @@ -460,7 +463,7 @@ DEFPY_YANG (rip_redistribute, protocol); } -void cli_show_rip_redistribute(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_redistribute(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " redistribute %s", @@ -490,7 +493,7 @@ DEFPY_YANG (rip_route, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_route(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_route(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " route %s\n", yang_dnode_get_string(dnode, NULL)); @@ -535,7 +538,7 @@ DEFPY_YANG (no_rip_timers, return nb_cli_apply_changes(vty, "./timers"); } -void cli_show_rip_timers(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " timers basic %s %s %s\n", @@ -573,7 +576,7 @@ DEFPY_YANG (no_rip_version, return nb_cli_apply_changes(vty, NULL); } -void cli_show_rip_version(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_version(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { /* @@ -619,7 +622,8 @@ DEFPY_YANG (ip_rip_split_horizon, return nb_cli_apply_changes(vty, "./frr-ripd:rip"); } -void cli_show_ip_rip_split_horizon(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_rip_split_horizon(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { int value; @@ -655,7 +659,7 @@ DEFPY_YANG (ip_rip_v2_broadcast, return nb_cli_apply_changes(vty, "./frr-ripd:rip"); } -void cli_show_ip_rip_v2_broadcast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_rip_v2_broadcast(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -711,7 +715,8 @@ DEFPY_YANG (no_ip_rip_receive_version, return nb_cli_apply_changes(vty, "./frr-ripd:rip"); } -void cli_show_ip_rip_receive_version(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_rip_receive_version(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { switch (yang_dnode_get_enum(dnode, NULL)) { @@ -780,7 +785,7 @@ DEFPY_YANG (no_ip_rip_send_version, return nb_cli_apply_changes(vty, "./frr-ripd:rip"); } -void cli_show_ip_rip_send_version(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_rip_send_version(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { switch (yang_dnode_get_enum(dnode, NULL)) { @@ -860,7 +865,7 @@ DEFPY_YANG (no_ip_rip_authentication_mode, } void cli_show_ip_rip_authentication_scheme(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { switch (yang_dnode_get_enum(dnode, "./mode")) { @@ -933,7 +938,7 @@ DEFPY_YANG (no_ip_rip_authentication_string, } void cli_show_ip_rip_authentication_string(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " ip rip authentication string %s\n", @@ -982,7 +987,7 @@ DEFPY_YANG (no_ip_rip_authentication_key_chain, } void cli_show_ip_rip_authentication_key_chain(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " ip rip authentication key-chain %s\n", @@ -1021,7 +1026,7 @@ DEFPY_YANG (clear_ip_rip, DEFUN (rip_distribute_list, rip_distribute_list_cmd, - "distribute-list [prefix] WORD <in|out> [WORD]", + "distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", "Filter networks in routing updates\n" "Specify a prefix\n" "Access-list name\n" @@ -1041,7 +1046,7 @@ DEFUN (rip_distribute_list, DEFUN (rip_no_distribute_list, rip_no_distribute_list_cmd, - "no distribute-list [prefix] WORD <in|out> [WORD]", + "no distribute-list [prefix] ACCESSLIST4_NAME <in|out> [WORD]", NO_STR "Filter networks in routing updates\n" "Specify a prefix\n" diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index 2eb7bb6da1..8fd64f2874 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -317,14 +317,12 @@ static int rip_ifp_down(struct interface *ifp) rip_interface_sync(ifp); rip_if_down(ifp); - if (IS_RIP_DEBUG_ZEBRA) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_RIP_DEBUG_ZEBRA) zlog_debug( "interface %s vrf %s(%u) index %d flags %llx metric %d mtu %d is down", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); - } + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu); return 0; } @@ -332,14 +330,12 @@ static int rip_ifp_down(struct interface *ifp) /* Inteface link up message processing */ static int rip_ifp_up(struct interface *ifp) { - if (IS_RIP_DEBUG_ZEBRA) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_RIP_DEBUG_ZEBRA) zlog_debug( "interface %s vrf %s(%u) index %d flags %#llx metric %d mtu %d is up", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); - } + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu); rip_interface_sync(ifp); @@ -360,13 +356,12 @@ static int rip_ifp_create(struct interface *ifp) { rip_interface_sync(ifp); - if (IS_RIP_DEBUG_ZEBRA) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + if (IS_RIP_DEBUG_ZEBRA) zlog_debug( "interface add %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); - } + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu); /* Check if this interface is RIP enabled or not.*/ rip_enable_apply(ifp); @@ -387,8 +382,6 @@ static int rip_ifp_create(struct interface *ifp) static int rip_ifp_destroy(struct interface *ifp) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - rip_interface_sync(ifp); if (if_is_up(ifp)) { rip_if_down(ifp); @@ -397,8 +390,9 @@ static int rip_ifp_destroy(struct interface *ifp) if (IS_RIP_DEBUG_ZEBRA) zlog_debug( "interface delete %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu); return 0; } @@ -415,12 +409,11 @@ int rip_interface_vrf_update(ZAPI_CALLBACK_ARGS) return 0; if (IS_RIP_DEBUG_ZEBRA) { - struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id); zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)", - ifp->name, VRF_LOGNAME(vrf), vrf_id, - VRF_LOGNAME(nvrf), new_vrf_id); + ifp->name, ifp->vrf->name, vrf_id, VRF_LOGNAME(nvrf), + new_vrf_id); } if_update_to_new_vrf(ifp, new_vrf_id); @@ -1103,33 +1096,6 @@ void rip_passive_nondefault_clean(struct rip *rip) rip_passive_interface_apply_all(rip); } -/* Write rip configuration of each interface. */ -static int rip_interface_config_write(struct vty *vty) -{ - struct vrf *vrf; - int write = 0; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct interface *ifp; - - FOR_ALL_INTERFACES (vrf, ifp) { - struct lyd_node *dnode; - - dnode = yang_dnode_getf( - running_config->dnode, - "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifp->name, vrf->name); - if (dnode == NULL) - continue; - - write = 1; - nb_cli_show_dnode_cmds(vty, dnode, false); - } - } - - return write; -} - int rip_show_network_config(struct vty *vty, struct rip *rip) { unsigned int i; @@ -1157,16 +1123,11 @@ int rip_show_network_config(struct vty *vty, struct rip *rip) void rip_interface_sync(struct interface *ifp) { - struct vrf *vrf; - - vrf = vrf_lookup_by_id(ifp->vrf_id); - if (vrf) { - struct rip_interface *ri; + struct rip_interface *ri; - ri = ifp->info; - if (ri) - ri->rip = vrf->info; - } + ri = ifp->info; + if (ri) + ri->rip = ifp->vrf->info; } /* Called when interface structure allocated. */ @@ -1194,7 +1155,7 @@ void rip_if_init(void) hook_register_prio(if_del, 0, rip_interface_delete_hook); /* Install interface node. */ - if_cmd_init(rip_interface_config_write); + if_cmd_init_default(); if_zapi_callbacks(rip_ifp_create, rip_ifp_up, rip_ifp_down, rip_ifp_destroy); } diff --git a/ripd/rip_main.c b/ripd/rip_main.c index 7b9146b13a..6fb5ca95a9 100644 --- a/ripd/rip_main.c +++ b/ripd/rip_main.c @@ -94,7 +94,7 @@ static void sigusr1(void) zlog_rotate(); } -static struct quagga_signal_t ripd_signals[] = { +static struct frr_signal_t ripd_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/ripd/rip_nb.h b/ripd/rip_nb.h index 26bb3cb3bd..1e29f3b771 100644 --- a/ripd/rip_nb.h +++ b/ripd/rip_nb.h @@ -128,57 +128,62 @@ void ripd_instance_redistribute_apply_finish( void ripd_instance_timers_apply_finish(struct nb_cb_apply_finish_args *args); /* Optional 'cli_show' callbacks. */ -void cli_show_router_rip(struct vty *vty, struct lyd_node *dnode, +void cli_show_router_rip(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_allow_ecmp(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_allow_ecmp(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_rip_default_information_originate(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_default_metric(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_default_metric(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_distance(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_distance(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_distance_source(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_distance_source(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_neighbor(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_neighbor(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_network_prefix(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_network_prefix(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_network_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_network_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_offset_list(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_offset_list(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_passive_default(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_passive_default(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_passive_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_passive_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_non_passive_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_non_passive_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_redistribute(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_redistribute(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_route(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_route(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_timers(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_rip_version(struct vty *vty, struct lyd_node *dnode, +void cli_show_rip_version(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_rip_split_horizon(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_rip_split_horizon(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_rip_v2_broadcast(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_rip_v2_broadcast(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_rip_receive_version(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_rip_receive_version(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip_rip_send_version(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip_rip_send_version(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_ip_rip_authentication_scheme(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); void cli_show_ip_rip_authentication_string(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); void cli_show_ip_rip_authentication_key_chain(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); /* Notifications. */ diff --git a/ripd/rip_snmp.c b/ripd/rip_snmp.c index 824cbd8cf1..436dc4de0e 100644 --- a/ripd/rip_snmp.c +++ b/ripd/rip_snmp.c @@ -257,7 +257,7 @@ static struct interface *rip2IfLookup(struct variable *v, oid name[], oid2in_addr(name + v->namelen, sizeof(struct in_addr), addr); - return if_lookup_exact_address((void *)addr, AF_INET, + return if_lookup_address_local((void *)addr, AF_INET, VRF_DEFAULT); } else { len = *length - v->namelen; diff --git a/ripd/rip_zebra.c b/ripd/rip_zebra.c index 074370dc26..1f15668635 100644 --- a/ripd/rip_zebra.c +++ b/ripd/rip_zebra.c @@ -230,17 +230,21 @@ static void rip_zebra_connected(struct zclient *zclient) zclient_send_reg_requests(zclient, VRF_DEFAULT); } +zclient_handler *const rip_handlers[] = { + [ZEBRA_INTERFACE_ADDRESS_ADD] = rip_interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = rip_interface_address_delete, + [ZEBRA_INTERFACE_VRF_UPDATE] = rip_interface_vrf_update, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = rip_zebra_read_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = rip_zebra_read_route, +}; + void rip_zclient_init(struct thread_master *master) { /* Set default value to the zebra client structure. */ - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, rip_handlers, + array_size(rip_handlers)); zclient_init(zclient, ZEBRA_ROUTE_RIP, 0, &ripd_privs); zclient->zebra_connected = rip_zebra_connected; - zclient->interface_address_add = rip_interface_address_add; - zclient->interface_address_delete = rip_interface_address_delete; - zclient->interface_vrf_update = rip_interface_vrf_update; - zclient->redistribute_route_add = rip_zebra_read_route; - zclient->redistribute_route_del = rip_zebra_read_route; } void rip_zclient_stop(void) diff --git a/ripd/subdir.am b/ripd/subdir.am index b43e369ab2..b00c375888 100644 --- a/ripd/subdir.am +++ b/ripd/subdir.am @@ -3,7 +3,6 @@ # if RIPD -noinst_LIBRARIES += ripd/librip.a sbin_PROGRAMS += ripd/ripd vtysh_scan += \ ripd/rip_cli.c \ @@ -18,12 +17,13 @@ endif man8 += $(MANBUILD)/frr-ripd.8 endif -ripd_librip_a_SOURCES = \ +ripd_ripd_SOURCES = \ ripd/rip_cli.c \ ripd/rip_debug.c \ ripd/rip_errors.c \ ripd/rip_interface.c \ ripd/rip_offset.c \ + ripd/rip_main.c \ ripd/rip_nb.c \ ripd/rip_nb_config.c \ ripd/rip_nb_rpcs.c \ @@ -47,10 +47,7 @@ noinst_HEADERS += \ ripd/ripd.h \ # end -ripd_ripd_LDADD = ripd/librip.a lib/libfrr.la $(LIBCAP) -ripd_ripd_SOURCES = \ - ripd/rip_main.c \ - # end +ripd_ripd_LDADD = lib/libfrr.la $(LIBCAP) nodist_ripd_ripd_SOURCES = \ yang/frr-ripd.yang.c \ # end diff --git a/ripngd/ripng_cli.c b/ripngd/ripng_cli.c index 722c0c7dd6..5bf3103a78 100644 --- a/ripngd/ripng_cli.c +++ b/ripngd/ripng_cli.c @@ -83,8 +83,8 @@ DEFPY_YANG (no_router_ripng, return nb_cli_apply_changes_clear_pending(vty, NULL); } -void cli_show_router_ripng(struct vty *vty, struct lyd_node *dnode, - bool show_defaults) +void cli_show_router_ripng(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults) { const char *vrf_name; @@ -112,7 +112,7 @@ DEFPY_YANG (ripng_allow_ecmp, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ripng_allow_ecmp(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_allow_ecmp(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -138,7 +138,7 @@ DEFPY_YANG (ripng_default_information_originate, } void cli_show_ripng_default_information_originate(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults) { if (!yang_dnode_get_bool(dnode, NULL)) @@ -174,7 +174,8 @@ DEFPY_YANG (no_ripng_default_metric, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ripng_default_metric(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_default_metric(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " default-metric %s\n", @@ -197,7 +198,8 @@ DEFPY_YANG (ripng_network_prefix, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ripng_network_prefix(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_network_prefix(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " network %s\n", yang_dnode_get_string(dnode, NULL)); @@ -219,7 +221,8 @@ DEFPY_YANG (ripng_network_if, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ripng_network_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_network_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " network %s\n", yang_dnode_get_string(dnode, NULL)); @@ -230,7 +233,7 @@ void cli_show_ripng_network_interface(struct vty *vty, struct lyd_node *dnode, */ DEFPY_YANG (ripng_offset_list, ripng_offset_list_cmd, - "[no] offset-list WORD$acl <in|out>$direction (0-16)$metric [IFNAME]", + "[no] offset-list ACCESSLIST6_NAME$acl <in|out>$direction (0-16)$metric [IFNAME]", NO_STR "Modify RIPng metric\n" "Access-list name\n" @@ -252,7 +255,7 @@ DEFPY_YANG (ripng_offset_list, ifname ? ifname : "*", direction); } -void cli_show_ripng_offset_list(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_offset_list(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *interface; @@ -284,7 +287,8 @@ DEFPY_YANG (ripng_passive_interface, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ripng_passive_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_passive_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " passive-interface %s\n", @@ -320,7 +324,7 @@ DEFPY_YANG (ripng_redistribute, protocol); } -void cli_show_ripng_redistribute(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_redistribute(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " redistribute %s", @@ -350,7 +354,7 @@ DEFPY_YANG (ripng_route, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ripng_route(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_route(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " route %s\n", yang_dnode_get_string(dnode, NULL)); @@ -373,7 +377,8 @@ DEFPY_YANG (ripng_aggregate_address, return nb_cli_apply_changes(vty, NULL); } -void cli_show_ripng_aggregate_address(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_aggregate_address(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " aggregate-address %s\n", @@ -419,7 +424,7 @@ DEFPY_YANG (no_ripng_timers, return nb_cli_apply_changes(vty, "./timers"); } -void cli_show_ripng_timers(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { vty_out(vty, " timers basic %s %s %s\n", @@ -454,7 +459,8 @@ DEFPY_YANG (ipv6_ripng_split_horizon, return nb_cli_apply_changes(vty, "./frr-ripngd:ripng"); } -void cli_show_ipv6_ripng_split_horizon(struct vty *vty, struct lyd_node *dnode, +void cli_show_ipv6_ripng_split_horizon(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults) { int value; @@ -505,7 +511,7 @@ DEFPY_YANG (clear_ipv6_rip, DEFUN (ripng_ipv6_distribute_list, ripng_ipv6_distribute_list_cmd, - "ipv6 distribute-list [prefix] WORD <in|out> [WORD]", + "ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", "IPv6\n" "Filter networks in routing updates\n" "Specify a prefix\n" @@ -526,7 +532,7 @@ DEFUN (ripng_ipv6_distribute_list, DEFUN (ripng_no_ipv6_distribute_list, ripng_no_ipv6_distribute_list_cmd, - "no ipv6 distribute-list [prefix] WORD <in|out> [WORD]", + "no ipv6 distribute-list [prefix] ACCESSLIST6_NAME <in|out> [WORD]", NO_STR "IPv6\n" "Filter networks in routing updates\n" diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 7b5e7604d2..a6d379fda4 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -201,14 +201,12 @@ static int ripng_if_down(struct interface *ifp) /* Inteface link up message processing. */ static int ripng_ifp_up(struct interface *ifp) { - if (IS_RIPNG_DEBUG_ZEBRA) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( "interface up %s vrf %s(%u) index %d flags %llx metric %d mtu %d", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); - } + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu6); ripng_interface_sync(ifp); @@ -230,14 +228,12 @@ static int ripng_ifp_down(struct interface *ifp) ripng_interface_sync(ifp); ripng_if_down(ifp); - if (IS_RIPNG_DEBUG_ZEBRA) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( "interface down %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); - } + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu6); return 0; } @@ -247,14 +243,12 @@ static int ripng_ifp_create(struct interface *ifp) { ripng_interface_sync(ifp); - if (IS_RIPNG_DEBUG_ZEBRA) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( "RIPng interface add %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); - } + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu6); /* Check is this interface is RIP enabled or not.*/ ripng_enable_apply(ifp); @@ -270,8 +264,6 @@ static int ripng_ifp_create(struct interface *ifp) static int ripng_ifp_destroy(struct interface *ifp) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - ripng_interface_sync(ifp); if (if_is_up(ifp)) { ripng_if_down(ifp); @@ -280,8 +272,9 @@ static int ripng_ifp_destroy(struct interface *ifp) if (IS_RIPNG_DEBUG_ZEBRA) zlog_debug( "interface delete %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, - (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex, (unsigned long long)ifp->flags, + ifp->metric, ifp->mtu6); return 0; } @@ -298,12 +291,11 @@ int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS) return 0; if (IS_RIPNG_DEBUG_ZEBRA) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id); zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)", - ifp->name, VRF_LOGNAME(vrf), vrf_id, - VRF_LOGNAME(nvrf), new_vrf_id); + ifp->name, ifp->vrf->name, vrf_id, VRF_LOGNAME(nvrf), + new_vrf_id); } if_update_to_new_vrf(ifp, new_vrf_id); @@ -896,16 +888,11 @@ static struct ripng_interface *ri_new(void) void ripng_interface_sync(struct interface *ifp) { - struct vrf *vrf; - - vrf = vrf_lookup_by_id(ifp->vrf_id); - if (vrf) { - struct ripng_interface *ri; + struct ripng_interface *ri; - ri = ifp->info; - if (ri) - ri->ripng = vrf->info; - } + ri = ifp->info; + if (ri) + ri->ripng = ifp->vrf->info; } static int ripng_if_new_hook(struct interface *ifp) @@ -923,33 +910,6 @@ static int ripng_if_delete_hook(struct interface *ifp) return 0; } -/* Configuration write function for ripngd. */ -static int interface_config_write(struct vty *vty) -{ - struct vrf *vrf; - int write = 0; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct interface *ifp; - - FOR_ALL_INTERFACES (vrf, ifp) { - struct lyd_node *dnode; - - dnode = yang_dnode_getf( - running_config->dnode, - "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifp->name, vrf->name); - if (dnode == NULL) - continue; - - write = 1; - nb_cli_show_dnode_cmds(vty, dnode, false); - } - } - - return write; -} - /* Initialization of interface. */ void ripng_if_init(void) { @@ -958,7 +918,7 @@ void ripng_if_init(void) hook_register_prio(if_del, 0, ripng_if_delete_hook); /* Install interface node. */ - if_cmd_init(interface_config_write); + if_cmd_init_default(); if_zapi_callbacks(ripng_ifp_create, ripng_ifp_up, ripng_ifp_down, ripng_ifp_destroy); } diff --git a/ripngd/ripng_main.c b/ripngd/ripng_main.c index 34cd4ab0a7..bc169785a9 100644 --- a/ripngd/ripng_main.c +++ b/ripngd/ripng_main.c @@ -94,7 +94,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t ripng_signals[] = { +struct frr_signal_t ripng_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/ripngd/ripng_nb.h b/ripngd/ripng_nb.h index d6aecbf6b0..cf04242480 100644 --- a/ripngd/ripng_nb.h +++ b/ripngd/ripng_nb.h @@ -101,32 +101,38 @@ void ripngd_instance_redistribute_apply_finish( void ripngd_instance_timers_apply_finish(struct nb_cb_apply_finish_args *args); /* Optional 'cli_show' callbacks. */ -void cli_show_router_ripng(struct vty *vty, struct lyd_node *dnode, +void cli_show_router_ripng(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_allow_ecmp(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_allow_ecmp(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); void cli_show_ripng_default_information_originate(struct vty *vty, - struct lyd_node *dnode, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_default_metric(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_default_metric(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_network_prefix(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_network_prefix(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_network_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_network_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_offset_list(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_offset_list(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_passive_interface(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_passive_interface(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_redistribute(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_redistribute(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_route(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_route(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_aggregate_address(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_aggregate_address(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ripng_timers(struct vty *vty, struct lyd_node *dnode, +void cli_show_ripng_timers(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_ipv6_ripng_split_horizon(struct vty *vty, struct lyd_node *dnode, +void cli_show_ipv6_ripng_split_horizon(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); #endif /* _FRR_RIPNG_NB_H_ */ diff --git a/ripngd/ripng_nexthop.c b/ripngd/ripng_nexthop.c index 3e9fa90938..50972feffc 100644 --- a/ripngd/ripng_nexthop.c +++ b/ripngd/ripng_nexthop.c @@ -43,8 +43,6 @@ DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data"); #define DEBUG 1 -#define min(a, b) ((a) < (b) ? (a) : (b)) - struct ripng_rte_data { struct prefix_ipv6 *p; struct ripng_info *rinfo; @@ -151,7 +149,7 @@ void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, if (mtu < 0) mtu = IFMINMTU; - rtemax = (min(mtu, RIPNG_MAX_PACKET_SIZE) - IPV6_HDRLEN + rtemax = (MIN(mtu, RIPNG_MAX_PACKET_SIZE) - IPV6_HDRLEN - sizeof(struct udphdr) - sizeof(struct ripng_packet) + sizeof(struct rte)) / sizeof(struct rte); diff --git a/ripngd/ripng_zebra.c b/ripngd/ripng_zebra.c index baf7f00961..4108aa506e 100644 --- a/ripngd/ripng_zebra.c +++ b/ripngd/ripng_zebra.c @@ -234,19 +234,23 @@ static void ripng_zebra_connected(struct zclient *zclient) zclient_send_reg_requests(zclient, VRF_DEFAULT); } +static zclient_handler *const ripng_handlers[] = { + [ZEBRA_INTERFACE_ADDRESS_ADD] = ripng_interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = ripng_interface_address_delete, + [ZEBRA_INTERFACE_VRF_UPDATE] = ripng_interface_vrf_update, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = ripng_zebra_read_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = ripng_zebra_read_route, +}; + /* Initialize zebra structure and it's commands. */ void zebra_init(struct thread_master *master) { /* Allocate zebra structure. */ - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, ripng_handlers, + array_size(ripng_handlers)); zclient_init(zclient, ZEBRA_ROUTE_RIPNG, 0, &ripngd_privs); zclient->zebra_connected = ripng_zebra_connected; - zclient->interface_address_add = ripng_interface_address_add; - zclient->interface_address_delete = ripng_interface_address_delete; - zclient->interface_vrf_update = ripng_interface_vrf_update; - zclient->redistribute_route_add = ripng_zebra_read_route; - zclient->redistribute_route_del = ripng_zebra_read_route; } void ripng_zebra_stop(void) diff --git a/ripngd/subdir.am b/ripngd/subdir.am index 9d8d27d4cc..a4db3e5a6b 100644 --- a/ripngd/subdir.am +++ b/ripngd/subdir.am @@ -3,7 +3,6 @@ # if RIPNGD -noinst_LIBRARIES += ripngd/libripng.a sbin_PROGRAMS += ripngd/ripngd vtysh_scan += \ ripngd/ripng_cli.c \ @@ -14,12 +13,13 @@ vtysh_daemons += ripngd man8 += $(MANBUILD)/frr-ripngd.8 endif -ripngd_libripng_a_SOURCES = \ +ripngd_ripngd_SOURCES = \ ripngd/ripng_cli.c \ ripngd/ripng_debug.c \ ripngd/ripng_interface.c \ ripngd/ripng_nexthop.c \ ripngd/ripng_offset.c \ + ripngd/ripng_main.c \ ripngd/ripng_nb.c \ ripngd/ripng_nb_config.c \ ripngd/ripng_nb_rpcs.c \ @@ -43,10 +43,7 @@ noinst_HEADERS += \ ripngd/ripngd.h \ # end -ripngd_ripngd_LDADD = ripngd/libripng.a lib/libfrr.la $(LIBCAP) -ripngd_ripngd_SOURCES = \ - ripngd/ripng_main.c \ - # end +ripngd_ripngd_LDADD = lib/libfrr.la $(LIBCAP) nodist_ripngd_ripngd_SOURCES = \ yang/frr-ripngd.yang.c \ # end diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index a646c313e4..8494f479c4 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -94,7 +94,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t sharp_signals[] = { +struct frr_signal_t sharp_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/sharpd/sharp_vty.c b/sharpd/sharp_vty.c index b6581cd9e6..0a323f744e 100644 --- a/sharpd/sharp_vty.c +++ b/sharpd/sharp_vty.c @@ -1065,12 +1065,8 @@ DEFUN (show_sharp_ted, ls_show_ted(sg.ted, vty, json, verbose); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -1137,9 +1133,7 @@ DEFPY (show_sharp_segment_routing_srv6, } } - vty_out(vty, "%s\n", json_object_to_json_string_ext( - jo_locs, JSON_C_TO_STRING_PRETTY)); - json_object_free(jo_locs); + vty_json(vty, jo_locs); } else { for (ALL_LIST_ELEMENTS_RO(sg.srv6_locators, loc_node, loc)) { vty_out(vty, "Locator %s has %d prefix chunks\n", diff --git a/sharpd/sharp_zebra.c b/sharpd/sharp_zebra.c index 2575475dd2..8c9f0c2784 100644 --- a/sharpd/sharp_zebra.c +++ b/sharpd/sharp_zebra.c @@ -626,19 +626,12 @@ void sharp_zebra_nexthop_watch(struct prefix *p, vrf_id_t vrf_id, bool import, { int command; - if (!import) { - command = ZEBRA_NEXTHOP_REGISTER; + command = ZEBRA_NEXTHOP_REGISTER; - if (!watch) - command = ZEBRA_NEXTHOP_UNREGISTER; - } else { - command = ZEBRA_IMPORT_ROUTE_REGISTER; - - if (!watch) - command = ZEBRA_IMPORT_ROUTE_UNREGISTER; - } + if (!watch) + command = ZEBRA_NEXTHOP_UNREGISTER; - if (zclient_send_rnh(zclient, command, p, connected, vrf_id) + if (zclient_send_rnh(zclient, command, p, connected, false, vrf_id) == ZCLIENT_SEND_FAILURE) zlog_warn("%s: Failure to send nexthop to zebra", __func__); } @@ -727,6 +720,10 @@ void sharp_redistribute_vrf(struct vrf *vrf, int type) 0, vrf->vrf_id); } +static zclient_handler *const sharp_opaque_handlers[] = { + [ZEBRA_OPAQUE_MESSAGE] = sharp_opaque_handler, +}; + /* Add a zclient with a specified session id, for testing. */ int sharp_zclient_create(uint32_t session_id) { @@ -739,15 +736,14 @@ int sharp_zclient_create(uint32_t session_id) return -1; } - client = zclient_new(master, &zclient_options_default); + client = zclient_new(master, &zclient_options_default, + sharp_opaque_handlers, + array_size(sharp_opaque_handlers)); client->sock = -1; client->session_id = session_id; zclient_init(client, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); - /* Register handlers for messages we expect this session to see */ - client->opaque_msg_handler = sharp_opaque_handler; - /* Enqueue on the list of test clients */ add_zclient(client); @@ -935,7 +931,7 @@ int sharp_zebra_srv6_manager_release_locator_chunk(const char *locator_name) return srv6_manager_release_locator_chunk(zclient, locator_name); } -static void sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) +static int sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) { struct stream *s = NULL; struct srv6_locator_chunk s6c = {}; @@ -958,17 +954,31 @@ static void sharp_zebra_process_srv6_locator_chunk(ZAPI_CALLBACK_ARGS) for (ALL_LIST_ELEMENTS_RO(loc->chunks, chunk_node, c)) if (!prefix_cmp(c, &s6c.prefix)) - return; + return 0; chunk = prefix_ipv6_new(); *chunk = s6c.prefix; listnode_add(loc->chunks, chunk); - return; + return 0; } zlog_err("%s: can't get locator_chunk!!", __func__); + return 0; } +static zclient_handler *const sharp_handlers[] = { + [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, + [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner, + [ZEBRA_NEXTHOP_UPDATE] = sharp_nexthop_update, + [ZEBRA_NHG_NOTIFY_OWNER] = nhg_notify_owner, + [ZEBRA_REDISTRIBUTE_ROUTE_ADD] = sharp_redistribute_route, + [ZEBRA_REDISTRIBUTE_ROUTE_DEL] = sharp_redistribute_route, + [ZEBRA_OPAQUE_MESSAGE] = sharp_opaque_handler, + [ZEBRA_SRV6_MANAGER_GET_LOCATOR_CHUNK] = + sharp_zebra_process_srv6_locator_chunk, +}; + void sharp_zebra_init(void) { struct zclient_options opt = {.receive_notify = true}; @@ -976,20 +986,10 @@ void sharp_zebra_init(void) if_zapi_callbacks(sharp_ifp_create, sharp_ifp_up, sharp_ifp_down, sharp_ifp_destroy); - zclient = zclient_new(master, &opt); + zclient = zclient_new(master, &opt, sharp_handlers, + array_size(sharp_handlers)); zclient_init(zclient, ZEBRA_ROUTE_SHARP, 0, &sharp_privs); zclient->zebra_connected = zebra_connected; - zclient->interface_address_add = interface_address_add; - zclient->interface_address_delete = interface_address_delete; - zclient->route_notify_owner = route_notify_owner; - zclient->nexthop_update = sharp_nexthop_update; - zclient->import_check_update = sharp_nexthop_update; - zclient->nhg_notify_owner = nhg_notify_owner; zclient->zebra_buffer_write_ready = sharp_zclient_buffer_ready; - zclient->redistribute_route_add = sharp_redistribute_route; - zclient->redistribute_route_del = sharp_redistribute_route; - zclient->opaque_msg_handler = sharp_opaque_handler; - zclient->process_srv6_locator_chunk = - sharp_zebra_process_srv6_locator_chunk; } diff --git a/staticd/static_main.c b/staticd/static_main.c index f7a15462a0..6051b2df1c 100644 --- a/staticd/static_main.c +++ b/staticd/static_main.c @@ -91,7 +91,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t static_signals[] = { +struct frr_signal_t static_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/staticd/static_routes.c b/staticd/static_routes.c index 60f384e517..1d52dd30e2 100644 --- a/staticd/static_routes.c +++ b/staticd/static_routes.c @@ -199,14 +199,14 @@ bool static_add_nexthop_validate(const char *nh_vrf_name, switch (type) { case STATIC_IPV4_GATEWAY: case STATIC_IPV4_GATEWAY_IFNAME: - if (if_lookup_exact_address(&ipaddr->ipaddr_v4, AF_INET, - vrf->vrf_id)) + if (if_address_is_local(&ipaddr->ipaddr_v4, AF_INET, + vrf->vrf_id)) return false; break; case STATIC_IPV6_GATEWAY: case STATIC_IPV6_GATEWAY_IFNAME: - if (if_lookup_exact_address(&ipaddr->ipaddr_v6, AF_INET6, - vrf->vrf_id)) + if (if_address_is_local(&ipaddr->ipaddr_v6, AF_INET6, + vrf->vrf_id)) return false; break; default: @@ -432,13 +432,13 @@ static void static_ifindex_update_nh(struct interface *ifp, bool up, if (up) { if (strcmp(nh->ifname, ifp->name)) return; - if (nh->nh_vrf_id != ifp->vrf_id) + if (nh->nh_vrf_id != ifp->vrf->vrf_id) return; nh->ifindex = ifp->ifindex; } else { if (nh->ifindex != ifp->ifindex) return; - if (nh->nh_vrf_id != ifp->vrf_id) + if (nh->nh_vrf_id != ifp->vrf->vrf_id) return; nh->ifindex = IFINDEX_INTERNAL; } @@ -723,7 +723,7 @@ static void static_fixup_intf_nh(struct route_table *stable, continue; frr_each(static_path_list, &si->path_list, pn) { frr_each(static_nexthop_list, &pn->nexthop_list, nh) { - if (nh->nh_vrf_id != ifp->vrf_id) + if (nh->nh_vrf_id != ifp->vrf->vrf_id) continue; if (nh->ifindex != ifp->ifindex) @@ -750,7 +750,7 @@ void static_install_intf_nh(struct interface *ifp) struct static_vrf *svrf = vrf->info; /* Not needed if same vrf since happens naturally */ - if (vrf->vrf_id == ifp->vrf_id) + if (vrf->vrf_id == ifp->vrf->vrf_id) continue; /* Install any static routes configured for this interface. */ diff --git a/staticd/static_vrf.c b/staticd/static_vrf.c index 4bea3075c9..6ba0bf4544 100644 --- a/staticd/static_vrf.c +++ b/staticd/static_vrf.c @@ -123,17 +123,6 @@ struct route_table *static_vrf_static_table(afi_t afi, safi_t safi, return svrf->stable[afi][safi]; } -struct static_vrf *static_vrf_lookup_by_id(vrf_id_t vrf_id) -{ - struct vrf *vrf; - - vrf = vrf_lookup_by_id(vrf_id); - if (vrf) - return ((struct static_vrf *)vrf->info); - - return NULL; -} - struct static_vrf *static_vrf_lookup_by_name(const char *name) { struct vrf *vrf; diff --git a/staticd/static_vrf.h b/staticd/static_vrf.h index be311af8c4..885246bfaa 100644 --- a/staticd/static_vrf.h +++ b/staticd/static_vrf.h @@ -39,7 +39,6 @@ struct stable_info { #define GET_STABLE_VRF_ID(info) info->svrf->vrf->vrf_id struct static_vrf *static_vrf_lookup_by_name(const char *vrf_name); -struct static_vrf *static_vrf_lookup_by_id(vrf_id_t vrf_id); void static_vrf_init(void); diff --git a/staticd/static_vty.c b/staticd/static_vty.c index 751a262775..95d1386a67 100644 --- a/staticd/static_vty.c +++ b/staticd/static_vty.c @@ -1002,7 +1002,7 @@ DEFPY_YANG(ipv6_route_vrf, table_str, false, color_str); } -void static_cli_show(struct vty *vty, struct lyd_node *dnode, +void static_cli_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrf; @@ -1012,7 +1012,7 @@ void static_cli_show(struct vty *vty, struct lyd_node *dnode, vty_out(vty, "vrf %s\n", vrf); } -void static_cli_show_end(struct vty *vty, struct lyd_node *dnode) +void static_cli_show_end(struct vty *vty, const struct lyd_node *dnode) { const char *vrf; @@ -1154,7 +1154,7 @@ static void nexthop_cli_show(struct vty *vty, const struct lyd_node *route, vty_out(vty, "\n"); } -void static_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode, +void static_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list"); @@ -1164,7 +1164,7 @@ void static_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode, nexthop_cli_show(vty, route, NULL, path, dnode, show_defaults); } -void static_src_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode, +void static_src_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const struct lyd_node *path = yang_dnode_get_parent(dnode, "path-list"); @@ -1174,7 +1174,8 @@ void static_src_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode, nexthop_cli_show(vty, route, src, path, dnode, show_defaults); } -int static_nexthop_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +int static_nexthop_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { enum static_nh_type nh_type1, nh_type2; struct prefix prefix1, prefix2; @@ -1221,7 +1222,8 @@ int static_nexthop_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) yang_dnode_get_string(dnode2, "./vrf")); } -int static_route_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +int static_route_list_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { const char *afi_safi1, *afi_safi2; afi_t afi1, afi2; @@ -1246,7 +1248,8 @@ int static_route_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) return prefix_cmp(&prefix1, &prefix2); } -int static_src_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +int static_src_list_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { struct prefix prefix1, prefix2; @@ -1256,7 +1259,8 @@ int static_src_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) return prefix_cmp(&prefix1, &prefix2); } -int static_path_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2) +int static_path_list_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2) { uint32_t table_id1, table_id2; uint8_t distance1, distance2; diff --git a/staticd/static_vty.h b/staticd/static_vty.h index 8861afa468..84a359593f 100644 --- a/staticd/static_vty.h +++ b/staticd/static_vty.h @@ -23,17 +23,21 @@ extern "C" { #endif -void static_cli_show(struct vty *vty, struct lyd_node *dnode, +void static_cli_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void static_cli_show_end(struct vty *vty, struct lyd_node *dnode); -void static_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode, +void static_cli_show_end(struct vty *vty, const struct lyd_node *dnode); +void static_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void static_src_nexthop_cli_show(struct vty *vty, struct lyd_node *dnode, +void static_src_nexthop_cli_show(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -int static_nexthop_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); -int static_route_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); -int static_src_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); -int static_path_list_cli_cmp(struct lyd_node *dnode1, struct lyd_node *dnode2); +int static_nexthop_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2); +int static_route_list_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2); +int static_src_list_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2); +int static_path_list_cli_cmp(const struct lyd_node *dnode1, + const struct lyd_node *dnode2); void static_vty_init(void); diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 452b5c42a4..311aeda338 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -84,12 +84,6 @@ static int interface_address_delete(ZAPI_CALLBACK_ARGS) static int static_ifp_up(struct interface *ifp) { - if (if_is_vrf(ifp)) { - struct static_vrf *svrf = static_vrf_lookup_by_id(ifp->vrf_id); - - static_fixup_vrf_ids(svrf); - } - /* Install any static reliant on this interface coming up */ static_install_intf_nh(ifp); static_ifindex_update(ifp, true); @@ -162,14 +156,10 @@ static bool static_nexthop_is_local(vrf_id_t vrfid, struct prefix *addr, int family) { if (family == AF_INET) { - if (if_lookup_exact_address(&addr->u.prefix4, - AF_INET, - vrfid)) + if (if_address_is_local(&addr->u.prefix4, AF_INET, vrfid)) return true; } else if (family == AF_INET6) { - if (if_lookup_exact_address(&addr->u.prefix6, - AF_INET6, - vrfid)) + if (if_address_is_local(&addr->u.prefix6, AF_INET6, vrfid)) return true; } return false; @@ -332,7 +322,7 @@ void static_zebra_nht_register(struct static_nexthop *nh, bool reg) static_nht_hash_free(nhtd); } - if (zclient_send_rnh(zclient, cmd, &p, false, nh->nh_vrf_id) + if (zclient_send_rnh(zclient, cmd, &p, false, false, nh->nh_vrf_id) == ZCLIENT_SEND_FAILURE) zlog_warn("%s: Failure to send nexthop to zebra", __func__); } @@ -508,6 +498,13 @@ extern void static_zebra_route_add(struct static_path *pn, bool install) zclient, &api); } +static zclient_handler *const static_handlers[] = { + [ZEBRA_INTERFACE_ADDRESS_ADD] = interface_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = interface_address_delete, + [ZEBRA_ROUTE_NOTIFY_OWNER] = route_notify_owner, + [ZEBRA_NEXTHOP_UPDATE] = static_zebra_nexthop_update, +}; + void static_zebra_init(void) { struct zclient_options opt = { .receive_notify = true }; @@ -515,15 +512,12 @@ void static_zebra_init(void) if_zapi_callbacks(static_ifp_create, static_ifp_up, static_ifp_down, static_ifp_destroy); - zclient = zclient_new(master, &opt); + zclient = zclient_new(master, &opt, static_handlers, + array_size(static_handlers)); zclient_init(zclient, ZEBRA_ROUTE_STATIC, 0, &static_privs); zclient->zebra_capabilities = static_zebra_capabilities; zclient->zebra_connected = zebra_connected; - zclient->interface_address_add = interface_address_add; - zclient->interface_address_delete = interface_address_delete; - zclient->route_notify_owner = route_notify_owner; - zclient->nexthop_update = static_zebra_nexthop_update; static_nht_hash = hash_create(static_nht_hash_key, static_nht_hash_cmp, diff --git a/tests/.gitignore b/tests/.gitignore index 498d7dd0b7..53dbd68c9a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -28,6 +28,7 @@ /lib/test_frrscript /lib/test_frrlua /lib/test_graph +/lib/test_grpc /lib/test_heavy /lib/test_heavy_thread /lib/test_heavy_wq @@ -40,10 +41,12 @@ /lib/test_prefix2str /lib/test_printfrr /lib/test_privs +/lib/test_resolver /lib/test_ringbuf /lib/test_segv /lib/test_seqlock /lib/test_sig +/lib/test_skiplist /lib/test_srcdest_table /lib/test_stream /lib/test_table diff --git a/tests/bgpd/subdir.am b/tests/bgpd/subdir.am new file mode 100644 index 0000000000..5148e7e440 --- /dev/null +++ b/tests/bgpd/subdir.am @@ -0,0 +1,82 @@ +if !BGPD +PYTEST_IGNORE += --ignore=bgpd/ +endif +BGP_TEST_LDADD = bgpd/libbgp.a $(RFPLDADD) $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) $(UST_LIBS) -lm + + +if BGPD +check_PROGRAMS += tests/bgpd/test_aspath +endif +tests_bgpd_test_aspath_CFLAGS = $(TESTS_CFLAGS) +tests_bgpd_test_aspath_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD) +tests_bgpd_test_aspath_SOURCES = tests/bgpd/test_aspath.c +EXTRA_DIST += tests/bgpd/test_aspath.py + + +if BGPD +check_PROGRAMS += tests/bgpd/test_bgp_table +endif +tests_bgpd_test_bgp_table_CFLAGS = $(TESTS_CFLAGS) +tests_bgpd_test_bgp_table_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_bgpd_test_bgp_table_LDADD = $(BGP_TEST_LDADD) +tests_bgpd_test_bgp_table_SOURCES = tests/bgpd/test_bgp_table.c + + +if BGPD +check_PROGRAMS += tests/bgpd/test_capability +endif +tests_bgpd_test_capability_CFLAGS = $(TESTS_CFLAGS) +tests_bgpd_test_capability_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_bgpd_test_capability_LDADD = $(BGP_TEST_LDADD) +tests_bgpd_test_capability_SOURCES = tests/bgpd/test_capability.c +EXTRA_DIST += tests/bgpd/test_capability.py + + +if BGPD +check_PROGRAMS += tests/bgpd/test_ecommunity +endif +tests_bgpd_test_ecommunity_CFLAGS = $(TESTS_CFLAGS) +tests_bgpd_test_ecommunity_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD) +tests_bgpd_test_ecommunity_SOURCES = tests/bgpd/test_ecommunity.c +EXTRA_DIST += tests/bgpd/test_ecommunity.py + + +if BGPD +check_PROGRAMS += tests/bgpd/test_mp_attr +endif +tests_bgpd_test_mp_attr_CFLAGS = $(TESTS_CFLAGS) +tests_bgpd_test_mp_attr_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD) +tests_bgpd_test_mp_attr_SOURCES = tests/bgpd/test_mp_attr.c +EXTRA_DIST += tests/bgpd/test_mp_attr.py + + +if BGPD +check_PROGRAMS += tests/bgpd/test_mpath +endif +tests_bgpd_test_mpath_CFLAGS = $(TESTS_CFLAGS) +tests_bgpd_test_mpath_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD) +tests_bgpd_test_mpath_SOURCES = tests/bgpd/test_mpath.c +EXTRA_DIST += tests/bgpd/test_mpath.py + + +if BGPD +check_PROGRAMS += tests/bgpd/test_packet +endif +tests_bgpd_test_packet_CFLAGS = $(TESTS_CFLAGS) +tests_bgpd_test_packet_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_bgpd_test_packet_LDADD = $(BGP_TEST_LDADD) +tests_bgpd_test_packet_SOURCES = tests/bgpd/test_packet.c + + +if BGPD +check_PROGRAMS += tests/bgpd/test_peer_attr +endif +tests_bgpd_test_peer_attr_CFLAGS = $(TESTS_CFLAGS) +tests_bgpd_test_peer_attr_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_bgpd_test_peer_attr_LDADD = $(BGP_TEST_LDADD) +tests_bgpd_test_peer_attr_SOURCES = tests/bgpd/test_peer_attr.c +EXTRA_DIST += tests/bgpd/test_peer_attr.py diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c index 77fd876594..b93cbd8e5a 100644 --- a/tests/bgpd/test_mpath.c +++ b/tests/bgpd/test_mpath.c @@ -330,7 +330,7 @@ static int run_bgp_path_info_mpath_update(testcase_t *t) bgp_mp_list_add(&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[3]; old_best = NULL; - bgp_path_info_mpath_update(&test_rn, new_best, old_best, &mp_list, + bgp_path_info_mpath_update(NULL, &test_rn, new_best, old_best, &mp_list, &mp_cfg); bgp_mp_list_clear(&mp_list); EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 2, test_result); @@ -345,7 +345,7 @@ static int run_bgp_path_info_mpath_update(testcase_t *t) bgp_mp_list_add(&mp_list, &test_mp_list_info[1]); new_best = &test_mp_list_info[0]; old_best = &test_mp_list_info[3]; - bgp_path_info_mpath_update(&test_rn, new_best, old_best, &mp_list, + bgp_path_info_mpath_update(NULL, &test_rn, new_best, old_best, &mp_list, &mp_cfg); bgp_mp_list_clear(&mp_list); EXPECT_TRUE(bgp_path_info_mpath_count(new_best) == 1, test_result); @@ -392,7 +392,7 @@ static int global_test_init(void) { qobj_init(); master = thread_master_create(NULL); - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, NULL, 0); bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); vrf_init(NULL, NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); diff --git a/tests/isisd/subdir.am b/tests/isisd/subdir.am new file mode 100644 index 0000000000..2f9ce81f16 --- /dev/null +++ b/tests/isisd/subdir.am @@ -0,0 +1,66 @@ +if !ISISD +PYTEST_IGNORE += --ignore=isisd/ +endif +ISISD_TEST_LDADD = isisd/libisis.a $(ALL_TESTS_LDADD) +noinst_HEADERS += \ + tests/isisd/test_common.h \ + # end + + +if ISISD +check_PROGRAMS += tests/isisd/test_fuzz_isis_tlv +endif +tests_isisd_test_fuzz_isis_tlv_CFLAGS = $(TESTS_CFLAGS) -I$(top_builddir)/tests/isisd +tests_isisd_test_fuzz_isis_tlv_CPPFLAGS = $(TESTS_CPPFLAGS) -I$(top_builddir)/tests/isisd +tests_isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD) +tests_isisd_test_fuzz_isis_tlv_SOURCES = tests/isisd/test_fuzz_isis_tlv.c tests/isisd/test_common.c +nodist_tests_isisd_test_fuzz_isis_tlv_SOURCES = tests/isisd/test_fuzz_isis_tlv_tests.h +EXTRA_DIST += \ + tests/isisd/test_fuzz_isis_tlv.py \ + tests/isisd/test_fuzz_isis_tlv_tests.h.gz \ + # end + +tests/isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz + @mkdir -p tests/isisd + $(AM_V_GEN)gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@" +CLEANFILES += tests/isisd/test_fuzz_isis_tlv_tests.h + +tests/isisd/tests_isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ + tests/isisd/test_fuzz_isis_tlv_tests.h +tests/isisd/test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ + tests/isisd/test_fuzz_isis_tlv_tests.h + + +if ISISD +check_PROGRAMS += tests/isisd/test_isis_lspdb +endif +tests_isisd_test_isis_lspdb_CFLAGS = $(TESTS_CFLAGS) +tests_isisd_test_isis_lspdb_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_isisd_test_isis_lspdb_LDADD = $(ISISD_TEST_LDADD) +tests_isisd_test_isis_lspdb_SOURCES = tests/isisd/test_isis_lspdb.c tests/isisd/test_common.c +EXTRA_DIST += tests/isisd/test_isis_lspdb.py + + +if ISISD +check_PROGRAMS += tests/isisd/test_isis_spf +endif +tests_isisd_test_isis_spf_CFLAGS = $(TESTS_CFLAGS) +tests_isisd_test_isis_spf_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_isisd_test_isis_spf_LDADD = $(ISISD_TEST_LDADD) +tests_isisd_test_isis_spf_SOURCES = tests/isisd/test_isis_spf.c tests/isisd/test_common.c tests/isisd/test_topologies.c +nodist_tests_isisd_test_isis_spf_SOURCES = yang/frr-isisd.yang.c +EXTRA_DIST += \ + tests/isisd/test_isis_spf.py \ + tests/isisd/test_isis_spf.in \ + tests/isisd/test_isis_spf.refout \ + # end + + +if ISISD +check_PROGRAMS += tests/isisd/test_isis_vertex_queue +endif +tests_isisd_test_isis_vertex_queue_CFLAGS = $(TESTS_CFLAGS) +tests_isisd_test_isis_vertex_queue_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD) +tests_isisd_test_isis_vertex_queue_SOURCES = tests/isisd/test_isis_vertex_queue.c tests/isisd/test_common.c +EXTRA_DIST += tests/isisd/test_isis_vertex_queue.py diff --git a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz Binary files differindex 4f59d1d7c0..b50c5683bf 100644 --- a/tests/isisd/test_fuzz_isis_tlv_tests.h.gz +++ b/tests/isisd/test_fuzz_isis_tlv_tests.h.gz diff --git a/tests/lib/cli/common_cli.c b/tests/lib/cli/common_cli.c index 8be81cc4cb..7c9febe2ca 100644 --- a/tests/lib/cli/common_cli.c +++ b/tests/lib/cli/common_cli.c @@ -60,6 +60,7 @@ static void vty_do_exit(int isexit) } const struct frr_yang_module_info *const *test_yang_modules = NULL; +int test_log_prio = ZLOG_DISABLED; /* main routine. */ int main(int argc, char **argv) @@ -73,7 +74,7 @@ int main(int argc, char **argv) /* master init. */ master = thread_master_create(NULL); - zlog_aux_init("NONE: ", ZLOG_DISABLED); + zlog_aux_init("NONE: ", test_log_prio); /* Library inits. */ cmd_init(1); diff --git a/tests/lib/cli/common_cli.h b/tests/lib/cli/common_cli.h index 3042ff5b12..6660b27ef7 100644 --- a/tests/lib/cli/common_cli.h +++ b/tests/lib/cli/common_cli.h @@ -37,6 +37,8 @@ extern void test_init(int argc, char **argv); */ extern struct thread_master *master; +extern int test_log_prio; + extern int dump_args(struct vty *vty, const char *descr, int argc, struct cmd_token *argv[]); diff --git a/tests/lib/cli/test_commands.refout b/tests/lib/cli/test_commands.refout index 9d4a6ef03e..2ec3e5504b 100644 --- a/tests/lib/cli/test_commands.refout +++ b/tests/lib/cli/test_commands.refout @@ -191,38 +191,38 @@ execute strict 'no ipv6 nd mtu 1'@11: rv==0, 'no ipv6 nd mtu <1-65535>': '1' complete 'no ipv6 nd mtu 1'@11: rv==2 describe 'no ipv6 nd mtu 1'@11: rv==0 '<1-65535>' 'MTU in bytes' -execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' -execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@17: rv==0 'in' 'Filter incoming updates' -execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' -execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@18: rv==0 'in' 'Filter incoming updates' -execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' -execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@19: rv==0 'in' 'Filter incoming updates' -execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' -execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@20: rv==0 'in' 'Filter incoming updates' -execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' -execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@21: rv==0 'in' 'Filter incoming updates' -execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' -execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list (<1-199>|<1300-2699>|WORD) (in|out)': '1.2.3.4', '1', 'in' +execute relaxed 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' +execute strict 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0, 'no neighbor (A.B.C.D|X:X::X:X|WORD) distribute-list WORD (in|out)': '1.2.3.4', '1', 'in' complete 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==7 'in' describe 'no neighbor 1.2.3.4 distribute-list 1 in'@22: rv==0 diff --git a/tests/lib/subdir.am b/tests/lib/subdir.am new file mode 100644 index 0000000000..00fe93278b --- /dev/null +++ b/tests/lib/subdir.am @@ -0,0 +1,364 @@ +############################################################################## +if SCRIPTING +check_PROGRAMS += tests/lib/test_frrlua +endif +tests_lib_test_frrlua_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_frrlua_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_frrlua_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_frrlua_SOURCES = tests/lib/test_frrlua.c +EXTRA_DIST += tests/lib/test_frrlua.py + +if SCRIPTING +check_PROGRAMS += tests/lib/test_frrscript +endif +tests_lib_test_frrscript_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_frrscript_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_frrscript_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_frrscript_SOURCES = tests/lib/test_frrscript.c +EXTRA_DIST += tests/lib/test_frrscript.py + + +############################################################################## +GRPC_TESTS_LDADD = staticd/libstatic.a grpc/libfrrgrpc_pb.la -lgrpc++ -lprotobuf $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) -lm + +if GRPC +check_PROGRAMS += tests/lib/test_grpc +endif +tests_lib_test_grpc_CXXFLAGS = $(WERROR) $(TESTS_CXXFLAGS) +tests_lib_test_grpc_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_grpc_LDADD = $(GRPC_TESTS_LDADD) +tests_lib_test_grpc_SOURCES = tests/lib/test_grpc.cpp + + +############################################################################## +if ZEROMQ +check_PROGRAMS += tests/lib/test_zmq +endif +tests_lib_test_zmq_CFLAGS = $(TESTS_CFLAGS) $(ZEROMQ_CFLAGS) +tests_lib_test_zmq_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_zmq_LDADD = lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS) +tests_lib_test_zmq_SOURCES = tests/lib/test_zmq.c + + +############################################################################## +if CARES +check_PROGRAMS += tests/lib/test_resolver +endif +tests_lib_test_resolver_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_resolver_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_resolver_LDADD = $(ALL_TESTS_LDADD) lib/libfrrcares.la +tests_lib_test_resolver_SOURCES = tests/lib/test_resolver.c tests/lib/cli/common_cli.c + + +############################################################################## +noinst_HEADERS += \ + tests/helpers/c/prng.h \ + tests/helpers/c/tests.h \ + tests/lib/cli/common_cli.h \ + # end + + +check_PROGRAMS += tests/lib/cxxcompat +tests_lib_cxxcompat_CFLAGS = $(TESTS_CFLAGS) $(CXX_COMPAT_CFLAGS) $(WERROR) +tests_lib_cxxcompat_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_cxxcompat_SOURCES = tests/lib/cxxcompat.c +tests_lib_cxxcompat_LDADD = $(ALL_TESTS_LDADD) + + +check_PROGRAMS += tests/lib/cli/test_cli +tests_lib_cli_test_cli_CFLAGS = $(TESTS_CFLAGS) +tests_lib_cli_test_cli_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD) +tests_lib_cli_test_cli_SOURCES = tests/lib/cli/test_cli.c tests/lib/cli/common_cli.c +clippy_scan += tests/lib/cli/test_cli.c +EXTRA_DIST += \ + tests/lib/cli/test_cli.in \ + tests/lib/cli/test_cli.py \ + tests/lib/cli/test_cli.refout \ + # end + + +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 +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 + $(AM_V_GEN)sed \ + -e 's%"vtysh/vtysh\.h"%"tests/helpers/c/tests.h"%' \ + -e 's/vtysh_init_cmd/test_init_cmd/' \ + -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ + < vtysh/vtysh_cmd.c \ + > "$@" +CLEANFILES += tests/lib/cli/test_commands_defun.c +EXTRA_DIST += \ + tests/lib/cli/test_commands.in \ + tests/lib/cli/test_commands.py \ + tests/lib/cli/test_commands.refout \ + # end + + +check_PROGRAMS += tests/lib/northbound/test_oper_data +tests_lib_northbound_test_oper_data_CFLAGS = $(TESTS_CFLAGS) +tests_lib_northbound_test_oper_data_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_northbound_test_oper_data_LDADD = $(ALL_TESTS_LDADD) +tests_lib_northbound_test_oper_data_SOURCES = tests/lib/northbound/test_oper_data.c +nodist_tests_lib_northbound_test_oper_data_SOURCES = yang/frr-test-module.yang.c +EXTRA_DIST += \ + tests/lib/northbound/test_oper_data.in \ + tests/lib/northbound/test_oper_data.py \ + tests/lib/northbound/test_oper_data.refout \ + # end + + +check_PROGRAMS += tests/lib/test_assert +tests_lib_test_assert_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_assert_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_assert_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_assert_SOURCES = tests/lib/test_assert.c +EXTRA_DIST += tests/lib/test_assert.py + + +check_PROGRAMS += tests/lib/test_atomlist +tests_lib_test_atomlist_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_atomlist_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_atomlist_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_atomlist_SOURCES = tests/lib/test_atomlist.c +EXTRA_DIST += tests/lib/test_atomlist.py + + +check_PROGRAMS += tests/lib/test_buffer +tests_lib_test_buffer_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_buffer_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_buffer_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_buffer_SOURCES = tests/lib/test_buffer.c + + +check_PROGRAMS += tests/lib/test_checksum +tests_lib_test_checksum_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_checksum_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_checksum_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_checksum_SOURCES = tests/lib/test_checksum.c + + +check_PROGRAMS += tests/lib/test_graph +tests_lib_test_graph_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_graph_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_graph_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_graph_SOURCES = tests/lib/test_graph.c +EXTRA_DIST += \ + tests/lib/test_graph.py \ + tests/lib/test_graph.refout \ + # end + + +check_PROGRAMS += tests/lib/test_heavy +tests_lib_test_heavy_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_heavy_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_heavy_LDADD = $(ALL_TESTS_LDADD) -lm +tests_lib_test_heavy_SOURCES = tests/lib/test_heavy.c tests/helpers/c/main.c + + +check_PROGRAMS += tests/lib/test_heavy_thread +tests_lib_test_heavy_thread_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_heavy_thread_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_heavy_thread_LDADD = $(ALL_TESTS_LDADD) -lm +tests_lib_test_heavy_thread_SOURCES = tests/lib/test_heavy_thread.c tests/helpers/c/main.c + + +check_PROGRAMS += tests/lib/test_heavy_wq +tests_lib_test_heavy_wq_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_heavy_wq_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_heavy_wq_LDADD = $(ALL_TESTS_LDADD) -lm +tests_lib_test_heavy_wq_SOURCES = tests/lib/test_heavy_wq.c tests/helpers/c/main.c + + +check_PROGRAMS += tests/lib/test_idalloc +tests_lib_test_idalloc_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_idalloc_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_idalloc_SOURCES = tests/lib/test_idalloc.c + + +check_PROGRAMS += tests/lib/test_memory +tests_lib_test_memory_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_memory_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_memory_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_memory_SOURCES = tests/lib/test_memory.c + + +check_PROGRAMS += tests/lib/test_nexthop_iter +tests_lib_test_nexthop_iter_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_nexthop_iter_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_nexthop_iter_SOURCES = tests/lib/test_nexthop_iter.c tests/helpers/c/prng.c +EXTRA_DIST += tests/lib/test_nexthop_iter.py + + +check_PROGRAMS += tests/lib/test_nexthop +tests_lib_test_nexthop_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_nexthop_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_nexthop_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_nexthop_SOURCES = tests/lib/test_nexthop.c +EXTRA_DIST += tests/lib/test_nexthop.py + + +check_PROGRAMS += tests/lib/test_ntop +tests_lib_test_ntop_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_ntop_CPPFLAGS = $(CPPFLAGS_BASE) # no assert override +tests_lib_test_ntop_LDADD = # none +tests_lib_test_ntop_SOURCES = tests/lib/test_ntop.c tests/helpers/c/prng.c +EXTRA_DIST += tests/lib/test_ntop.py + + +check_PROGRAMS += tests/lib/test_plist +tests_lib_test_plist_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_plist_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_plist_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_plist_SOURCES = tests/lib/test_plist.c tests/lib/cli/common_cli.c + + +check_PROGRAMS += tests/lib/test_prefix2str +tests_lib_test_prefix2str_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_prefix2str_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_prefix2str_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_prefix2str_SOURCES = tests/lib/test_prefix2str.c tests/helpers/c/prng.c +EXTRA_DIST += tests/lib/test_prefix2str.py + + +check_PROGRAMS += tests/lib/test_printfrr +tests_lib_test_printfrr_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_printfrr_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_printfrr_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_printfrr_SOURCES = tests/lib/test_printfrr.c +EXTRA_DIST += tests/lib/test_printfrr.py + + +check_PROGRAMS += tests/lib/test_privs +tests_lib_test_privs_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_privs_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_privs_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_privs_SOURCES = tests/lib/test_privs.c + + +check_PROGRAMS += tests/lib/test_ringbuf +tests_lib_test_ringbuf_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_ringbuf_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_ringbuf_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_ringbuf_SOURCES = tests/lib/test_ringbuf.c +EXTRA_DIST += tests/lib/test_ringbuf.py + + +check_PROGRAMS += tests/lib/test_segv +tests_lib_test_segv_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_segv_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_segv_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_segv_SOURCES = tests/lib/test_segv.c + + +check_PROGRAMS += tests/lib/test_seqlock +tests_lib_test_seqlock_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_seqlock_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_seqlock_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_seqlock_SOURCES = tests/lib/test_seqlock.c + + +check_PROGRAMS += tests/lib/test_sig +tests_lib_test_sig_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_sig_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_sig_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_sig_SOURCES = tests/lib/test_sig.c + + +check_PROGRAMS += tests/lib/test_skiplist +tests_lib_test_skiplist_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_skiplist_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_skiplist_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_skiplist_SOURCES = tests/lib/test_skiplist.c + + +check_PROGRAMS += tests/lib/test_srcdest_table +tests_lib_test_srcdest_table_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_srcdest_table_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_srcdest_table_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_srcdest_table_SOURCES = tests/lib/test_srcdest_table.c tests/helpers/c/prng.c +EXTRA_DIST += tests/lib/test_srcdest_table.py + + +check_PROGRAMS += tests/lib/test_stream +tests_lib_test_stream_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_stream_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_stream_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_stream_SOURCES = tests/lib/test_stream.c +EXTRA_DIST += \ + tests/lib/test_stream.py \ + tests/lib/test_stream.refout \ + # end + + +check_PROGRAMS += tests/lib/test_table +tests_lib_test_table_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_table_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm +tests_lib_test_table_SOURCES = tests/lib/test_table.c +EXTRA_DIST += tests/lib/test_table.py + + +check_PROGRAMS += tests/lib/test_timer_correctness +tests_lib_test_timer_correctness_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_timer_correctness_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_timer_correctness_SOURCES = tests/lib/test_timer_correctness.c tests/helpers/c/prng.c +EXTRA_DIST += tests/lib/test_timer_correctness.py + + +check_PROGRAMS += tests/lib/test_timer_performance +tests_lib_test_timer_performance_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_timer_performance_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_timer_performance_SOURCES = tests/lib/test_timer_performance.c tests/helpers/c/prng.c + + +check_PROGRAMS += tests/lib/test_ttable +tests_lib_test_ttable_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_ttable_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_ttable_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_ttable_SOURCES = tests/lib/test_ttable.c +EXTRA_DIST += \ + tests/lib/test_ttable.py \ + tests/lib/test_ttable.refout \ + # end + + +check_PROGRAMS += tests/lib/test_typelist +tests_lib_test_typelist_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_typelist_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_typelist_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_typelist_SOURCES = tests/lib/test_typelist.c tests/helpers/c/prng.c +noinst_HEADERS += tests/lib/test_typelist.h +EXTRA_DIST += tests/lib/test_typelist.py + + +check_PROGRAMS += tests/lib/test_versioncmp +tests_lib_test_versioncmp_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_versioncmp_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_versioncmp_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_versioncmp_SOURCES = tests/lib/test_versioncmp.c +EXTRA_DIST += tests/lib/test_versioncmp.py + + +check_PROGRAMS += tests/lib/test_xref +tests_lib_test_xref_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_xref_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_xref_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_xref_SOURCES = tests/lib/test_xref.c +EXTRA_DIST += tests/lib/test_xref.py + + +check_PROGRAMS += tests/lib/test_zlog +tests_lib_test_zlog_CFLAGS = $(TESTS_CFLAGS) +tests_lib_test_zlog_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_lib_test_zlog_LDADD = $(ALL_TESTS_LDADD) +tests_lib_test_zlog_SOURCES = tests/lib/test_zlog.c +EXTRA_DIST += tests/lib/test_zlog.py diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index 06996a2f13..8413b7b372 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -259,8 +259,8 @@ int main(int argc, char **argv) * * gateway addresses only for now: interfaces require more setup */ - printchk("(null)", "%pNHcg", NULL); - printchk("(null)", "%pNHci", NULL); + printchk("(null)", "%pNHcg", (struct nexthop *)NULL); + printchk("(null)", "%pNHci", (struct nexthop *)NULL); struct nexthop nh; diff --git a/tests/lib/test_resolver.c b/tests/lib/test_resolver.c new file mode 100644 index 0000000000..6a582cceaf --- /dev/null +++ b/tests/lib/test_resolver.c @@ -0,0 +1,81 @@ +/* + * FRR c-ares integration test + * Copyright (C) 2021 David Lamparter for NetDEF, Inc. + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* this test is not run automatically since tests MUST NOT rely on any outside + * state. DNS is most definitely "outside state". A testbed may not have any + * internet connectivity at all. It may not have working DNS. Or worst of + * all, whatever name we use to test may have a temporary failure entirely + * beyond our control. + * + * The only way this test could be run in a testbed is with an all-local DNS + * setup, which considering the resolver code is rarely touched is not worth + * the time at all. Instead, after touching the resolver code, manually run + * this test and throw some names at it. + */ + +#include <zebra.h> + +#include "vty.h" +#include "command.h" +#include "resolver.h" +#include "log.h" +#include "sockunion.h" + +#include "tests/lib/cli/common_cli.h" + +extern struct thread_master *master; + +static void resolver_result(struct resolver_query *resq, const char *errstr, + int numaddrs, union sockunion *addr) +{ + int i; + + if (numaddrs <= 0) { + zlog_warn("hostname resolution failed: %s", errstr); + return; + } + + for (i = 0; i < numaddrs; i++) + zlog_info("resolver result: %pSU", &addr[i]); +} + +struct resolver_query query; + +DEFUN (test_resolve, + test_resolve_cmd, + "resolve WORD", + "DNS resolver\n" + "Name to resolve\n") +{ + resolver_resolve(&query, AF_UNSPEC, 0, argv[1]->arg, resolver_result); + return CMD_SUCCESS; +} + +__attribute__((_CONSTRUCTOR(2000))) +static void test_setup(void) +{ + test_log_prio = LOG_DEBUG; +} + +void test_init(int argc, char **argv) +{ + resolver_init(master); + + install_element(VIEW_NODE, &test_resolve_cmd); +} diff --git a/tests/lib/test_segv.c b/tests/lib/test_segv.c index 8133637adc..494a162a45 100644 --- a/tests/lib/test_segv.c +++ b/tests/lib/test_segv.c @@ -28,7 +28,7 @@ #include "lib/log.h" #include "lib/memory.h" -struct quagga_signal_t sigs[] = {}; +struct frr_signal_t sigs[] = {}; struct thread_master *master; diff --git a/tests/lib/test_sig.c b/tests/lib/test_sig.c index 2aceafb8f0..9165f1850f 100644 --- a/tests/lib/test_sig.c +++ b/tests/lib/test_sig.c @@ -36,18 +36,18 @@ static void sigusr2(void) printf("processed usr2\n"); } -struct quagga_signal_t sigs[] = {{ - .signal = SIGHUP, - .handler = &sighup, - }, - { - .signal = SIGUSR1, - .handler = &sigusr1, - }, - { - .signal = SIGUSR2, - .handler = &sigusr2, - }}; +struct frr_signal_t sigs[] = {{ + .signal = SIGHUP, + .handler = &sighup, + }, + { + .signal = SIGUSR1, + .handler = &sigusr1, + }, + { + .signal = SIGUSR2, + .handler = &sigusr2, + }}; struct thread_master *master; struct thread t; diff --git a/tests/lib/test_timer_correctness.c b/tests/lib/test_timer_correctness.c index 0ae9761b11..1756d87a6f 100644 --- a/tests/lib/test_timer_correctness.c +++ b/tests/lib/test_timer_correctness.c @@ -153,7 +153,6 @@ int main(int argc, char **argv) XFREE(MTYPE_TMP, timers[index]->arg); thread_cancel(&timers[index]); - timers[index] = NULL; timers_pending--; } diff --git a/tests/lib/test_timer_performance.c b/tests/lib/test_timer_performance.c index 23c044c7c1..f9d634b6a6 100644 --- a/tests/lib/test_timer_performance.c +++ b/tests/lib/test_timer_performance.c @@ -77,7 +77,6 @@ int main(int argc, char **argv) index = prng_rand(prng) % SCHEDULE_TIMERS; thread_cancel(&timers[index]); - timers[index] = NULL; } monotime(&tv_stop); diff --git a/tests/lib/test_typelist.h b/tests/lib/test_typelist.h index 379a2396b4..8261616ed2 100644 --- a/tests/lib/test_typelist.h +++ b/tests/lib/test_typelist.h @@ -39,6 +39,8 @@ #define list_find concat(TYPE, _find) #define list_find_lt concat(TYPE, _find_lt) #define list_find_gteq concat(TYPE, _find_gteq) +#define list_member concat(TYPE, _member) +#define list_anywhere concat(TYPE, _anywhere) #define list_del concat(TYPE, _del) #define list_pop concat(TYPE, _pop) #define list_swap_all concat(TYPE, _swap_all) @@ -239,6 +241,13 @@ static void concat(test_, TYPE)(void) ts_hash_headx( &head, "swap2b", "a538546a6e6ab0484e925940aa8dd02fd934408bbaed8cb66a0721841584d838"); + + while (list_pop(&other)) + ; + list_fini(&other); + prng_free(prng_swap); + + ts_ref("swap-cleanup"); #endif /* !IS_ATOMIC */ k = 0; @@ -294,7 +303,7 @@ static void concat(test_, TYPE)(void) #elif IS_HEAP(REALTYPE) /* heap - partially sorted. */ prev = NULL; - l = k / 2; + l = k / 4; for (i = 0; i < l; i++) { item = list_pop(&head); if (prev) @@ -303,7 +312,24 @@ static void concat(test_, TYPE)(void) k--; prev = item; } - ts_hash("pop", NULL); + ts_hash("pop#1", NULL); + + for (i = 0; i < NITEM; i++) + assertf(list_member(&head, &itm[i]) == itm[i].scratchpad, + "%zu should:%d is:%d", i, itm[i].scratchpad, + list_member(&head, &itm[i])); + ts_hash("member", NULL); + + l = k / 2; + for (; i < l; i++) { + item = list_pop(&head); + if (prev) + assert(prev->val < item->val); + item->scratchpad = 0; + k--; + prev = item; + } + ts_hash("pop#2", NULL); #else /* !IS_UNIQ(REALTYPE) && !IS_HEAP(REALTYPE) */ for (i = 0; i < NITEM; i++) { @@ -380,6 +406,14 @@ static void concat(test_, TYPE)(void) assert(l + list_count(&head) == k); ts_hashx("del", "cb2e5d80f08a803ef7b56c15e981b681adcea214bebc2f55e12e0bfb242b07ca"); +#if !IS_ATOMIC(REALTYPE) + for (i = 0; i < NITEM; i++) + assertf(list_member(&head, &itm[i]) == itm[i].scratchpad, + "%zu should:%d is:%d", i, itm[i].scratchpad, + list_member(&head, &itm[i])); + ts_hashx("member", "cb2e5d80f08a803ef7b56c15e981b681adcea214bebc2f55e12e0bfb242b07ca"); +#endif + frr_each_safe(list, &head, item) { assert(item->scratchpad != 0); @@ -449,6 +483,13 @@ static void concat(test_, TYPE)(void) ts_hash_head( &head, "swap2b", "eabfcf1413936daaf20965abced95762f45110a6619b84aac7d38481bce4ea19"); + + while (list_pop(&other)) + ; + list_fini(&other); + prng_free(prng_swap); + + ts_ref("swap-cleanup"); #endif for (i = 0; i < NITEM / 2; i++) { @@ -461,7 +502,39 @@ static void concat(test_, TYPE)(void) } ts_hash("del-prng", "86d568a95eb429dab3162976c5a5f3f75aabc835932cd682aa280b6923549564"); +#if !IS_ATOMIC(REALTYPE) + for (i = 0; i < NITEM; i++) { + assertf(list_member(&head, &itm[i]) == itm[i].scratchpad, + "%zu should:%d is:%d", i, itm[i].scratchpad, + list_member(&head, &itm[i])); + assertf(list_anywhere(&itm[i]) == itm[i].scratchpad, + "%zu should:%d is:%d", i, itm[i].scratchpad, + list_anywhere(&itm[i])); + } + ts_hash("member", "86d568a95eb429dab3162976c5a5f3f75aabc835932cd682aa280b6923549564"); +#endif + l = 0; + while (l < (k / 4) && (prev = list_pop(&head))) { + assert(prev->scratchpad != 0); + + prev->scratchpad = 0; + l++; + } + ts_hash("pop#1", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d"); + +#if !IS_ATOMIC(REALTYPE) + for (i = 0; i < NITEM; i++) { + assertf(list_member(&head, &itm[i]) == itm[i].scratchpad, + "%zu should:%d is:%d", i, itm[i].scratchpad, + list_member(&head, &itm[i])); + assertf(list_anywhere(&itm[i]) == itm[i].scratchpad, + "%zu should:%d is:%d", i, itm[i].scratchpad, + list_anywhere(&itm[i])); + } + ts_hash("member", "42b8950c880535b2d2e0c980f9845f7841ecf675c0fb9801aec4170d2036349d"); +#endif + while ((item = list_pop(&head))) { assert(item->scratchpad != 0); @@ -471,7 +544,7 @@ static void concat(test_, TYPE)(void) assert(l == k); assert(list_count(&head) == 0); assert(list_first(&head) == NULL); - ts_hash("pop", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"); + ts_hash("pop#2", "df3f619804a92fdb4057192dc43dd748ea778adc52bc498ce80524c014b81119"); prng_free(prng); prng = prng_new(0x1e5a2d69); @@ -650,6 +723,7 @@ static void concat(test_, TYPE)(void) list_fini(&head); ts_ref("fini"); ts_end(); + prng_free(prng); printfrr("%s end\n", str(TYPE)); } @@ -680,6 +754,8 @@ static void concat(test_, TYPE)(void) #undef list_find #undef list_find_lt #undef list_find_gteq +#undef list_member +#undef list_anywhere #undef list_del #undef list_pop #undef list_swap_all diff --git a/tests/lib/test_zmq.c b/tests/lib/test_zmq.c index 65195aa3e1..c411de7252 100644 --- a/tests/lib/test_zmq.c +++ b/tests/lib/test_zmq.c @@ -266,7 +266,7 @@ static void sigchld(void) frrzmq_thread_cancel(&cb, &cb->write); } -static struct quagga_signal_t sigs[] = { +static struct frr_signal_t sigs[] = { { .signal = SIGCHLD, .handler = sigchld, diff --git a/tests/ospf6d/subdir.am b/tests/ospf6d/subdir.am new file mode 100644 index 0000000000..ef1f40cf08 --- /dev/null +++ b/tests/ospf6d/subdir.am @@ -0,0 +1,19 @@ +if !OSPF6D +PYTEST_IGNORE += --ignore=ospf6d/ +endif +OSPF6_TEST_LDADD = ospf6d/libospf6.a $(ALL_TESTS_LDADD) + + +if OSPF6D +check_PROGRAMS += tests/ospf6d/test_lsdb +endif +tests_ospf6d_test_lsdb_CFLAGS = $(TESTS_CFLAGS) +tests_ospf6d_test_lsdb_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD) +tests_ospf6d_test_lsdb_SOURCES = tests/ospf6d/test_lsdb.c tests/lib/cli/common_cli.c +clippy_scan += tests/ospf6d/test_lsdb.c +EXTRA_DIST += \ + tests/ospf6d/test_lsdb.py \ + tests/ospf6d/test_lsdb.in \ + tests/ospf6d/test_lsdb.refout \ + # end diff --git a/tests/ospfd/subdir.am b/tests/ospfd/subdir.am new file mode 100644 index 0000000000..5ed5b9deaa --- /dev/null +++ b/tests/ospfd/subdir.am @@ -0,0 +1,21 @@ +if !OSPFD +PYTEST_IGNORE += --ignore=ospfd/ +endif +OSPFD_TEST_LDADD = ospfd/libfrrospf.a $(ALL_TESTS_LDADD) +noinst_HEADERS += \ + tests/ospfd/common.h \ + # end + + +if OSPFD +check_PROGRAMS += tests/ospfd/test_ospf_spf +endif +tests_ospfd_test_ospf_spf_CFLAGS = $(TESTS_CFLAGS) +tests_ospfd_test_ospf_spf_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_ospfd_test_ospf_spf_LDADD = $(OSPFD_TEST_LDADD) +tests_ospfd_test_ospf_spf_SOURCES = tests/ospfd/test_ospf_spf.c tests/ospfd/common.c tests/ospfd/topologies.c +EXTRA_DIST += \ + tests/ospfd/test_ospf_spf.py \ + tests/ospfd/test_ospf_spf.in \ + tests/ospfd/test_ospf_spf.refout \ + # end diff --git a/tests/subdir.am b/tests/subdir.am index f21e12ecbb..ab322f70d2 100644 --- a/tests/subdir.am +++ b/tests/subdir.am @@ -2,165 +2,6 @@ # tests # -if BGPD -TESTS_BGPD = \ - tests/bgpd/test_aspath \ - tests/bgpd/test_capability \ - tests/bgpd/test_packet \ - tests/bgpd/test_peer_attr \ - tests/bgpd/test_ecommunity \ - tests/bgpd/test_mp_attr \ - tests/bgpd/test_mpath \ - tests/bgpd/test_bgp_table -IGNORE_BGPD = -else -TESTS_BGPD = -IGNORE_BGPD = --ignore=bgpd/ -endif - -if ISISD -TESTS_ISISD = \ - tests/isisd/test_fuzz_isis_tlv \ - tests/isisd/test_isis_lspdb \ - tests/isisd/test_isis_spf \ - tests/isisd/test_isis_vertex_queue \ - # end -IGNORE_ISISD = -else -TESTS_ISISD = -IGNORE_ISISD = --ignore=isisd/ -endif - -if OSPFD -TESTS_OSPFD = \ - tests/ospfd/test_ospf_spf \ - # end -IGNORE_OSPFD = -else -TESTS_OSPFD = -IGNORE_OSPFD = --ignore=ospfd/ -endif - -if OSPF6D -TESTS_OSPF6D = \ - tests/ospf6d/test_lsdb \ - # end -IGNORE_OSPF6D = -else -TESTS_OSPF6D = -IGNORE_OSPF6D = --ignore=ospf6d/ -endif - -if ZEBRA -TESTS_ZEBRA = \ - tests/zebra/test_lm_plugin \ - #end -IGNORE_ZEBRA = -else -TESTS_ZEBRA = -IGNORE_ZEBRA = --ignore=zebra/ -endif - -if SCRIPTING -TESTS_SCRIPTING = \ - tests/lib/test_frrlua \ - tests/lib/test_frrscript \ - #end -else -TESTS_SCRIPTING = -endif - -clippy_scan += \ - tests/lib/cli/test_cli.c \ - tests/ospf6d/test_lsdb.c \ - # end - -check_PROGRAMS = \ - tests/lib/cxxcompat \ - tests/lib/test_assert \ - tests/lib/test_atomlist \ - tests/lib/test_buffer \ - tests/lib/test_checksum \ - tests/lib/test_heavy_thread \ - tests/lib/test_heavy_wq \ - tests/lib/test_heavy \ - tests/lib/test_idalloc \ - tests/lib/test_memory \ - tests/lib/test_nexthop_iter \ - tests/lib/test_nexthop \ - tests/lib/test_ntop \ - tests/lib/test_plist \ - tests/lib/test_prefix2str \ - tests/lib/test_printfrr \ - tests/lib/test_privs \ - tests/lib/test_ringbuf \ - tests/lib/test_srcdest_table \ - tests/lib/test_segv \ - tests/lib/test_seqlock \ - tests/lib/test_sig \ - tests/lib/test_skiplist \ - tests/lib/test_stream \ - tests/lib/test_table \ - tests/lib/test_timer_correctness \ - tests/lib/test_timer_performance \ - tests/lib/test_ttable \ - tests/lib/test_typelist \ - tests/lib/test_versioncmp \ - tests/lib/test_xref \ - tests/lib/test_zlog \ - tests/lib/test_graph \ - tests/lib/cli/test_cli \ - tests/lib/cli/test_commands \ - tests/lib/northbound/test_oper_data \ - $(TESTS_BGPD) \ - $(TESTS_ISISD) \ - $(TESTS_OSPFD) \ - $(TESTS_OSPF6D) \ - $(TESTS_ZEBRA) \ - $(TESTS_SCRIPTING) \ - # end - -if GRPC -check_PROGRAMS += \ - tests/lib/test_grpc \ - #end -endif - -if ZEROMQ -check_PROGRAMS += \ - tests/lib/test_zmq \ - # end -endif - -tests/lib/cli/test_commands_defun.c: vtysh/vtysh_cmd.c - mkdir -p tests/lib/cli - sed \ - -e 's%"vtysh/vtysh\.h"%"tests/helpers/c/tests.h"%' \ - -e 's/vtysh_init_cmd/test_init_cmd/' \ - -e 's/VTYSH_[A-Z][A-Z_0-9]*/0/g' \ - < vtysh/vtysh_cmd.c \ - > "$@" -CLEANFILES += tests/lib/cli/test_commands_defun.c - -tests/isisd/test_fuzz_isis_tlv_tests.h: $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz - mkdir -p tests/isisd - gzip -d < $(top_srcdir)/tests/isisd/test_fuzz_isis_tlv_tests.h.gz > "$@" -CLEANFILES += tests/isisd/test_fuzz_isis_tlv_tests.h - -tests/isisd/tests_isisd_test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ - tests/isisd/test_fuzz_isis_tlv_tests.h -tests/isisd/test_fuzz_isis_tlv-test_fuzz_isis_tlv.$(OBJEXT): \ - tests/isisd/test_fuzz_isis_tlv_tests.h - -noinst_HEADERS += \ - tests/helpers/c/prng.h \ - tests/helpers/c/tests.h \ - tests/lib/cli/common_cli.h \ - tests/lib/test_typelist.h \ - tests/isisd/test_common.h \ - tests/ospfd/common.h \ - # end - # # *sigh* - there is no way to get CPPFLAGS or CFLAGS for a group of files :( # @@ -184,319 +25,52 @@ TESTS_CXXFLAGS = \ # note no -Werror ALL_TESTS_LDADD = lib/libfrr.la $(LIBCAP) -BGP_TEST_LDADD = bgpd/libbgp.a $(RFPLDADD) $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) $(UST_LIBS) -lm -ISISD_TEST_LDADD = isisd/libisis.a $(ALL_TESTS_LDADD) -if GRPC -GRPC_TESTS_LDADD = staticd/libstatic.a grpc/libfrrgrpc_pb.la -lgrpc++ -lprotobuf $(ALL_TESTS_LDADD) $(LIBYANG_LIBS) -lm -endif -OSPFD_TEST_LDADD = ospfd/libfrrospf.a $(ALL_TESTS_LDADD) -OSPF6_TEST_LDADD = ospf6d/libospf6.a $(ALL_TESTS_LDADD) -ZEBRA_TEST_LDADD = zebra/label_manager.o $(ALL_TESTS_LDADD) - -tests_bgpd_test_aspath_CFLAGS = $(TESTS_CFLAGS) -tests_bgpd_test_aspath_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_bgpd_test_aspath_LDADD = $(BGP_TEST_LDADD) -tests_bgpd_test_aspath_SOURCES = tests/bgpd/test_aspath.c -tests_bgpd_test_bgp_table_CFLAGS = $(TESTS_CFLAGS) -tests_bgpd_test_bgp_table_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_bgpd_test_bgp_table_LDADD = $(BGP_TEST_LDADD) -tests_bgpd_test_bgp_table_SOURCES = tests/bgpd/test_bgp_table.c -tests_bgpd_test_capability_CFLAGS = $(TESTS_CFLAGS) -tests_bgpd_test_capability_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_bgpd_test_capability_LDADD = $(BGP_TEST_LDADD) -tests_bgpd_test_capability_SOURCES = tests/bgpd/test_capability.c -tests_bgpd_test_ecommunity_CFLAGS = $(TESTS_CFLAGS) -tests_bgpd_test_ecommunity_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_bgpd_test_ecommunity_LDADD = $(BGP_TEST_LDADD) -tests_bgpd_test_ecommunity_SOURCES = tests/bgpd/test_ecommunity.c -tests_bgpd_test_mp_attr_CFLAGS = $(TESTS_CFLAGS) -tests_bgpd_test_mp_attr_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_bgpd_test_mp_attr_LDADD = $(BGP_TEST_LDADD) -tests_bgpd_test_mp_attr_SOURCES = tests/bgpd/test_mp_attr.c -tests_bgpd_test_mpath_CFLAGS = $(TESTS_CFLAGS) -tests_bgpd_test_mpath_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_bgpd_test_mpath_LDADD = $(BGP_TEST_LDADD) -tests_bgpd_test_mpath_SOURCES = tests/bgpd/test_mpath.c -tests_bgpd_test_packet_CFLAGS = $(TESTS_CFLAGS) -tests_bgpd_test_packet_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_bgpd_test_packet_LDADD = $(BGP_TEST_LDADD) -tests_bgpd_test_packet_SOURCES = tests/bgpd/test_packet.c -tests_bgpd_test_peer_attr_CFLAGS = $(TESTS_CFLAGS) -tests_bgpd_test_peer_attr_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_bgpd_test_peer_attr_LDADD = $(BGP_TEST_LDADD) -tests_bgpd_test_peer_attr_SOURCES = tests/bgpd/test_peer_attr.c - -tests_isisd_test_fuzz_isis_tlv_CFLAGS = $(TESTS_CFLAGS) -I$(top_builddir)/tests/isisd -tests_isisd_test_fuzz_isis_tlv_CPPFLAGS = $(TESTS_CPPFLAGS) -I$(top_builddir)/tests/isisd -tests_isisd_test_fuzz_isis_tlv_LDADD = $(ISISD_TEST_LDADD) -tests_isisd_test_fuzz_isis_tlv_SOURCES = tests/isisd/test_fuzz_isis_tlv.c tests/isisd/test_common.c -nodist_tests_isisd_test_fuzz_isis_tlv_SOURCES = tests/isisd/test_fuzz_isis_tlv_tests.h -tests_isisd_test_isis_lspdb_CFLAGS = $(TESTS_CFLAGS) -tests_isisd_test_isis_lspdb_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_isisd_test_isis_lspdb_LDADD = $(ISISD_TEST_LDADD) -tests_isisd_test_isis_lspdb_SOURCES = tests/isisd/test_isis_lspdb.c tests/isisd/test_common.c -tests_isisd_test_isis_spf_CFLAGS = $(TESTS_CFLAGS) -tests_isisd_test_isis_spf_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_isisd_test_isis_spf_LDADD = $(ISISD_TEST_LDADD) -tests_isisd_test_isis_spf_SOURCES = tests/isisd/test_isis_spf.c tests/isisd/test_common.c tests/isisd/test_topologies.c -nodist_tests_isisd_test_isis_spf_SOURCES = yang/frr-isisd.yang.c -tests_isisd_test_isis_vertex_queue_CFLAGS = $(TESTS_CFLAGS) -tests_isisd_test_isis_vertex_queue_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_isisd_test_isis_vertex_queue_LDADD = $(ISISD_TEST_LDADD) -tests_isisd_test_isis_vertex_queue_SOURCES = tests/isisd/test_isis_vertex_queue.c tests/isisd/test_common.c - -tests_ospfd_test_ospf_spf_CFLAGS = $(TESTS_CFLAGS) -tests_ospfd_test_ospf_spf_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_ospfd_test_ospf_spf_LDADD = $(OSPFD_TEST_LDADD) -tests_ospfd_test_ospf_spf_SOURCES = tests/ospfd/test_ospf_spf.c tests/ospfd/common.c tests/ospfd/topologies.c - -tests_lib_cxxcompat_CFLAGS = $(TESTS_CFLAGS) $(CXX_COMPAT_CFLAGS) $(WERROR) -tests_lib_cxxcompat_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_cxxcompat_SOURCES = tests/lib/cxxcompat.c -tests_lib_cxxcompat_LDADD = $(ALL_TESTS_LDADD) -tests_lib_cli_test_cli_CFLAGS = $(TESTS_CFLAGS) -tests_lib_cli_test_cli_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_cli_test_cli_LDADD = $(ALL_TESTS_LDADD) -tests_lib_cli_test_cli_SOURCES = tests/lib/cli/test_cli.c tests/lib/cli/common_cli.c -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 -tests_lib_cli_test_commands_SOURCES = tests/lib/cli/test_commands.c tests/helpers/c/prng.c -tests_lib_northbound_test_oper_data_CFLAGS = $(TESTS_CFLAGS) -tests_lib_northbound_test_oper_data_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_northbound_test_oper_data_LDADD = $(ALL_TESTS_LDADD) -tests_lib_northbound_test_oper_data_SOURCES = tests/lib/northbound/test_oper_data.c -nodist_tests_lib_northbound_test_oper_data_SOURCES = yang/frr-test-module.yang.c -if GRPC -tests_lib_test_grpc_CXXFLAGS = $(WERROR) $(TESTS_CXXFLAGS) -tests_lib_test_grpc_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_grpc_LDADD = $(GRPC_TESTS_LDADD) -tests_lib_test_grpc_SOURCES = tests/lib/test_grpc.cpp -endif -tests_lib_test_assert_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_assert_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_assert_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_assert_SOURCES = tests/lib/test_assert.c -tests_lib_test_atomlist_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_atomlist_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_atomlist_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_atomlist_SOURCES = tests/lib/test_atomlist.c -tests_lib_test_buffer_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_buffer_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_buffer_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_buffer_SOURCES = tests/lib/test_buffer.c -tests_lib_test_checksum_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_checksum_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_checksum_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_checksum_SOURCES = tests/lib/test_checksum.c -if SCRIPTING -tests_lib_test_frrlua_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_frrlua_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_frrlua_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_frrlua_SOURCES = tests/lib/test_frrlua.c -tests_lib_test_frrscript_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_frrscript_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_frrscript_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_frrscript_SOURCES = tests/lib/test_frrscript.c -endif -tests_lib_test_graph_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_graph_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_graph_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_graph_SOURCES = tests/lib/test_graph.c -tests_lib_test_heavy_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_heavy_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_heavy_LDADD = $(ALL_TESTS_LDADD) -lm -tests_lib_test_heavy_SOURCES = tests/lib/test_heavy.c tests/helpers/c/main.c -tests_lib_test_heavy_thread_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_heavy_thread_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_heavy_thread_LDADD = $(ALL_TESTS_LDADD) -lm -tests_lib_test_heavy_thread_SOURCES = tests/lib/test_heavy_thread.c tests/helpers/c/main.c -tests_lib_test_heavy_wq_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_heavy_wq_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_heavy_wq_LDADD = $(ALL_TESTS_LDADD) -lm -tests_lib_test_heavy_wq_SOURCES = tests/lib/test_heavy_wq.c tests/helpers/c/main.c -tests_lib_test_idalloc_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_idalloc_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_idalloc_SOURCES = tests/lib/test_idalloc.c -tests_lib_test_memory_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_memory_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_memory_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_memory_SOURCES = tests/lib/test_memory.c -tests_lib_test_nexthop_iter_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_nexthop_iter_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_nexthop_iter_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_nexthop_iter_SOURCES = tests/lib/test_nexthop_iter.c tests/helpers/c/prng.c -tests_lib_test_nexthop_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_nexthop_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_nexthop_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_nexthop_SOURCES = tests/lib/test_nexthop.c -tests_lib_test_ntop_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_ntop_CPPFLAGS = $(CPPFLAGS_BASE) # no assert override -tests_lib_test_ntop_LDADD = # none -tests_lib_test_ntop_SOURCES = tests/lib/test_ntop.c tests/helpers/c/prng.c -tests_lib_test_plist_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_plist_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_plist_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_plist_SOURCES = tests/lib/test_plist.c tests/lib/cli/common_cli.c -tests_lib_test_prefix2str_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_prefix2str_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_prefix2str_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_prefix2str_SOURCES = tests/lib/test_prefix2str.c tests/helpers/c/prng.c -tests_lib_test_printfrr_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_printfrr_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_printfrr_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_printfrr_SOURCES = tests/lib/test_printfrr.c -tests_lib_test_privs_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_privs_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_privs_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_privs_SOURCES = tests/lib/test_privs.c -tests_lib_test_ringbuf_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_ringbuf_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_ringbuf_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_ringbuf_SOURCES = tests/lib/test_ringbuf.c -tests_lib_test_segv_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_segv_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_segv_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_segv_SOURCES = tests/lib/test_segv.c -tests_lib_test_seqlock_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_seqlock_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_seqlock_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_seqlock_SOURCES = tests/lib/test_seqlock.c -tests_lib_test_sig_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_sig_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_sig_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_sig_SOURCES = tests/lib/test_sig.c -tests_lib_test_skiplist_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_skiplist_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_skiplist_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_skiplist_SOURCES = tests/lib/test_skiplist.c -tests_lib_test_srcdest_table_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_srcdest_table_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_srcdest_table_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_srcdest_table_SOURCES = tests/lib/test_srcdest_table.c tests/helpers/c/prng.c -tests_lib_test_stream_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_stream_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_stream_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_stream_SOURCES = tests/lib/test_stream.c -tests_lib_test_table_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_table_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_table_LDADD = $(ALL_TESTS_LDADD) -lm -tests_lib_test_table_SOURCES = tests/lib/test_table.c -tests_lib_test_timer_correctness_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_timer_correctness_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_timer_correctness_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_timer_correctness_SOURCES = tests/lib/test_timer_correctness.c tests/helpers/c/prng.c -tests_lib_test_timer_performance_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_timer_performance_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_timer_performance_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_timer_performance_SOURCES = tests/lib/test_timer_performance.c tests/helpers/c/prng.c -tests_lib_test_ttable_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_ttable_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_ttable_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_ttable_SOURCES = tests/lib/test_ttable.c -tests_lib_test_typelist_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_typelist_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_typelist_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_typelist_SOURCES = tests/lib/test_typelist.c tests/helpers/c/prng.c -tests_lib_test_versioncmp_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_versioncmp_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_versioncmp_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_versioncmp_SOURCES = tests/lib/test_versioncmp.c -tests_lib_test_xref_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_xref_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_xref_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_xref_SOURCES = tests/lib/test_xref.c -tests_lib_test_zlog_CFLAGS = $(TESTS_CFLAGS) -tests_lib_test_zlog_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_zlog_LDADD = $(ALL_TESTS_LDADD) -tests_lib_test_zlog_SOURCES = tests/lib/test_zlog.c -tests_lib_test_zmq_CFLAGS = $(TESTS_CFLAGS) $(ZEROMQ_CFLAGS) -tests_lib_test_zmq_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_lib_test_zmq_LDADD = lib/libfrrzmq.la $(ALL_TESTS_LDADD) $(ZEROMQ_LIBS) -tests_lib_test_zmq_SOURCES = tests/lib/test_zmq.c - -tests_ospf6d_test_lsdb_CFLAGS = $(TESTS_CFLAGS) -tests_ospf6d_test_lsdb_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_ospf6d_test_lsdb_LDADD = $(OSPF6_TEST_LDADD) -tests_ospf6d_test_lsdb_SOURCES = tests/ospf6d/test_lsdb.c tests/lib/cli/common_cli.c - -tests_zebra_test_lm_plugin_CFLAGS = $(TESTS_CFLAGS) -tests_zebra_test_lm_plugin_CPPFLAGS = $(TESTS_CPPFLAGS) -tests_zebra_test_lm_plugin_LDADD = $(ZEBRA_TEST_LDADD) -tests_zebra_test_lm_plugin_SOURCES = tests/zebra/test_lm_plugin.c EXTRA_DIST += \ tests/runtests.py \ - tests/bgpd/test_aspath.py \ - tests/bgpd/test_capability.py \ - tests/bgpd/test_ecommunity.py \ - tests/bgpd/test_mp_attr.py \ - tests/bgpd/test_mpath.py \ - tests/bgpd/test_peer_attr.py \ tests/helpers/python/frrsix.py \ tests/helpers/python/frrtest.py \ - tests/isisd/test_fuzz_isis_tlv.py \ - tests/isisd/test_fuzz_isis_tlv_tests.h.gz \ - tests/isisd/test_isis_lspdb.py \ - tests/isisd/test_isis_spf.py \ - tests/isisd/test_isis_spf.in \ - tests/isisd/test_isis_spf.refout \ - tests/isisd/test_isis_vertex_queue.py \ - tests/ospfd/test_ospf_spf.py \ - tests/ospfd/test_ospf_spf.in \ - tests/ospfd/test_ospf_spf.refout \ - tests/lib/cli/test_commands.in \ - tests/lib/cli/test_commands.py \ - tests/lib/cli/test_commands.refout \ - tests/lib/cli/test_cli.in \ - tests/lib/cli/test_cli.py \ - tests/lib/cli/test_cli.refout \ - tests/lib/northbound/test_oper_data.in \ - tests/lib/northbound/test_oper_data.py \ - tests/lib/northbound/test_oper_data.refout \ - tests/lib/test_assert.py \ - tests/lib/test_atomlist.py \ - tests/lib/test_nexthop_iter.py \ - tests/lib/test_nexthop.py \ - tests/lib/test_ntop.py \ - tests/lib/test_prefix2str.py \ - tests/lib/test_printfrr.py \ - tests/lib/test_ringbuf.py \ - tests/lib/test_srcdest_table.py \ - tests/lib/test_stream.py \ - tests/lib/test_stream.refout \ - tests/lib/test_table.py \ - tests/lib/test_timer_correctness.py \ - tests/lib/test_ttable.py \ - tests/lib/test_ttable.refout \ - tests/lib/test_typelist.py \ - tests/lib/test_versioncmp.py \ - tests/lib/test_xref.py \ - tests/lib/test_zlog.py \ - tests/lib/test_graph.py \ - tests/lib/test_graph.refout \ - tests/ospf6d/test_lsdb.py \ - tests/ospf6d/test_lsdb.in \ - tests/ospf6d/test_lsdb.refout \ - tests/zebra/test_lm_plugin.py \ - tests/zebra/test_lm_plugin.refout \ # end - -if SCRIPTING -EXTRA_DIST += \ - tests/lib/test_frrscript.py \ - tests/lib/test_frrlua.py \ - #end -endif +check_PROGRAMS = +PYTEST_IGNORE = .PHONY: tests/tests.xml tests/tests.xml: $(check_PROGRAMS) - ( cd tests; $(PYTHON) ../$(srcdir)/tests/runtests.py --junitxml=tests.xml -v ../$(srcdir)/tests $(IGNORE_BGPD) $(IGNORE_ISISD) $(IGNORE_OSPFD) $(IGNORE_OSPF6D); ) + ( cd tests; $(PYTHON) ../$(srcdir)/tests/runtests.py --junitxml=tests.xml -v ../$(srcdir)/tests $(PYTEST_IGNORE); ) check: tests/tests.xml clean-local: clean-tests .PHONY: clean-tests clean-tests: -rm -f tests/tests.xml + + +# CHEAT SHEET: +# +### conditional (if needed) - ONLY for "check_PROGRAMS +=" line! +# if DAEMON +# check_PROGRAMS += tests/daemon/test_foo +# endif +### CFLAGS/CPPFLAGS/LDADD as usual, extend on top of TESTS_XYZFLAGS +# tests_daemon_test_foo_CFLAGS = $(TESTS_CFLAGS) +# tests_daemon_test_foo_CPPFLAGS = $(TESTS_CPPFLAGS) +# tests_daemon_test_foo_LDADD = $(ALL_TESTS_LDADD) +# tests_daemon_test_foo_SOURCES = tests/daemon/test_foo.c +### don't forget "nodist_" for autogenerated source files, & add to CLEANFILES +# nodist_tests_daemon_test_foo_SOURCES = tests/daemon/test_foo_autogen.c +# CLEANFILES += tests/daemon/test_foo_autogen.c +### clippy_scan works normally +# clippy_scan += tests/daemon/test_foo.c +### header files for tests go into "noinst_HEADERS" +# noinst_HEADERS += tests/daemon/foo.h +### all python scripts & auxiliary files are added into EXTRA_DIST +# EXTRA_DIST += tests/daemon/test_foo.py +# + +include tests/bgpd/subdir.am +include tests/isisd/subdir.am +include tests/ospfd/subdir.am +include tests/ospf6d/subdir.am +include tests/zebra/subdir.am +include tests/lib/subdir.am diff --git a/tests/topotests/all_protocol_startup/r1/isisd.conf b/tests/topotests/all_protocol_startup/r1/isisd.conf index 413f8d15a9..8ceded894f 100644 --- a/tests/topotests/all_protocol_startup/r1/isisd.conf +++ b/tests/topotests/all_protocol_startup/r1/isisd.conf @@ -1,6 +1,6 @@ log file isisd.log ! -debug isis events +! debug isis events ! ! interface r1-eth5 diff --git a/tests/topotests/all_protocol_startup/r1/ldpd.conf b/tests/topotests/all_protocol_startup/r1/ldpd.conf index 02332a4e75..2358fb898e 100644 --- a/tests/topotests/all_protocol_startup/r1/ldpd.conf +++ b/tests/topotests/all_protocol_startup/r1/ldpd.conf @@ -1,7 +1,7 @@ log file ldpd.log ! -debug mpls ldp event -debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp zebra ! ! mpls ldp diff --git a/tests/topotests/all_protocol_startup/r1/ospf6d.conf b/tests/topotests/all_protocol_startup/r1/ospf6d.conf index 5c6f071644..2e45186653 100644 --- a/tests/topotests/all_protocol_startup/r1/ospf6d.conf +++ b/tests/topotests/all_protocol_startup/r1/ospf6d.conf @@ -1,9 +1,9 @@ log file ospf6d.log ! -debug ospf6 lsa unknown -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor ! interface r1-eth4 ! diff --git a/tests/topotests/all_protocol_startup/r1/ospfd.conf b/tests/topotests/all_protocol_startup/r1/ospfd.conf index bac9f61620..188f810f81 100644 --- a/tests/topotests/all_protocol_startup/r1/ospfd.conf +++ b/tests/topotests/all_protocol_startup/r1/ospfd.conf @@ -1,7 +1,7 @@ log file ospfd.log ! -debug ospf event -debug ospf zebra +! debug ospf event +! debug ospf zebra ! router ospf ospf router-id 192.168.0.1 diff --git a/tests/topotests/all_protocol_startup/r1/ripd.conf b/tests/topotests/all_protocol_startup/r1/ripd.conf index ace7608873..0a06794886 100644 --- a/tests/topotests/all_protocol_startup/r1/ripd.conf +++ b/tests/topotests/all_protocol_startup/r1/ripd.conf @@ -1,7 +1,7 @@ log file ripd.log ! -debug rip events -debug rip zebra +! debug rip events +! debug rip zebra ! router rip version 2 diff --git a/tests/topotests/all_protocol_startup/r1/ripngd.conf b/tests/topotests/all_protocol_startup/r1/ripngd.conf index 2e0aef3a14..d9d900f926 100644 --- a/tests/topotests/all_protocol_startup/r1/ripngd.conf +++ b/tests/topotests/all_protocol_startup/r1/ripngd.conf @@ -1,7 +1,7 @@ log file ripngd.log ! -debug ripng events -debug ripng zebra +! debug ripng events +! debug ripng zebra ! router ripng network fc00:0:0:2::/64 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 ddb7f4e16e..ca8c005f9e 100644 --- a/tests/topotests/all_protocol_startup/test_all_protocol_startup.py +++ b/tests/topotests/all_protocol_startup/test_all_protocol_startup.py @@ -34,7 +34,6 @@ import pytest import glob from time import sleep - pytestmark = [ pytest.mark.babeld, pytest.mark.bgpd, @@ -115,7 +114,7 @@ def setup_module(module): tgen.gears["r%s" % i].start() # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) + # tgen.mininet_cli() def teardown_module(module): @@ -127,7 +126,8 @@ def teardown_module(module): def test_router_running(): global fatal_error - net = get_topogen().net + tgen = get_topogen() + net = tgen.net # Skip if previous fatal error condition is raised if fatal_error != "": @@ -143,7 +143,7 @@ def test_router_running(): assert fatal_error == "", fatal_error # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) + # tgen.mininet_cli() def test_error_messages_vtysh(): @@ -198,9 +198,6 @@ def test_error_messages_vtysh(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_error_messages_daemons(): global fatal_error @@ -289,9 +286,6 @@ def test_error_messages_daemons(): assert error_logs == "", "Daemons report errors to StdErr" - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_converge_protocols(): global fatal_error @@ -325,7 +319,7 @@ def test_converge_protocols(): actual = ( net["r%s" % i] .cmd( - "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\s*$/d' | sort 2> /dev/null" + "vtysh -c \"show ip route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null" ) .rstrip() ) @@ -358,7 +352,7 @@ def test_converge_protocols(): actual = ( net["r%s" % i] .cmd( - "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\s*$/d' | sort 2> /dev/null" + "vtysh -c \"show ipv6 route\" | sed -e '/^Codes: /,/^\\s*$/d' | sort 2> /dev/null" ) .rstrip() ) @@ -379,9 +373,6 @@ def test_converge_protocols(): assert failures == 0, "IPv6 Routing table failed for r%s\n%s" % (i, diff) - # For debugging after starting FRR daemons, uncomment the next line - ## CLI(net) - def route_get_nhg_id(route_str): net = get_topogen().net @@ -397,34 +388,71 @@ def route_get_nhg_id(route_str): def verify_nexthop_group(nhg_id, recursive=False, ecmp=0): net = get_topogen().net - # Verify NHG is valid/installed - output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) - - match = re.search(r"Valid", output) - assert match is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id - + count = 0 + valid = None + ecmpcount = None + depends = None + resolved_id = None + installed = None + found = False + + while not found and count < 10: + count += 1 + # Verify NHG is valid/installed + output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) + valid = re.search(r"Valid", output) + if valid is None: + found = False + sleep(1) + continue + + if ecmp or recursive: + ecmpcount = re.search(r"Depends:.*\n", output) + if ecmpcount is None: + found = False + sleep(1) + continue + + # list of IDs in group + depends = re.findall(r"\((\d+)\)", ecmpcount.group(0)) + + if ecmp: + if len(depends) != ecmp: + found = False + sleep(1) + continue + else: + # If recursive, we need to look at its resolved group + if len(depends) != 1: + found = False + sleep(1) + continue + + resolved_id = int(depends[0]) + verify_nexthop_group(resolved_id, False) + else: + installed = re.search(r"Installed", output) + if installed is None: + found = False + sleep(1) + continue + found = True + + assert valid is not None, "Nexthop Group ID=%d not marked Valid" % nhg_id if ecmp or recursive: - match = re.search(r"Depends:.*\n", output) - assert match is not None, "Nexthop Group ID=%d has no depends" % nhg_id - - # list of IDs in group - depends = re.findall(r"\((\d+)\)", match.group(0)) - + assert ecmpcount is not None, "Nexthop Group ID=%d has no depends" % nhg_id if ecmp: assert len(depends) == ecmp, ( "Nexthop Group ID=%d doesn't match ecmp size" % nhg_id ) else: - # If recursive, we need to look at its resolved group assert len(depends) == 1, ( "Nexthop Group ID=%d should only have one recursive depend" % nhg_id ) - resolved_id = int(depends[0]) - verify_nexthop_group(resolved_id, False) - else: - match = re.search(r"Installed", output) - assert match is not None, "Nexthop Group ID=%d not marked Installed" % nhg_id + assert installed is not None, ( + "Nexthop Group ID=%d not marked Installed" % nhg_id + ) def verify_route_nexthop_group(route_str, recursive=False, ecmp=0): @@ -455,7 +483,6 @@ def test_nexthop_groups(): # Create with sharpd using nexthop-group net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.1 nexthop-group basic 1"') - verify_route_nexthop_group("2.2.2.1/32") ## Connected @@ -465,7 +492,6 @@ def test_nexthop_groups(): ) net["r1"].cmd('vtysh -c "sharp install routes 2.2.2.2 nexthop-group connected 1"') - verify_route_nexthop_group("2.2.2.2/32") ## Recursive @@ -542,24 +568,33 @@ def test_nexthop_groups(): net["r1"].cmd( 'vtysh -c "sharp install routes 6.6.6.4 nexthop-group infinite-recursive 1"' ) + sleep(5) net["r1"].cmd( 'vtysh -c "sharp install routes 6.6.6.3 nexthop-group infinite-recursive 1"' ) + sleep(5) net["r1"].cmd( 'vtysh -c "sharp install routes 6.6.6.2 nexthop-group infinite-recursive 1"' ) + sleep(5) net["r1"].cmd( 'vtysh -c "sharp install routes 6.6.6.1 nexthop-group infinite-recursive 1"' ) # Get routes and test if has too many (duplicate) nexthops + count = 0 + dups = [] nhg_id = route_get_nhg_id("6.6.6.1/32") - output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) + while (len(dups) != 3) and count < 10: + output = net["r1"].cmd('vtysh -c "show nexthop-group rib %d"' % nhg_id) - dups = re.findall(r"(via 1\.1\.1\.1)", output) + dups = re.findall(r"(via 1\.1\.1\.1)", output) + if len(dups) != 3: + count += 1 + sleep(1) # Should find 3, itself is inactive assert len(dups) == 3, ( @@ -567,8 +602,6 @@ def test_nexthop_groups(): % nhg_id ) - ##CLI(net) - ## Remove all NHG routes net["r1"].cmd('vtysh -c "sharp remove routes 2.2.2.1 1"') @@ -638,9 +671,6 @@ def test_rip_status(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_ripng_status(): global fatal_error @@ -705,9 +735,6 @@ def test_ripng_status(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_ospfv2_interfaces(): global fatal_error @@ -790,9 +817,6 @@ def test_ospfv2_interfaces(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_isis_interfaces(): global fatal_error @@ -856,9 +880,6 @@ def test_isis_interfaces(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_bgp_summary(): global fatal_error @@ -1037,9 +1058,6 @@ def test_bgp_summary(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_bgp_ipv6_summary(): global fatal_error @@ -1138,12 +1156,15 @@ def test_bgp_ipv6_summary(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_nht(): + global fatal_error net = get_topogen().net + + # Skip if previous fatal error condition is raised + if fatal_error != "": + pytest.skip(fatal_error) + print("\n\n**** Test that nexthop tracking is at least nominally working ****\n") thisDir = os.path.dirname(os.path.realpath(__file__)) @@ -1256,9 +1277,6 @@ def test_bgp_ipv4(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_bgp_ipv6(): global fatal_error @@ -1325,9 +1343,6 @@ def test_bgp_ipv6(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_route_map(): global fatal_error @@ -1488,6 +1503,14 @@ def test_nexthop_group_replace(): 'vtysh -c "c t" -c "nexthop-group replace" -c "nexthop 1.1.1.1 r1-eth1 onlink" -c "nexthop 1.1.1.2 r1-eth2 onlink"' ) + # At the moment there is absolutely no real easy way to query sharpd + # for the nexthop group actually installed. If it is not installed + # sharpd will just transmit the nexthops down instead of the nexthop + # group id. Leading to a situation where the replace is not actually + # being tested. So let's just wait some time here because this + # is hard and this test fails all the time + sleep(5) + # Create with sharpd using nexthop-group net["r1"].cmd('vtysh -c "sharp install routes 3.3.3.1 nexthop-group replace 1"') @@ -1567,9 +1590,6 @@ def test_mpls_interfaces(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_shutdown_check_stderr(): global fatal_error diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r1/bfdd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r1/bfdd.conf index f35e772790..ee7144d003 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r1/bfdd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r1/bfdd.conf @@ -1,5 +1,5 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf index 689797a5e6..d30c32043e 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r1/bgpd.conf @@ -1,4 +1,4 @@ -debug bgp neighbor-events +! debug bgp neighbor-events router bgp 101 bgp router-id 10.254.254.1 no bgp ebgp-requires-policy diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r3/bfdd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r3/bfdd.conf index f35e772790..ee7144d003 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r3/bfdd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r3/bfdd.conf @@ -1,5 +1,5 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! diff --git a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf index 1f5aac42ed..dba2ffd372 100644 --- a/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf +++ b/tests/topotests/bfd_bgp_cbit_topo3/r3/bgpd.conf @@ -1,4 +1,4 @@ -debug bgp neighbor-events +! debug bgp neighbor-events router bgp 102 bgp router-id 10.254.254.3 no bgp ebgp-requires-policy diff --git a/tests/topotests/bfd_isis_topo1/rt1/bfdd.conf b/tests/topotests/bfd_isis_topo1/rt1/bfdd.conf index 57f9cd9e3d..dbcf23f306 100644 --- a/tests/topotests/bfd_isis_topo1/rt1/bfdd.conf +++ b/tests/topotests/bfd_isis_topo1/rt1/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 10.0.1.2 interface eth-rt2 diff --git a/tests/topotests/bfd_isis_topo1/rt1/isisd.conf b/tests/topotests/bfd_isis_topo1/rt1/isisd.conf index 8026aad49d..a5cbdd932e 100644 --- a/tests/topotests/bfd_isis_topo1/rt1/isisd.conf +++ b/tests/topotests/bfd_isis_topo1/rt1/isisd.conf @@ -5,11 +5,11 @@ hostname rt1 ! password 1 ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis adj-packets -debug isis lsp-sched +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis adj-packets +! debug isis lsp-sched ! interface lo ip router isis 1 diff --git a/tests/topotests/bfd_isis_topo1/rt1/zebra.conf b/tests/topotests/bfd_isis_topo1/rt1/zebra.conf index 6003125b6b..7e6f7881b4 100644 --- a/tests/topotests/bfd_isis_topo1/rt1/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt1/zebra.conf @@ -3,10 +3,10 @@ log timestamp precision 3 ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra events -debug zebra rib +! debug zebra kernel +! debug zebra packet +! debug zebra events +! debug zebra rib ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/bfd_isis_topo1/rt2/bfdd.conf b/tests/topotests/bfd_isis_topo1/rt2/bfdd.conf index 6b34e337d3..d5054aac09 100644 --- a/tests/topotests/bfd_isis_topo1/rt2/bfdd.conf +++ b/tests/topotests/bfd_isis_topo1/rt2/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 10.0.1.1 interface eth-rt1 diff --git a/tests/topotests/bfd_isis_topo1/rt2/isisd.conf b/tests/topotests/bfd_isis_topo1/rt2/isisd.conf index b0fde64a5e..b32170d208 100644 --- a/tests/topotests/bfd_isis_topo1/rt2/isisd.conf +++ b/tests/topotests/bfd_isis_topo1/rt2/isisd.conf @@ -4,9 +4,9 @@ hostname rt2 ! password 1 ! -debug isis events -debug isis route-events -debug isis spf-events +! debug isis events +! debug isis route-events +! debug isis spf-events ! interface lo ip router isis 1 diff --git a/tests/topotests/bfd_isis_topo1/rt2/zebra.conf b/tests/topotests/bfd_isis_topo1/rt2/zebra.conf index 5fc7fc5b28..5788e31f12 100644 --- a/tests/topotests/bfd_isis_topo1/rt2/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt2/zebra.conf @@ -2,8 +2,8 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet +! debug zebra kernel +! debug zebra packet ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/bfd_isis_topo1/rt3/bfdd.conf b/tests/topotests/bfd_isis_topo1/rt3/bfdd.conf index 22937fe46f..fd9a5e1b9d 100644 --- a/tests/topotests/bfd_isis_topo1/rt3/bfdd.conf +++ b/tests/topotests/bfd_isis_topo1/rt3/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 10.0.2.1 interface eth-rt1 diff --git a/tests/topotests/bfd_isis_topo1/rt3/isisd.conf b/tests/topotests/bfd_isis_topo1/rt3/isisd.conf index 5c36e96c0f..b98f249395 100644 --- a/tests/topotests/bfd_isis_topo1/rt3/isisd.conf +++ b/tests/topotests/bfd_isis_topo1/rt3/isisd.conf @@ -4,9 +4,9 @@ hostname rt3 ! password 1 ! -debug isis events -debug isis route-events -debug isis spf-events +! debug isis events +! debug isis route-events +! debug isis spf-events ! interface lo ip router isis 1 diff --git a/tests/topotests/bfd_isis_topo1/rt3/zebra.conf b/tests/topotests/bfd_isis_topo1/rt3/zebra.conf index d368de9bbe..78eac2e15a 100644 --- a/tests/topotests/bfd_isis_topo1/rt3/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt3/zebra.conf @@ -2,8 +2,8 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet +! debug zebra kernel +! debug zebra packet ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/bfd_isis_topo1/rt4/bfdd.conf b/tests/topotests/bfd_isis_topo1/rt4/bfdd.conf index f35e772790..ee7144d003 100644 --- a/tests/topotests/bfd_isis_topo1/rt4/bfdd.conf +++ b/tests/topotests/bfd_isis_topo1/rt4/bfdd.conf @@ -1,5 +1,5 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! diff --git a/tests/topotests/bfd_isis_topo1/rt4/isisd.conf b/tests/topotests/bfd_isis_topo1/rt4/isisd.conf index 3eac407776..6a4b05f204 100644 --- a/tests/topotests/bfd_isis_topo1/rt4/isisd.conf +++ b/tests/topotests/bfd_isis_topo1/rt4/isisd.conf @@ -4,9 +4,9 @@ hostname rt4 ! password 1 ! -debug isis events -debug isis route-events -debug isis spf-events +! debug isis events +! debug isis route-events +! debug isis spf-events ! interface lo ip router isis 1 diff --git a/tests/topotests/bfd_isis_topo1/rt4/zebra.conf b/tests/topotests/bfd_isis_topo1/rt4/zebra.conf index 7b053bac35..a6cb573ed8 100644 --- a/tests/topotests/bfd_isis_topo1/rt4/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt4/zebra.conf @@ -2,8 +2,8 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet +! debug zebra kernel +! debug zebra packet ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/bfd_isis_topo1/rt5/bfdd.conf b/tests/topotests/bfd_isis_topo1/rt5/bfdd.conf index f35e772790..ee7144d003 100644 --- a/tests/topotests/bfd_isis_topo1/rt5/bfdd.conf +++ b/tests/topotests/bfd_isis_topo1/rt5/bfdd.conf @@ -1,5 +1,5 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! diff --git a/tests/topotests/bfd_isis_topo1/rt5/isisd.conf b/tests/topotests/bfd_isis_topo1/rt5/isisd.conf index 5d449f6f93..ed32b15ea1 100644 --- a/tests/topotests/bfd_isis_topo1/rt5/isisd.conf +++ b/tests/topotests/bfd_isis_topo1/rt5/isisd.conf @@ -4,9 +4,9 @@ hostname rt5 ! password 1 ! -debug isis events -debug isis route-events -debug isis spf-events +! debug isis events +! debug isis route-events +! debug isis spf-events ! interface lo ip router isis 1 diff --git a/tests/topotests/bfd_isis_topo1/rt5/zebra.conf b/tests/topotests/bfd_isis_topo1/rt5/zebra.conf index 0b7c9e02f3..33473c91a3 100644 --- a/tests/topotests/bfd_isis_topo1/rt5/zebra.conf +++ b/tests/topotests/bfd_isis_topo1/rt5/zebra.conf @@ -2,8 +2,8 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet +! debug zebra kernel +! debug zebra packet ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/bfd_isis_topo1/test_bfd_isis_topo1.py b/tests/topotests/bfd_isis_topo1/test_bfd_isis_topo1.py index 3c176f25a3..27a4419329 100644 --- a/tests/topotests/bfd_isis_topo1/test_bfd_isis_topo1.py +++ b/tests/topotests/bfd_isis_topo1/test_bfd_isis_topo1.py @@ -72,7 +72,6 @@ import os import sys import pytest import json -from time import sleep from functools import partial # Save the Current Working Directory to find configuration files. @@ -193,15 +192,14 @@ def test_bfd_isis_interface_failure_rt2_step3(): # By default BFD provides a recovery time of 900ms plus jitter, so let's wait # initial 2 seconds to let the CI not suffer. # TODO: add check for array size - sleep(2) router_compare_json_output( - "rt1", "show ip route isis json", "step3/show_ip_route_rt2_down.ref", 1, 0 + "rt1", "show ip route isis json", "step3/show_ip_route_rt2_down.ref", 20, 1 ) router_compare_json_output( - "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_rt2_down.ref", 1, 0 + "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_rt2_down.ref", 20, 1 ) router_compare_json_output( - "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 1, 0 + "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 20, 1 ) # Check recovery, this can take some time @@ -232,15 +230,14 @@ def test_bfd_isis_interface_failure_rt3_step3(): # By default BFD provides a recovery time of 900ms plus jitter, so let's wait # initial 2 seconds to let the CI not suffer. # TODO: add check for array size - sleep(2) router_compare_json_output( - "rt1", "show ip route isis json", "step3/show_ip_route_rt3_down.ref", 1, 0 + "rt1", "show ip route isis json", "step3/show_ip_route_rt3_down.ref", 20, 1 ) router_compare_json_output( - "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_rt3_down.ref", 1, 0 + "rt1", "show ipv6 route isis json", "step3/show_ipv6_route_rt3_down.ref", 20, 1 ) router_compare_json_output( - "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 1, 0 + "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 20, 1 ) # Check recovery, this can take some time diff --git a/tests/topotests/bfd_ospf_topo1/rt1/bfdd.conf b/tests/topotests/bfd_ospf_topo1/rt1/bfdd.conf index 610a20f88a..f34f4ca61d 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/bfdd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt1/bfdd.conf @@ -1,9 +1,9 @@ log file bfdd.log log timestamp precision 3 ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd ! diff --git a/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf index 9da8765005..ce36494604 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt1/ospfd.conf @@ -5,8 +5,8 @@ hostname rt1 ! password 1 ! -debug ospf event -debug ospf zebra +! debug ospf event +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/bfd_ospf_topo1/rt1/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt1/zebra.conf index 6003125b6b..7e6f7881b4 100644 --- a/tests/topotests/bfd_ospf_topo1/rt1/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt1/zebra.conf @@ -3,10 +3,10 @@ log timestamp precision 3 ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra events -debug zebra rib +! debug zebra kernel +! debug zebra packet +! debug zebra events +! debug zebra rib ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/bfd_ospf_topo1/rt2/bfdd.conf b/tests/topotests/bfd_ospf_topo1/rt2/bfdd.conf index 437f063d8f..5baea3c842 100644 --- a/tests/topotests/bfd_ospf_topo1/rt2/bfdd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt2/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd ! diff --git a/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf index 11be6a14b2..a8ca564e4e 100644 --- a/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt2/ospfd.conf @@ -4,8 +4,8 @@ hostname rt2 ! password 1 ! -debug ospf event -debug ospf zebra +! debug ospf event +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/bfd_ospf_topo1/rt2/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt2/zebra.conf index 5fc7fc5b28..5788e31f12 100644 --- a/tests/topotests/bfd_ospf_topo1/rt2/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt2/zebra.conf @@ -2,8 +2,8 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet +! debug zebra kernel +! debug zebra packet ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/bfd_ospf_topo1/rt3/bfdd.conf b/tests/topotests/bfd_ospf_topo1/rt3/bfdd.conf index 437f063d8f..5baea3c842 100644 --- a/tests/topotests/bfd_ospf_topo1/rt3/bfdd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt3/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd ! diff --git a/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf index acc54b3866..0404994c09 100644 --- a/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt3/ospfd.conf @@ -4,8 +4,8 @@ hostname rt3 ! password 1 ! -debug ospf event -debug ospf zebra +! debug ospf event +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/bfd_ospf_topo1/rt3/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt3/zebra.conf index d368de9bbe..78eac2e15a 100644 --- a/tests/topotests/bfd_ospf_topo1/rt3/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt3/zebra.conf @@ -2,8 +2,8 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet +! debug zebra kernel +! debug zebra packet ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/bfd_ospf_topo1/rt4/bfdd.conf b/tests/topotests/bfd_ospf_topo1/rt4/bfdd.conf index f35e772790..ee7144d003 100644 --- a/tests/topotests/bfd_ospf_topo1/rt4/bfdd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt4/bfdd.conf @@ -1,5 +1,5 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! diff --git a/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf index 670e56ccc8..6b8ab3704f 100644 --- a/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt4/ospfd.conf @@ -4,8 +4,8 @@ hostname rt4 ! password 1 ! -debug ospf event -debug ospf zebra +! debug ospf event +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/bfd_ospf_topo1/rt4/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt4/zebra.conf index 7b053bac35..a6cb573ed8 100644 --- a/tests/topotests/bfd_ospf_topo1/rt4/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt4/zebra.conf @@ -2,8 +2,8 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet +! debug zebra kernel +! debug zebra packet ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/bfd_ospf_topo1/rt5/bfdd.conf b/tests/topotests/bfd_ospf_topo1/rt5/bfdd.conf index f35e772790..ee7144d003 100644 --- a/tests/topotests/bfd_ospf_topo1/rt5/bfdd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt5/bfdd.conf @@ -1,5 +1,5 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! diff --git a/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf b/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf index 286de51288..043432ec3d 100644 --- a/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf +++ b/tests/topotests/bfd_ospf_topo1/rt5/ospfd.conf @@ -4,8 +4,8 @@ hostname rt5 ! password 1 ! -debug ospf event -debug ospf zebra +! debug ospf event +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/bfd_ospf_topo1/rt5/zebra.conf b/tests/topotests/bfd_ospf_topo1/rt5/zebra.conf index 0b7c9e02f3..33473c91a3 100644 --- a/tests/topotests/bfd_ospf_topo1/rt5/zebra.conf +++ b/tests/topotests/bfd_ospf_topo1/rt5/zebra.conf @@ -2,8 +2,8 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet +! debug zebra kernel +! debug zebra packet ! interface lo ip address 5.5.5.5/32 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 bef2c3f162..93a2339299 100755 --- a/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py +++ b/tests/topotests/bfd_ospf_topo1/test_bfd_ospf_topo1.py @@ -195,16 +195,16 @@ def test_bfd_ospf_interface_failure_rt2_step3(): # By default BFD provides a recovery time of 900ms plus jitter, so let's wait # initial 2 seconds to let the CI not suffer. - topotest.sleep(2, 'Wait for BFD down notification') + topotest.sleep(2, "Wait for BFD down notification") router_compare_json_output( - "rt1", "show ip route ospf json", "step3/show_ip_route_rt2_down.ref", 1, 0 + "rt1", "show ip route ospf json", "step3/show_ip_route_rt2_down.ref", 10, 2 ) router_compare_json_output( - "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt2_down.ref", 1, 0 + "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt2_down.ref", 10, 2 ) router_compare_json_output( - "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 1, 0 + "rt1", "show bfd peers json", "step3/show_bfd_peers_rt2_down.ref", 10, 2 ) # Check recovery, this can take some time @@ -234,15 +234,15 @@ def test_bfd_ospf_interface_failure_rt3_step3(): # By default BFD provides a recovery time of 900ms plus jitter, so let's wait # initial 2 seconds to let the CI not suffer. - topotest.sleep(2, 'Wait for BFD down notification') + topotest.sleep(2, "Wait for BFD down notification") router_compare_json_output( - "rt1", "show ip route ospf json", "step3/show_ip_route_rt3_down.ref", 1, 0 + "rt1", "show ip route ospf json", "step3/show_ip_route_rt3_down.ref", 10, 2 ) router_compare_json_output( - "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt3_down.ref", 1, 0 + "rt1", "show ipv6 route ospf json", "step3/show_ipv6_route_rt3_down.ref", 10, 2 ) router_compare_json_output( - "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 1, 0 + "rt1", "show bfd peers json", "step3/show_bfd_peers_rt3_down.ref", 10, 2 ) # Check recovery, this can take some time diff --git a/tests/topotests/bfd_profiles_topo1/r1/bfdd.conf b/tests/topotests/bfd_profiles_topo1/r1/bfdd.conf index 688f2e839c..c2ac9c1b7c 100644 --- a/tests/topotests/bfd_profiles_topo1/r1/bfdd.conf +++ b/tests/topotests/bfd_profiles_topo1/r1/bfdd.conf @@ -1,6 +1,6 @@ -debug bfd peer -debug bfd network -debug bfd zebra +! debug bfd peer +! debug bfd network +! debug bfd zebra ! bfd profile slowtx diff --git a/tests/topotests/bfd_profiles_topo1/r2/bfdd.conf b/tests/topotests/bfd_profiles_topo1/r2/bfdd.conf index 700c46ba1e..b68eecb34c 100644 --- a/tests/topotests/bfd_profiles_topo1/r2/bfdd.conf +++ b/tests/topotests/bfd_profiles_topo1/r2/bfdd.conf @@ -1,6 +1,6 @@ -debug bfd peer -debug bfd network -debug bfd zebra +! debug bfd peer +! debug bfd network +! debug bfd zebra ! bfd profile slowtx diff --git a/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf b/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf index 0c3db97bc1..1aab1d1372 100644 --- a/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf +++ b/tests/topotests/bfd_profiles_topo1/r2/bgpd.conf @@ -1,4 +1,4 @@ -debug bgp neighbor-events +! debug bgp neighbor-events ! router bgp 100 bgp router-id 10.254.254.2 diff --git a/tests/topotests/bfd_profiles_topo1/r3/bfdd.conf b/tests/topotests/bfd_profiles_topo1/r3/bfdd.conf index 08eb0468d6..f3a86edce8 100644 --- a/tests/topotests/bfd_profiles_topo1/r3/bfdd.conf +++ b/tests/topotests/bfd_profiles_topo1/r3/bfdd.conf @@ -1,6 +1,6 @@ -debug bfd peer -debug bfd network -debug bfd zebra +! debug bfd peer +! debug bfd network +! debug bfd zebra ! bfd profile fasttx diff --git a/tests/topotests/bfd_profiles_topo1/r3/isisd.conf b/tests/topotests/bfd_profiles_topo1/r3/isisd.conf index ca965e3956..3bba2b03cf 100644 --- a/tests/topotests/bfd_profiles_topo1/r3/isisd.conf +++ b/tests/topotests/bfd_profiles_topo1/r3/isisd.conf @@ -1,8 +1,8 @@ hostname r3 ! -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets ! interface r3-eth1 ipv6 router isis lan diff --git a/tests/topotests/bfd_profiles_topo1/r4/bfdd.conf b/tests/topotests/bfd_profiles_topo1/r4/bfdd.conf index 4f5e022077..a5d1e25949 100644 --- a/tests/topotests/bfd_profiles_topo1/r4/bfdd.conf +++ b/tests/topotests/bfd_profiles_topo1/r4/bfdd.conf @@ -1,6 +1,6 @@ -debug bfd peer -debug bfd network -debug bfd zebra +! debug bfd peer +! debug bfd network +! debug bfd zebra ! bfd profile fast-tx diff --git a/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf b/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf index 200937a9a5..12d68270f8 100644 --- a/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf +++ b/tests/topotests/bfd_profiles_topo1/r4/bgpd.conf @@ -1,4 +1,4 @@ -debug bgp neighbor-events +! debug bgp neighbor-events ! router bgp 200 bgp router-id 10.254.254.4 diff --git a/tests/topotests/bfd_profiles_topo1/r4/isisd.conf b/tests/topotests/bfd_profiles_topo1/r4/isisd.conf index d8ffc9bc2c..18009ce6dc 100644 --- a/tests/topotests/bfd_profiles_topo1/r4/isisd.conf +++ b/tests/topotests/bfd_profiles_topo1/r4/isisd.conf @@ -1,8 +1,8 @@ hostname r4 ! -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets ! interface r4-eth0 ipv6 router isis lan diff --git a/tests/topotests/bfd_profiles_topo1/r5/bfdd.conf b/tests/topotests/bfd_profiles_topo1/r5/bfdd.conf index 74dae5a60d..670fd44165 100644 --- a/tests/topotests/bfd_profiles_topo1/r5/bfdd.conf +++ b/tests/topotests/bfd_profiles_topo1/r5/bfdd.conf @@ -1,6 +1,6 @@ -debug bfd peer -debug bfd network -debug bfd zebra +! debug bfd peer +! debug bfd network +! debug bfd zebra ! bfd ! profile is commented out on purpose. diff --git a/tests/topotests/bfd_profiles_topo1/r6/bfdd.conf b/tests/topotests/bfd_profiles_topo1/r6/bfdd.conf index 74dae5a60d..670fd44165 100644 --- a/tests/topotests/bfd_profiles_topo1/r6/bfdd.conf +++ b/tests/topotests/bfd_profiles_topo1/r6/bfdd.conf @@ -1,6 +1,6 @@ -debug bfd peer -debug bfd network -debug bfd zebra +! debug bfd peer +! debug bfd network +! debug bfd zebra ! bfd ! profile is commented out on purpose. diff --git a/tests/topotests/bfd_topo1/r1/bfdd.conf b/tests/topotests/bfd_topo1/r1/bfdd.conf index 4102000337..b9efbafbc5 100644 --- a/tests/topotests/bfd_topo1/r1/bfdd.conf +++ b/tests/topotests/bfd_topo1/r1/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 192.168.0.2 diff --git a/tests/topotests/bfd_topo1/r2/bfdd.conf b/tests/topotests/bfd_topo1/r2/bfdd.conf index 412450ca1e..0d1e17e3ff 100644 --- a/tests/topotests/bfd_topo1/r2/bfdd.conf +++ b/tests/topotests/bfd_topo1/r2/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 192.168.0.1 diff --git a/tests/topotests/bfd_topo1/r3/bfdd.conf b/tests/topotests/bfd_topo1/r3/bfdd.conf index 4cf20bb904..e091a1c41d 100644 --- a/tests/topotests/bfd_topo1/r3/bfdd.conf +++ b/tests/topotests/bfd_topo1/r3/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 192.168.1.2 diff --git a/tests/topotests/bfd_topo1/r4/bfdd.conf b/tests/topotests/bfd_topo1/r4/bfdd.conf index 34b88c9a35..63dd738451 100644 --- a/tests/topotests/bfd_topo1/r4/bfdd.conf +++ b/tests/topotests/bfd_topo1/r4/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 192.168.2.2 diff --git a/tests/topotests/bfd_topo2/r1/bfdd.conf b/tests/topotests/bfd_topo2/r1/bfdd.conf index f03135021e..df8baeb5af 100644 --- a/tests/topotests/bfd_topo2/r1/bfdd.conf +++ b/tests/topotests/bfd_topo2/r1/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 2001:db8:4::1 multihop local-address 2001:db8:1::1 diff --git a/tests/topotests/bfd_topo2/r2/bfdd.conf b/tests/topotests/bfd_topo2/r2/bfdd.conf index f35e772790..ee7144d003 100644 --- a/tests/topotests/bfd_topo2/r2/bfdd.conf +++ b/tests/topotests/bfd_topo2/r2/bfdd.conf @@ -1,5 +1,5 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! diff --git a/tests/topotests/bfd_topo2/r3/bfdd.conf b/tests/topotests/bfd_topo2/r3/bfdd.conf index f35e772790..ee7144d003 100644 --- a/tests/topotests/bfd_topo2/r3/bfdd.conf +++ b/tests/topotests/bfd_topo2/r3/bfdd.conf @@ -1,5 +1,5 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! diff --git a/tests/topotests/bfd_topo2/r4/bfdd.conf b/tests/topotests/bfd_topo2/r4/bfdd.conf index 0173dc9be2..c1e8d28e96 100644 --- a/tests/topotests/bfd_topo2/r4/bfdd.conf +++ b/tests/topotests/bfd_topo2/r4/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 2001:db8:1::1 multihop local-address 2001:db8:4::1 diff --git a/tests/topotests/bfd_topo3/r1/bfd-peers.json b/tests/topotests/bfd_topo3/r1/bfd-peers.json index f8a354fc20..3ce8d97f15 100644 --- a/tests/topotests/bfd_topo3/r1/bfd-peers.json +++ b/tests/topotests/bfd_topo3/r1/bfd-peers.json @@ -18,9 +18,8 @@ "remote-receive-interval": 2000, "remote-transmit-interval": 2000, "status": "up", - "transmit-interval": 2000, "uptime": "*", - "vrf": "default" + "transmit-interval": 2000 }, { "detect-multiplier": 3, @@ -41,9 +40,8 @@ "remote-receive-interval": 600, "remote-transmit-interval": 600, "status": "up", - "transmit-interval": 600, "uptime": "*", - "vrf": "default" + "transmit-interval": 600 }, { "detect-multiplier": 3, @@ -64,8 +62,7 @@ "remote-receive-interval": 2000, "remote-transmit-interval": 2000, "status": "up", - "transmit-interval": 2000, "uptime": "*", - "vrf": "default" + "transmit-interval": 2000 } ] diff --git a/tests/topotests/bfd_topo3/r1/bfdd.conf b/tests/topotests/bfd_topo3/r1/bfdd.conf index 8e40b76d41..60f129b48d 100644 --- a/tests/topotests/bfd_topo3/r1/bfdd.conf +++ b/tests/topotests/bfd_topo3/r1/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd profile fast-tx diff --git a/tests/topotests/bfd_topo3/r2/bfd-peers.json b/tests/topotests/bfd_topo3/r2/bfd-peers.json index 786d66dbe3..a40f7e46cf 100644 --- a/tests/topotests/bfd_topo3/r2/bfd-peers.json +++ b/tests/topotests/bfd_topo3/r2/bfd-peers.json @@ -18,9 +18,8 @@ "remote-receive-interval": 600, "remote-transmit-interval": 600, "status": "up", - "transmit-interval": 600, "uptime": "*", - "vrf": "default" + "transmit-interval": 600 }, { "detect-multiplier": 3, @@ -41,8 +40,7 @@ "remote-receive-interval": 2000, "remote-transmit-interval": 2000, "status": "up", - "transmit-interval": 2000, "uptime": "*", - "vrf": "default" + "transmit-interval": 2000 } ] diff --git a/tests/topotests/bfd_topo3/r2/bfdd.conf b/tests/topotests/bfd_topo3/r2/bfdd.conf index 2a92e463e0..8297043e6d 100644 --- a/tests/topotests/bfd_topo3/r2/bfdd.conf +++ b/tests/topotests/bfd_topo3/r2/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd profile fast-tx diff --git a/tests/topotests/bfd_topo3/r3/bfd-peers.json b/tests/topotests/bfd_topo3/r3/bfd-peers.json index 1f58663a4e..2182b26ed3 100644 --- a/tests/topotests/bfd_topo3/r3/bfd-peers.json +++ b/tests/topotests/bfd_topo3/r3/bfd-peers.json @@ -18,9 +18,8 @@ "remote-receive-interval": 2000, "remote-transmit-interval": 2000, "status": "up", - "transmit-interval": 2000, "uptime": "*", - "vrf": "default" + "transmit-interval": 2000 }, { "detect-multiplier": 3, @@ -41,9 +40,8 @@ "remote-receive-interval": 2000, "remote-transmit-interval": 2000, "status": "up", - "transmit-interval": 2000, "uptime": "*", - "vrf": "default" + "transmit-interval": 2000 }, { "detect-multiplier": 3, @@ -64,8 +62,7 @@ "remote-receive-interval": 2000, "remote-transmit-interval": 2000, "status": "up", - "transmit-interval": 2000, "uptime": "*", - "vrf": "default" + "transmit-interval": 2000 } ] diff --git a/tests/topotests/bfd_topo3/r3/bfdd.conf b/tests/topotests/bfd_topo3/r3/bfdd.conf index f7972c6ce5..51ce2ac0c8 100644 --- a/tests/topotests/bfd_topo3/r3/bfdd.conf +++ b/tests/topotests/bfd_topo3/r3/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd profile slow-tx diff --git a/tests/topotests/bfd_topo3/r4/bfd-peers.json b/tests/topotests/bfd_topo3/r4/bfd-peers.json index 5477f39120..2f41f25c58 100644 --- a/tests/topotests/bfd_topo3/r4/bfd-peers.json +++ b/tests/topotests/bfd_topo3/r4/bfd-peers.json @@ -18,9 +18,8 @@ "remote-receive-interval": 2000, "remote-transmit-interval": 2000, "status": "up", - "transmit-interval": 2000, "uptime": "*", - "vrf": "default" + "transmit-interval": 2000 }, { "detect-multiplier": 3, @@ -41,8 +40,7 @@ "remote-receive-interval": 2000, "remote-transmit-interval": 2000, "status": "up", - "transmit-interval": 2000, "uptime": "*", - "vrf": "default" + "transmit-interval": 2000 } ] diff --git a/tests/topotests/bfd_topo3/r4/bfdd.conf b/tests/topotests/bfd_topo3/r4/bfdd.conf index f44abc0b8a..e5fc1647cf 100644 --- a/tests/topotests/bfd_topo3/r4/bfdd.conf +++ b/tests/topotests/bfd_topo3/r4/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd profile slow-tx diff --git a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf index fd57b2c4d5..8fca099686 100644 --- a/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r1/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 192.168.0.2 vrf r1-bfd-cust1 diff --git a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf index e5539f14e5..4490090ec6 100644 --- a/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r2/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 192.168.0.1 vrf r2-bfd-cust1 diff --git a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf index e1f53e1abc..0333320898 100644 --- a/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r3/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 192.168.1.2 vrf r3-bfd-cust1 diff --git a/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf b/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf index 9ef2023b21..119e5e5e40 100644 --- a/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf +++ b/tests/topotests/bfd_vrf_topo1/r4/bfdd.conf @@ -1,7 +1,7 @@ ! -debug bfd network -debug bfd peer -debug bfd zebra +! debug bfd network +! debug bfd peer +! debug bfd zebra ! bfd peer 192.168.2.2 vrf r4-bfd-cust1 diff --git a/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf b/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf index fa52150085..c7cf4a527f 100644 --- a/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf +++ b/tests/topotests/bgp_aggregate_address_topo1/r1/bgpd.conf @@ -1,4 +1,4 @@ -debug bgp updates +! debug bgp updates ! access-list acl-sup-one seq 5 permit 192.168.2.1/32 access-list acl-sup-one seq 10 deny any diff --git a/tests/topotests/bgp_auth/R1/bgpd_multi_vrf.conf b/tests/topotests/bgp_auth/R1/bgpd_multi_vrf.conf index 071b559462..644e01c0b4 100644 --- a/tests/topotests/bgp_auth/R1/bgpd_multi_vrf.conf +++ b/tests/topotests/bgp_auth/R1/bgpd_multi_vrf.conf @@ -1,4 +1,4 @@ -debug bgp neighbor-events +! debug bgp neighbor-events router bgp 65001 vrf blue timers bgp 3 9 diff --git a/tests/topotests/bgp_auth/R1/bgpd_vrf.conf b/tests/topotests/bgp_auth/R1/bgpd_vrf.conf index fc0ae53b11..5799da165a 100644 --- a/tests/topotests/bgp_auth/R1/bgpd_vrf.conf +++ b/tests/topotests/bgp_auth/R1/bgpd_vrf.conf @@ -1,4 +1,4 @@ -debug bgp neighbor-events +! debug bgp neighbor-events router bgp 65001 vrf blue timers bgp 3 9 diff --git a/tests/topotests/bgp_ecmp_topo1/peer1/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer1/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer1/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer1/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer10/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer10/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer10/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer10/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer11/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer11/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer11/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer11/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer12/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer12/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer12/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer12/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer13/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer13/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer13/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer13/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer14/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer14/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer14/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer14/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer15/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer15/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer15/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer15/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer16/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer16/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer16/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer16/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer17/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer17/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer17/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer17/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer18/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer18/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer18/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer18/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer19/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer19/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer19/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer19/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer2/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer2/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer2/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer2/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer20/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer20/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer20/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer20/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer3/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer3/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer3/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer3/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer4/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer4/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer4/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer4/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer5/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer5/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer5/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer5/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer6/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer6/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer6/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer6/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer7/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer7/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer7/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer7/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer8/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer8/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer8/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer8/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/peer9/exa-send.py b/tests/topotests/bgp_ecmp_topo1/peer9/exa-send.py index d9ae3d1906..6bef35508f 100755 --- a/tests/topotests/bgp_ecmp_topo1/peer9/exa-send.py +++ b/tests/topotests/bgp_ecmp_topo1/peer9/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_ecmp_topo1/r1/summary.txt b/tests/topotests/bgp_ecmp_topo1/r1/summary.txt index f0929536d3..68de28a35b 100644 --- a/tests/topotests/bgp_ecmp_topo1/r1/summary.txt +++ b/tests/topotests/bgp_ecmp_topo1/r1/summary.txt @@ -2,7 +2,7 @@ "ipv4Unicast":{ "routerId":"10.0.255.1", "as":100, - "vrfName":"Default", + "vrfName":"default", "peerCount":20, "peers":{ "10.0.1.101":{ diff --git a/tests/topotests/bgp_ecmp_topo1/r1/summary20.txt b/tests/topotests/bgp_ecmp_topo1/r1/summary20.txt index 9015f485f8..4895cdbecf 100644 --- a/tests/topotests/bgp_ecmp_topo1/r1/summary20.txt +++ b/tests/topotests/bgp_ecmp_topo1/r1/summary20.txt @@ -1,7 +1,7 @@ { "routerId":"10.0.255.1", "as":100, - "vrfName":"Default", + "vrfName":"default", "peerCount":20, "peers":{ "10.0.1.101":{ diff --git a/tests/topotests/bgp_ecmp_topo1/test_bgp_ecmp_topo1.py b/tests/topotests/bgp_ecmp_topo1/test_bgp_ecmp_topo1.py index 7b9ef0a505..96e4bf6ed3 100644 --- a/tests/topotests/bgp_ecmp_topo1/test_bgp_ecmp_topo1.py +++ b/tests/topotests/bgp_ecmp_topo1/test_bgp_ecmp_topo1.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 # # test_bgp_ecmp_topo1.py @@ -140,12 +140,6 @@ def test_bgp_convergence(): with 'json') and compare with `data` contents. """ output = router.vtysh_cmd(cmd, isjson=True) - if "ipv4Unicast" in output: - output["ipv4Unicast"]["vrfName"] = output["ipv4Unicast"]["vrfName"].replace( - "default", "Default" - ) - elif "vrfName" in output: - output["vrfName"] = output["vrfName"].replace("default", "Default") return topotest.json_cmp(output, data) test_func = functools.partial( diff --git a/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py b/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py index 54b3e80da5..2a51dc83ef 100644 --- a/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py +++ b/tests/topotests/bgp_ecmp_topo3/test_ibgp_ecmp_topo3.py @@ -29,6 +29,7 @@ import os import sys import time import pytest +import re from time import sleep # Save the Current Working Directory to find configuration files. @@ -221,6 +222,9 @@ def test_ecmp_fast_convergence(request, test_type, tgen, topo): shutdown_bringup_interface(tgen, "r2", intf1, True) shutdown_bringup_interface(tgen, "r2", intf2, True) + logger.info("Ensure that the links are still up") + result = verify_bgp_convergence(tgen, topo) + logger.info("Enable bgp fast-convergence cli") raw_config = { "r2": { @@ -233,6 +237,13 @@ def test_ecmp_fast_convergence(request, test_type, tgen, topo): result = apply_raw_config(tgen, raw_config) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + logger.info("Ensure BGP has processed the cli") + r2 = tgen.gears["r2"] + output = r2.vtysh_cmd("show run") + verify = re.search(r"fast-convergence", output ) + assert verify is not None, ( + "r2 does not have the fast convergence command yet") + logger.info("Shutdown one link b/w r2 and r3") shutdown_bringup_interface(tgen, "r2", intf1, False) diff --git a/tests/topotests/bgp_evpn_mh/torm11/evpn.conf b/tests/topotests/bgp_evpn_mh/torm11/evpn.conf index 01f4b65704..2c1c695a18 100644 --- a/tests/topotests/bgp_evpn_mh/torm11/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/torm11/evpn.conf @@ -1,9 +1,9 @@ ! frr defaults datacenter ! -debug bgp evpn mh es -debug bgp evpn mh route -debug bgp zebra +! debug bgp evpn mh es +! debug bgp evpn mh route +! debug bgp zebra ! ! router bgp 65002 diff --git a/tests/topotests/bgp_evpn_mh/torm11/zebra.conf b/tests/topotests/bgp_evpn_mh/torm11/zebra.conf index 33e89c06ae..a88370d06b 100644 --- a/tests/topotests/bgp_evpn_mh/torm11/zebra.conf +++ b/tests/topotests/bgp_evpn_mh/torm11/zebra.conf @@ -1,8 +1,8 @@ -debug zebra evpn mh es -debug zebra evpn mh mac -debug zebra evpn mh neigh -debug zebra evpn mh nh -debug zebra vxlan +! debug zebra evpn mh es +! debug zebra evpn mh mac +! debug zebra evpn mh neigh +! debug zebra evpn mh nh +! debug zebra vxlan ! evpn mh startup-delay 1 ! diff --git a/tests/topotests/bgp_evpn_mh/torm12/evpn.conf b/tests/topotests/bgp_evpn_mh/torm12/evpn.conf index 2c13024bbc..8b0ce1d98f 100644 --- a/tests/topotests/bgp_evpn_mh/torm12/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/torm12/evpn.conf @@ -1,9 +1,9 @@ ! frr defaults datacenter ! -debug bgp evpn mh es -debug bgp evpn mh route -debug bgp zebra +! debug bgp evpn mh es +! debug bgp evpn mh route +! debug bgp zebra ! ! router bgp 65003 diff --git a/tests/topotests/bgp_evpn_mh/torm12/zebra.conf b/tests/topotests/bgp_evpn_mh/torm12/zebra.conf index 419f62b2ac..95327628f4 100644 --- a/tests/topotests/bgp_evpn_mh/torm12/zebra.conf +++ b/tests/topotests/bgp_evpn_mh/torm12/zebra.conf @@ -1,8 +1,8 @@ -debug zebra evpn mh es -debug zebra evpn mh mac -debug zebra evpn mh neigh -debug zebra evpn mh nh -debug zebra vxlan +! debug zebra evpn mh es +! debug zebra evpn mh mac +! debug zebra evpn mh neigh +! debug zebra evpn mh nh +! debug zebra vxlan ! evpn mh startup-delay 1 ! diff --git a/tests/topotests/bgp_evpn_mh/torm21/evpn.conf b/tests/topotests/bgp_evpn_mh/torm21/evpn.conf index 2a2ba061c6..5247dc1ebd 100644 --- a/tests/topotests/bgp_evpn_mh/torm21/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/torm21/evpn.conf @@ -1,9 +1,9 @@ ! frr defaults datacenter ! -debug bgp evpn mh es -debug bgp evpn mh route -debug bgp zebra +! debug bgp evpn mh es +! debug bgp evpn mh route +! debug bgp zebra ! ! router bgp 65004 diff --git a/tests/topotests/bgp_evpn_mh/torm21/zebra.conf b/tests/topotests/bgp_evpn_mh/torm21/zebra.conf index 525f5eb099..6c75df73c3 100644 --- a/tests/topotests/bgp_evpn_mh/torm21/zebra.conf +++ b/tests/topotests/bgp_evpn_mh/torm21/zebra.conf @@ -1,8 +1,8 @@ -debug zebra evpn mh es -debug zebra evpn mh mac -debug zebra evpn mh neigh -debug zebra evpn mh nh -debug zebra vxlan +! debug zebra evpn mh es +! debug zebra evpn mh mac +! debug zebra evpn mh neigh +! debug zebra evpn mh nh +! debug zebra vxlan ! evpn mh startup-delay 1 ! diff --git a/tests/topotests/bgp_evpn_mh/torm22/evpn.conf b/tests/topotests/bgp_evpn_mh/torm22/evpn.conf index 432135c94a..ec56360176 100644 --- a/tests/topotests/bgp_evpn_mh/torm22/evpn.conf +++ b/tests/topotests/bgp_evpn_mh/torm22/evpn.conf @@ -1,9 +1,9 @@ ! frr defaults datacenter ! -debug bgp evpn mh es -debug bgp evpn mh route -debug bgp zebra +! debug bgp evpn mh es +! debug bgp evpn mh route +! debug bgp zebra ! router bgp 65005 bgp router-id 192.168.100.18 diff --git a/tests/topotests/bgp_evpn_mh/torm22/zebra.conf b/tests/topotests/bgp_evpn_mh/torm22/zebra.conf index 398064df6c..4c949668a2 100644 --- a/tests/topotests/bgp_evpn_mh/torm22/zebra.conf +++ b/tests/topotests/bgp_evpn_mh/torm22/zebra.conf @@ -1,8 +1,8 @@ -debug zebra evpn mh es -debug zebra evpn mh mac -debug zebra evpn mh neigh -debug zebra evpn mh nh -debug zebra vxlan +! debug zebra evpn mh es +! debug zebra evpn mh mac +! debug zebra evpn mh neigh +! debug zebra evpn mh nh +! debug zebra vxlan ! evpn mh startup-delay 1 ! diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf index 9237682067..ccbeae6ed7 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf @@ -1,6 +1,6 @@ -debug bgp neighbor-events -debug bgp updates -debug bgp zebra +! debug bgp neighbor-events +! debug bgp updates +! debug bgp zebra router bgp 65000 bgp router-id 192.168.100.21 bgp log-neighbor-changes diff --git a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf index f5eaab1953..4f1804c676 100644 --- a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf @@ -3,10 +3,10 @@ log stdout hostname r1 password zebra -debug zebra vxlan -debug zebra kernel -debug zebra dplane -debug zebra rib +! debug zebra vxlan +! debug zebra kernel +! debug zebra dplane +! debug zebra rib log stdout vrf r1-vrf-101 vni 101 diff --git a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf index 6dcacd288d..744c259d9a 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf @@ -1,6 +1,6 @@ -debug bgp neighbor-events -debug bgp updates -debug bgp zebra +! debug bgp neighbor-events +! debug bgp updates +! debug bgp zebra router bgp 65000 bgp router-id 192.168.100.41 bgp log-neighbor-changes diff --git a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf index e5f962d254..7d19a5b381 100644 --- a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf +++ b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf @@ -3,7 +3,7 @@ log stdout hostname r2 password zebra -debug zebra vxlan +! debug zebra vxlan vrf r2-vrf-101 vni 101 diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py index 6ea281e6f0..3e2fb2b6e0 100644 --- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py +++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py @@ -148,7 +148,7 @@ def setup_module(mod): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)), - "--vrfwnetns -o vrf0", + "--vrfwnetns", ) else: router.load_config( diff --git a/tests/topotests/bgp_extended_optional_parameters_length/__init__.py b/tests/topotests/bgp_extended_optional_parameters_length/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_extended_optional_parameters_length/__init__.py diff --git a/tests/topotests/bgp_extended_optional_parameters_length/r1/bgpd.conf b/tests/topotests/bgp_extended_optional_parameters_length/r1/bgpd.conf new file mode 100644 index 0000000000..d83013ca99 --- /dev/null +++ b/tests/topotests/bgp_extended_optional_parameters_length/r1/bgpd.conf @@ -0,0 +1,6 @@ +! +router bgp 65001 + no bgp ebgp-requires-policy + neighbor 192.168.1.2 remote-as external + neighbor 192.168.1.2 extended-optional-parameters +! diff --git a/tests/topotests/bgp_extended_optional_parameters_length/r1/zebra.conf b/tests/topotests/bgp_extended_optional_parameters_length/r1/zebra.conf new file mode 100644 index 0000000000..b29940f46a --- /dev/null +++ b/tests/topotests/bgp_extended_optional_parameters_length/r1/zebra.conf @@ -0,0 +1,4 @@ +! +int r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bgp_extended_optional_parameters_length/r2/bgpd.conf b/tests/topotests/bgp_extended_optional_parameters_length/r2/bgpd.conf new file mode 100644 index 0000000000..e390d6ed8d --- /dev/null +++ b/tests/topotests/bgp_extended_optional_parameters_length/r2/bgpd.conf @@ -0,0 +1,8 @@ +router bgp 65002 + no bgp ebgp-requires-policy + neighbor 192.168.1.1 remote-as external + neighbor 192.168.1.1 extended-optional-parameters + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_extended_optional_parameters_length/r2/zebra.conf b/tests/topotests/bgp_extended_optional_parameters_length/r2/zebra.conf new file mode 100644 index 0000000000..dc15cf756a --- /dev/null +++ b/tests/topotests/bgp_extended_optional_parameters_length/r2/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 172.16.16.1/32 +! +int r2-eth0 + ip address 192.168.1.2/24 +! 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 new file mode 100644 index 0000000000..e677dc6ff6 --- /dev/null +++ b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py @@ -0,0 +1,106 @@ +#!/usr/bin/env python + +# Copyright (c) 2021 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test if Extended Optional Parameters Length encoding format works +if forced with a knob. +https://datatracker.ietf.org/doc/html/rfc9072 +""" + +import os +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 + +pytestmark = [pytest.mark.bgpd] + + +def setup_module(mod): + topodef = {"s1": ("r1", "r2")} + tgen = Topogen(topodef, 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)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_extended_optional_parameters_length(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r1"] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast summary json")) + expected = { + "peers": { + "192.168.1.2": { + "pfxRcd": 2, + "pfxSnt": 2, + "state": "Established", + "peerState": "OK", + } + } + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, router) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't converge with extended-optional-parameters" + + def _bgp_extended_optional_parameters_length(router): + output = json.loads(router.vtysh_cmd("show bgp neighbor 192.168.1.2 json")) + expected = {"192.168.1.2": {"extendedOptionalParametersLength": True}} + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_extended_optional_parameters_length, router) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Can't see Extended Optional Parameters Length to be used" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_features/r1/ospf6d.conf b/tests/topotests/bgp_features/r1/ospf6d.conf index a38e4b862a..9afc6f4919 100644 --- a/tests/topotests/bgp_features/r1/ospf6d.conf +++ b/tests/topotests/bgp_features/r1/ospf6d.conf @@ -1,6 +1,6 @@ log file ospf6d.log ! -debug ospf6 neighbor +! debug ospf6 neighbor ! interface r1-lo ! diff --git a/tests/topotests/bgp_features/r1/ospf_neighbor.json b/tests/topotests/bgp_features/r1/ospf_neighbor.json index e742c119da..3b5f46d934 100644 --- a/tests/topotests/bgp_features/r1/ospf_neighbor.json +++ b/tests/topotests/bgp_features/r1/ospf_neighbor.json @@ -3,13 +3,13 @@ "192.168.0.2":[ { "priority":5, - "state":"Full\/Backup" + "converged":"Full" } ], "192.168.0.3":[ { "priority":5, - "state":"Full\/Backup" + "converged":"Full" } ] } diff --git a/tests/topotests/bgp_features/r1/ospfd.conf b/tests/topotests/bgp_features/r1/ospfd.conf index 68a1bb5c75..aef017fe52 100644 --- a/tests/topotests/bgp_features/r1/ospfd.conf +++ b/tests/topotests/bgp_features/r1/ospfd.conf @@ -1,7 +1,7 @@ log file ospfd.log ! -debug ospf event -debug ospf zebra +! debug ospf event +! debug ospf zebra ! interface r1-eth1 ip ospf hello-interval 2 diff --git a/tests/topotests/bgp_features/r2/ospf6d.conf b/tests/topotests/bgp_features/r2/ospf6d.conf index 47bd5a99cc..7fe535651e 100644 --- a/tests/topotests/bgp_features/r2/ospf6d.conf +++ b/tests/topotests/bgp_features/r2/ospf6d.conf @@ -1,6 +1,6 @@ log file ospf6d.log ! -debug ospf6 neighbor +! debug ospf6 neighbor ! interface r2-lo ! diff --git a/tests/topotests/bgp_features/r2/ospf_neighbor.json b/tests/topotests/bgp_features/r2/ospf_neighbor.json index 2fd589ae25..47bb57cd00 100644 --- a/tests/topotests/bgp_features/r2/ospf_neighbor.json +++ b/tests/topotests/bgp_features/r2/ospf_neighbor.json @@ -3,13 +3,13 @@ "192.168.0.1":[ { "priority":10, - "state":"Full\/DR" + "converged":"Full" } ], "192.168.0.3":[ { "priority":5, - "state":"Full\/Backup" + "converged":"Full" } ] } diff --git a/tests/topotests/bgp_features/r2/ospfd.conf b/tests/topotests/bgp_features/r2/ospfd.conf index 6f608e454b..7f043c9d74 100644 --- a/tests/topotests/bgp_features/r2/ospfd.conf +++ b/tests/topotests/bgp_features/r2/ospfd.conf @@ -1,7 +1,7 @@ log file ospfd.log ! -debug ospf event -debug ospf zebra +! debug ospf event +! debug ospf zebra ! int r2-eth1 ip ospf hello-interval 2 diff --git a/tests/topotests/bgp_features/r3/ospf6d.conf b/tests/topotests/bgp_features/r3/ospf6d.conf index eb74901ba1..07325b69b0 100644 --- a/tests/topotests/bgp_features/r3/ospf6d.conf +++ b/tests/topotests/bgp_features/r3/ospf6d.conf @@ -1,6 +1,6 @@ log file ospf6d.log ! -debug ospf6 neighbor +! debug ospf6 neighbor ! interface r3-lo ! diff --git a/tests/topotests/bgp_features/r3/ospf_neighbor.json b/tests/topotests/bgp_features/r3/ospf_neighbor.json index 80fc92c3bc..b84974ccca 100644 --- a/tests/topotests/bgp_features/r3/ospf_neighbor.json +++ b/tests/topotests/bgp_features/r3/ospf_neighbor.json @@ -3,13 +3,13 @@ "192.168.0.1":[ { "priority":10, - "state":"Full\/DR" + "converged":"Full" } ], "192.168.0.2":[ { "priority":10, - "state":"Full\/DR" + "converged":"Full" } ] } diff --git a/tests/topotests/bgp_features/r3/ospfd.conf b/tests/topotests/bgp_features/r3/ospfd.conf index 71e4f1e1df..c3399fd60d 100644 --- a/tests/topotests/bgp_features/r3/ospfd.conf +++ b/tests/topotests/bgp_features/r3/ospfd.conf @@ -1,7 +1,7 @@ log file ospfd.log ! -debug ospf event -debug ospf zebra +! debug ospf event +! debug ospf zebra ! int r3-eth1 ip ospf hello-interval 2 diff --git a/tests/topotests/bgp_features/test_bgp_features.py b/tests/topotests/bgp_features/test_bgp_features.py index 00f5d1fcb1..ab44ba3c83 100644 --- a/tests/topotests/bgp_features/test_bgp_features.py +++ b/tests/topotests/bgp_features/test_bgp_features.py @@ -235,20 +235,15 @@ def test_bgp_shutdown_message(): logger.info("Checking BGP shutdown received on router r{}".format(rtrNum)) shut_message = tgen.net["r{}".format(rtrNum)].cmd( - 'tail bgpd.log | grep "NOTIFICATION.*Cease/Administratively Shutdown"' + 'tail bgpd.log | grep "NOTIFICATION.*Cease/Administrative Shutdown"' ) assertmsg = "BGP shutdown message not received on router R{}".format(rtrNum) assert shut_message != "", assertmsg - m = re.search(".*([0-9]+ bytes[ 0-9a-fA-F]+)", shut_message) - if m: - found = m.group(1) - else: - found = "" assertmsg = "Incorrect BGP shutdown message received on router R{}".format( rtrNum ) - assert found == "8 bytes 41 42 43 44 61 62 63 64", assertmsg + assert "ABCDabcd" in shut_message, assertmsg # tgen.mininet_cli() 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 new file mode 100644 index 0000000000..290bf16fea --- /dev/null +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-1.py @@ -0,0 +1,1542 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF") +# in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test BGP Gracefull Restart functionality. +Basic Common Test steps for all the test case below : +- Create topology (setup module) + Creating 2 routers topology, r1, r2 in IBGP +- Bring up topology +- Verify for bgp to converge +- Configure BGP Garceful Restart on both the routers. + +1. Transition from Peer-level helper to Global Restarting +2. Transition from Peer-level helper to Global inherit helper +3. Transition from Peer-level restarting to Global inherit helper +4. Default GR functional mode is Helper. +5. Verify that the restarting node sets "R" bit while sending the + BGP open messages after the node restart, only if GR is enabled. +6. Verify if restarting node resets R bit in BGP open message + during normal BGP session flaps as well, even when GR restarting + mode is enabled. Here link flap happen due to interface UP/DOWN. +7. Verify if restarting node resets R bit in BGP + open message during normal BGP session flaps when GR is disabled. +8. Verify that restarting nodes set "F" bit while sending + the BGP open messages after it restarts, only when BGP GR is enabled. +9. Verify that only GR helper routers keep the stale + route entries, not any GR disabled router. +10. Verify that GR helper routers keeps all the routes received + from restarting node if both the routers are configured as + GR restarting node. +11. Verify that GR helper routers delete all the routes + received from a node if both the routers are configured as GR + helper node. +12. After BGP neighborship is established and GR capability is exchanged, + transition restarting router to disabled state and vice versa. +13. After BGP neighborship is established and GR capability is exchanged, + transition restarting router to disabled state and vice versa. +14. Verify that restarting nodes reset "F" bit while sending + the BGP open messages after it's restarts, when BGP GR is **NOT** enabled. +15. Verify that only GR helper routers keep the stale + route entries, not any GR disabled router. +16. Transition from Global Restarting to Disable and then Global + Disable to Restarting. +17. Transition from Global Helper to Disable and then Global + Disable to Helper. +18. Transition from Global Restart to Helper and then Global + Helper to Restart, Global Mode : GR Restarting + PerPeer Mode : GR Helper + GR Mode effective : GR Helper +19. Transition from Peer-level helper to Global Restarting, + Global Mode : GR Restarting + PerPeer Mode : GR Restarting + GR Mode effective : GR Restarting +20. Transition from Peer-level restart to Global Restart + Global Mode : GR Restarting + PerPeer Mode : GR Restarting + GR Mode effective : GR Restarting +21. Transition from Peer-level disabled to Global Restart + Global Mode : GR Restarting + PerPeer Mode : GR Disabled + GR Mode effective : GR Disabled +22. Peer-level inherit from Global Restarting + Global Mode : GR Restart + PerPeer Mode : None + GR Mode effective : GR Restart +23. Transition from Peer-level disbale to Global inherit helper + Global Mode : None + PerPeer Mode : GR Disable + GR Mode effective : GR Disable + +These tests have been broken up into 4 sub python scripts because +the totality of this run was fairly significant. +""" + +import os +import sys +import time +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("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +# Import topoJson from lib, to create topology and initial configuration +from lib.topojson import build_config_from_json +from lib.bgp import ( + clear_bgp, + verify_bgp_rib, + verify_graceful_restart, + create_router_bgp, + verify_r_bit, + verify_f_bit, + verify_bgp_convergence, + verify_bgp_convergence_from_running_config, +) + +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, + shutdown_bringup_interface, + step, + get_frr_ipv6_linklocal, + required_linux_kernel_version, +) + +pytestmark = [pytest.mark.bgpd] + + +# Global variables +NEXT_HOP_IP = {"ipv4": "192.168.1.10", "ipv6": "fd00:0:0:1::10"} +NEXT_HOP_IP_1 = {"ipv4": "192.168.0.1", "ipv6": "fd00::1"} +NEXT_HOP_IP_2 = {"ipv4": "192.168.0.2", "ipv6": "fd00::2"} +BGP_CONVERGENCE = False +GR_RESTART_TIMER = 20 +PREFERRED_NEXT_HOP = "link_local" + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + global ADDR_TYPES + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.16") + if result is not True: + pytest.skip("Kernel requirements are not met") + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_gr_topojson_topo1.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + ADDR_TYPES = check_address_types() + + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): + """ + This function groups the repetitive function calls into one function. + """ + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][peer]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][dut]["links"]["r2-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + return True + + +def next_hop_per_address_family( + tgen, dut, peer, addr_type, next_hop_dict, preferred_next_hop=PREFERRED_NEXT_HOP +): + """ + This function returns link_local or global next_hop per address-family + """ + + intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"] + if addr_type == "ipv6" and "link_local" in preferred_next_hop: + next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface) + else: + next_hop = next_hop_dict[addr_type] + + return next_hop + + +def BGP_GR_TC_50_p1(request): + """ + Test Objective : Transition from Peer-level helper to Global inherit helper + Global Mode : None + PerPeer Mode : Helper + GR Mode effective : GR Helper + + """ + + 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 helper node at per Peer-level for R2" + " and configure R2 as global restarting node." + ) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step("Verify on R2 that R1 advertises GR capabilities as a helper node") + + 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 + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Kill BGP on R2") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + step( + "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Bring up BGP on R2 and remove Peer-level GR config from R1 ") + + start_router_daemons(tgen, "r2", ["bgpd"]) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": False} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": False} + } + } + } + } + }, + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify on R2 that R1 still advertises GR capabilities as a helper node") + + input_dict = { + "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + 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 + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Kill BGP on R2") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + step( + "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Start BGP on R2") + + start_router_daemons(tgen, "r2", ["bgpd"]) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_51_p1(request): + """ + Test Objective : Transition from Peer-level restarting to Global inherit helper + Global Mode : None + PerPeer Mode : GR Restart + 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 at per Peer-level for R2") + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + } + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + step("Verify on R2 that R1 advertises GR capabilities as a restarting node") + + 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 + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r2", 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 that R1 keeps the stale entries in FIB & R2 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Bring up BGP on R1 and remove Peer-level GR config") + + start_router_daemons(tgen, "r1", ["bgpd"]) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": False} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": False} + } + } + } + } + }, + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify on R2 that R1 advertises GR capabilities as a helper node") + + input_dict = { + "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + 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 + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Kill BGPd on R2") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + step( + "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Start BGP on R2") + + start_router_daemons(tgen, "r2", ["bgpd"]) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_53_p1(request): + """ + Test Objective : Default GR functional mode is Helper. + Global Mode : None + PerPeer Mode : None + GR Mode effective : GR Helper + + """ + + 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 R2 as global restarting node") + + input_dict = {"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}} + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step( + "Verify on R2 that R1 advertises GR capabilities as a helper node based on inherit" + ) + + input_dict = { + "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + 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 + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Kill BGPd on R2") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + step( + "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Start BGP on R2") + + start_router_daemons(tgen, "r2", ["bgpd"]) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_4_p0(request): + """ + Test Objective : Verify that the restarting node sets "R" bit while sending the + BGP open messages after the node restart, only if GR is enabled. + """ + + 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) + + logger.info( + "[Phase 1] : Test Setup" " [Restart Mode]R1-----R2[Helper Mode] initialized " + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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 + ) + + # Verifying BGP RIB routes + dut = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + protocol = "bgp" + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Phase 2] : R2 goes for reload ") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + logger.info( + "[Phase 3] : R2 is still down, restart time {} sec." + "So time verify the routes are present in BGP RIB and ZEBRA ".format( + GR_RESTART_TIMER + ) + ) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib( + tgen, addr_type, dut, input_topo, next_hop, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying RIB routes + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + logger.info(" Expected behavior: {}".format(result)) + + logger.info("[Phase 5] : R2 is about to come up now ") + start_router_daemons(tgen, "r2", ["bgpd"]) + + logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ") + + 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_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2") + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_5_1_2_p1(request): + """ + Test Objective : Verify if restarting node resets R bit in BGP open message + during normal BGP session flaps as well, even when GR restarting mode is enabled. + Here link flap happen due to interface UP/DOWN. + + """ + 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) + + logger.info( + "[Phase 1] : Test Setup" " [Restart Mode]R1-----R2[Restart Mode] initialized " + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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 + ) + + # Verifying BGP RIB routes + dut = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + protocol = "bgp" + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Phase 2] : Now flap the link running the BGP session ") + # Shutdown interface + intf = "r2-r1-eth0" + shutdown_bringup_interface(tgen, "r2", intf) + + # Bring up Interface + shutdown_bringup_interface(tgen, "r2", intf, ifaceaction=True) + + 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_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2") + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Phase 2] : Restart BGPd on router R2. ") + kill_router_daemons(tgen, "r2", ["bgpd"]) + + start_router_daemons(tgen, "r2", ["bgpd"]) + + logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ") + + 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_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2") + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_6_1_2_p1(request): + """ + Test Objective : Verify if restarting node resets R bit in BGP + open message during normal BGP session flaps when GR is disabled. + """ + + 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) + + logger.info( + "[Phase 1] : Test Setup" "[Restart Mode]R1-----R2[Helper Mode] initialized " + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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 + ) + + # Verifying BGP RIB routes + dut = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + protocol = "bgp" + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Phase 1] : Changing mode" "[Disable Mode]R1-----R2[Helper Mode]") + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": True} + } + } + } + } + }, + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + # Verify GR stats + input_dict = { + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": True} + } + } + } + } + }, + } + } + }, + } + + # here the verify_graceful_restart fro the neighbor would be + # "NotReceived" as the latest GR config is not yet applied. + 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 + ) + + logger.info("[Phase 2] : Now flap the link running the BGP session ") + # Shutdown interface + intf = "r2-r1-eth0" + shutdown_bringup_interface(tgen, "r2", intf) + + # Bring up Interface + shutdown_bringup_interface(tgen, "r2", intf, ifaceaction=True) + + 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_r_bit( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format( + tc_name, result + ) + + logger.info("Restart BGPd on R2 ") + kill_router_daemons(tgen, "r2", ["bgpd"]) + + start_router_daemons(tgen, "r2", ["bgpd"]) + + 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_r_bit( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format( + tc_name, result + ) + + 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_topo1/test_bgp_gr_functionality_topo1-2.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py new file mode 100644 index 0000000000..0647ad5d06 --- /dev/null +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-2.py @@ -0,0 +1,404 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF") +# in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test BGP Gracefull Restart functionality. +Basic Common Test steps for all the test case below : +- Create topology (setup module) + Creating 2 routers topology, r1, r2 in IBGP +- Bring up topology +- Verify for bgp to converge +- Configure BGP Garceful Restart on both the routers. + +1. Transition from Peer-level helper to Global Restarting +2. Transition from Peer-level helper to Global inherit helper +3. Transition from Peer-level restarting to Global inherit helper +4. Default GR functional mode is Helper. +5. Verify that the restarting node sets "R" bit while sending the + BGP open messages after the node restart, only if GR is enabled. +6. Verify if restarting node resets R bit in BGP open message + during normal BGP session flaps as well, even when GR restarting + mode is enabled. Here link flap happen due to interface UP/DOWN. +7. Verify if restarting node resets R bit in BGP + open message during normal BGP session flaps when GR is disabled. +8. Verify that restarting nodes set "F" bit while sending + the BGP open messages after it restarts, only when BGP GR is enabled. +9. Verify that only GR helper routers keep the stale + route entries, not any GR disabled router. +10. Verify that GR helper routers keeps all the routes received + from restarting node if both the routers are configured as + GR restarting node. +11. Verify that GR helper routers delete all the routes + received from a node if both the routers are configured as GR + helper node. +12. After BGP neighborship is established and GR capability is exchanged, + transition restarting router to disabled state and vice versa. +13. After BGP neighborship is established and GR capability is exchanged, + transition restarting router to disabled state and vice versa. +14. Verify that restarting nodes reset "F" bit while sending + the BGP open messages after it's restarts, when BGP GR is **NOT** enabled. +15. Verify that only GR helper routers keep the stale + route entries, not any GR disabled router. +16. Transition from Global Restarting to Disable and then Global + Disable to Restarting. +17. Transition from Global Helper to Disable and then Global + Disable to Helper. +18. Transition from Global Restart to Helper and then Global + Helper to Restart, Global Mode : GR Restarting + PerPeer Mode : GR Helper + GR Mode effective : GR Helper +19. Transition from Peer-level helper to Global Restarting, + Global Mode : GR Restarting + PerPeer Mode : GR Restarting + GR Mode effective : GR Restarting +20. Transition from Peer-level restart to Global Restart + Global Mode : GR Restarting + PerPeer Mode : GR Restarting + GR Mode effective : GR Restarting +21. Transition from Peer-level disabled to Global Restart + Global Mode : GR Restarting + PerPeer Mode : GR Disabled + GR Mode effective : GR Disabled +22. Peer-level inherit from Global Restarting + Global Mode : GR Restart + PerPeer Mode : None + GR Mode effective : GR Restart +23. Transition from Peer-level disbale to Global inherit helper + Global Mode : None + PerPeer Mode : GR Disable + GR Mode effective : GR Disable + +These tests have been broken up into 4 sub python scripts because +the totality of this run was fairly significant. +""" + +import os +import sys +import time +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("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +# Import topoJson from lib, to create topology and initial configuration +from lib.topojson import build_config_from_json +from lib.bgp import ( + clear_bgp, + verify_bgp_rib, + verify_graceful_restart, + create_router_bgp, + verify_r_bit, + verify_f_bit, + verify_bgp_convergence, + verify_bgp_convergence_from_running_config, +) + +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, + shutdown_bringup_interface, + step, + get_frr_ipv6_linklocal, + required_linux_kernel_version, +) + +pytestmark = [pytest.mark.bgpd] + + +# Global variables +NEXT_HOP_IP = {"ipv4": "192.168.1.10", "ipv6": "fd00:0:0:1::10"} +NEXT_HOP_IP_1 = {"ipv4": "192.168.0.1", "ipv6": "fd00::1"} +NEXT_HOP_IP_2 = {"ipv4": "192.168.0.2", "ipv6": "fd00::2"} +BGP_CONVERGENCE = False +GR_RESTART_TIMER = 20 +PREFERRED_NEXT_HOP = "link_local" + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + global ADDR_TYPES + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.16") + if result is not True: + pytest.skip("Kernel requirements are not met") + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_gr_topojson_topo1.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + ADDR_TYPES = check_address_types() + + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): + """ + This function groups the repetitive function calls into one function. + """ + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][peer]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][dut]["links"]["r2-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + return True + + +def next_hop_per_address_family( + tgen, dut, peer, addr_type, next_hop_dict, preferred_next_hop=PREFERRED_NEXT_HOP +): + """ + This function returns link_local or global next_hop per address-family + """ + + intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"] + if addr_type == "ipv6" and "link_local" in preferred_next_hop: + next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface) + else: + next_hop = next_hop_dict[addr_type] + + return next_hop + + +def test_BGP_GR_TC_8_p1(request): + """ + Test Objective : Verify that restarting nodes set "F" bit while sending + the BGP open messages after it restarts, only when BGP GR is enabled. + """ + + 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) + + logger.info( + "[Phase 1] : Test Setup" " [Restart Mode]R1-----R2[Restart Mode] initialized " + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "graceful-restart": {"preserve-fw-state": True}, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + }, + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {"graceful-restart": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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 + ) + + # Verifying BGP RIB routes + dut = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + protocol = "bgp" + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Phase 2] : R1 goes for reload ") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Phase 3] : R1 is about to come up now ") + start_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ") + + 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_r_bit(tgen, topo, addr_type, input_dict, dut="r2", peer="r1") + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_f_bit(tgen, topo, addr_type, input_dict, dut="r2", peer="r1") + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + 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_topo1/test_bgp_gr_functionality_topo1.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py index 56f6e1a3be..0c3ff6451e 100644 --- a/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1.py +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-3.py @@ -85,6 +85,9 @@ Basic Common Test steps for all the test case below : Global Mode : None PerPeer Mode : GR Disable GR Mode effective : GR Disable + +These tests have been broken up into 4 sub python scripts because +the totality of this run was fairly significant. """ import os @@ -519,1165 +522,6 @@ def BGP_GR_TC_50_p1(request): write_test_footer(tc_name) -def test_BGP_GR_TC_51_p1(request): - """ - Test Objective : Transition from Peer-level restarting to Global inherit helper - Global Mode : None - PerPeer Mode : GR Restart - 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 at per Peer-level for R2") - - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - } - } - }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - step("Verify on R2 that R1 advertises GR capabilities as a restarting node") - - 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 - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r2", 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 that R1 keeps the stale entries in FIB & R2 keeps stale entries in RIB & FIB" - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_bgp_rib(tgen, addr_type, "r2", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - step("Bring up BGP on R1 and remove Peer-level GR config") - - start_router_daemons(tgen, "r1", ["bgpd"]) - - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": False} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": False} - } - } - } - } - }, - } - } - } - } - - result = create_router_bgp(tgen, topo, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - for addr_type in ADDR_TYPES: - neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] - clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) - - result = verify_bgp_convergence_from_running_config(tgen) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - step("Verify on R2 that R1 advertises GR capabilities as a helper node") - - input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - 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 - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - step("Kill BGPd on R2") - - kill_router_daemons(tgen, "r2", ["bgpd"]) - - step( - "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - step("Start BGP on R2") - - start_router_daemons(tgen, "r2", ["bgpd"]) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_53_p1(request): - """ - Test Objective : Default GR functional mode is Helper. - Global Mode : None - PerPeer Mode : None - GR Mode effective : GR Helper - - """ - - 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 R2 as global restarting node") - - input_dict = {"r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}} - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - step( - "Verify on R2 that R1 advertises GR capabilities as a helper node based on inherit" - ) - - input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - 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 - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - step("Kill BGPd on R2") - - kill_router_daemons(tgen, "r2", ["bgpd"]) - - step( - "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" - ) - - for addr_type in ADDR_TYPES: - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - next_hop = next_hop_per_address_family( - tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - step("Start BGP on R2") - - start_router_daemons(tgen, "r2", ["bgpd"]) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_4_p0(request): - """ - Test Objective : Verify that the restarting node sets "R" bit while sending the - BGP open messages after the node restart, only if GR is enabled. - """ - - 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) - - logger.info( - "[Phase 1] : Test Setup" " [Restart Mode]R1-----R2[Helper Mode] initialized " - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - } - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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 - ) - - # Verifying BGP RIB routes - dut = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - protocol = "bgp" - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Phase 2] : R2 goes for reload ") - - kill_router_daemons(tgen, "r2", ["bgpd"]) - - logger.info( - "[Phase 3] : R2 is still down, restart time {} sec." - "So time verify the routes are present in BGP RIB and ZEBRA ".format( - GR_RESTART_TIMER - ) - ) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib( - tgen, addr_type, dut, input_topo, next_hop, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes - result = verify_rib( - tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - logger.info("[Phase 5] : R2 is about to come up now ") - start_router_daemons(tgen, "r2", ["bgpd"]) - - logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ") - - 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_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2") - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_5_1_2_p1(request): - """ - Test Objective : Verify if restarting node resets R bit in BGP open message - during normal BGP session flaps as well, even when GR restarting mode is enabled. - Here link flap happen due to interface UP/DOWN. - - """ - 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) - - logger.info( - "[Phase 1] : Test Setup" " [Restart Mode]R1-----R2[Restart Mode] initialized " - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - } - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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 - ) - - # Verifying BGP RIB routes - dut = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - protocol = "bgp" - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Phase 2] : Now flap the link running the BGP session ") - # Shutdown interface - intf = "r2-r1-eth0" - shutdown_bringup_interface(tgen, "r2", intf) - - # Bring up Interface - shutdown_bringup_interface(tgen, "r2", intf, ifaceaction=True) - - 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_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2") - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Phase 2] : Restart BGPd on router R2. ") - kill_router_daemons(tgen, "r2", ["bgpd"]) - - start_router_daemons(tgen, "r2", ["bgpd"]) - - logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ") - - 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_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r2") - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_6_1_2_p1(request): - """ - Test Objective : Verify if restarting node resets R bit in BGP - open message during normal BGP session flaps when GR is disabled. - """ - - 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) - - logger.info( - "[Phase 1] : Test Setup" "[Restart Mode]R1-----R2[Helper Mode] initialized " - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - } - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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 - ) - - # Verifying BGP RIB routes - dut = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - protocol = "bgp" - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Phase 1] : Changing mode" "[Disable Mode]R1-----R2[Helper Mode]") - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - } - } - } - } - - result = create_router_bgp(tgen, topo, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - for addr_type in ADDR_TYPES: - neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] - clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) - - result = verify_bgp_convergence_from_running_config(tgen) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - # Verify GR stats - input_dict = { - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - } - } - }, - } - - # here the verify_graceful_restart fro the neighbor would be - # "NotReceived" as the latest GR config is not yet applied. - 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 - ) - - logger.info("[Phase 2] : Now flap the link running the BGP session ") - # Shutdown interface - intf = "r2-r1-eth0" - shutdown_bringup_interface(tgen, "r2", intf) - - # Bring up Interface - shutdown_bringup_interface(tgen, "r2", intf, ifaceaction=True) - - 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_r_bit( - tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format( - tc_name, result - ) - - logger.info("Restart BGPd on R2 ") - kill_router_daemons(tgen, "r2", ["bgpd"]) - - start_router_daemons(tgen, "r2", ["bgpd"]) - - 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_r_bit( - tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r2: R-bit is set to True\n Error: {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_8_p1(request): - """ - Test Objective : Verify that restarting nodes set "F" bit while sending - the BGP open messages after it restarts, only when BGP GR is enabled. - """ - - 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) - - logger.info( - "[Phase 1] : Test Setup" " [Restart Mode]R1-----R2[Restart Mode] initialized " - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "graceful-restart": {"preserve-fw-state": True}, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - }, - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2-link1": {"graceful-restart": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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 - ) - - # Verifying BGP RIB routes - dut = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo, next_hop) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - protocol = "bgp" - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Phase 2] : R1 goes for reload ") - - kill_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Phase 3] : R1 is about to come up now ") - start_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Phase 4] : R2 is UP now, so time to collect GR stats ") - - 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_r_bit(tgen, topo, addr_type, input_dict, dut="r2", peer="r1") - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_f_bit(tgen, topo, addr_type, input_dict, dut="r2", peer="r1") - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - def test_BGP_GR_TC_19_p1(request): """ Test Objective : Verify that GR helper routers keeps all the routes received @@ -3904,1165 +2748,6 @@ def test_BGP_GR_TC_45_p1(request): write_test_footer(tc_name) -def test_BGP_GR_TC_46_p1(request): - """ - Test Objective : transition from Peer-level helper to Global Restarting - Global Mode : GR Restarting - PerPeer Mode : GR Helper - GR Mode effective : GR Helper - - """ - - 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 and R2 as GR restarting node in global" - " and helper in per-Peer-level" - ) - - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-helper": True} - } - } - } - } - }, - }, - } - }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - step("Verify on R2 that R1 advertises GR capabilities as a restarting node") - - 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 = "r2" - peer = "r1" - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - 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 = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - 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 R2") - - kill_router_daemons(tgen, "r2", ["bgpd"]) - - step( - "Verify that R1 keeps the stale entries in RIB & FIB and R2 keeps stale entries in FIB using" - ) - - for addr_type in ADDR_TYPES: - dut = "r2" - peer = "r1" - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - 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 = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - 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( - "Bring up BGP on R1 and remove Peer-level GR config" - " from R1 following by a session reset" - ) - - start_router_daemons(tgen, "r2", ["bgpd"]) - - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-helper": False} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-helper": False} - } - } - } - } - }, - } - } - } - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - step("Verify on R2 that R1 advertises GR capabilities as a restarting node") - - input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - 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 Routes are still present \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 Routes are still present \n Error {}".format( - tc_name, result - ) - - step("Kill BGP on R1") - - kill_router_daemons(tgen, "r1", ["bgpd"]) - - step( - "Verify that R1 keeps the stale entries in FIB command 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 Routes are still present \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 Routes are still present \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_47_p1(request): - """ - Test Objective : transition from Peer-level restart to Global Restart - Global Mode : GR Restarting - PerPeer Mode : GR Restarting - GR Mode effective : GR Restarting - - """ - - 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 and R2 as GR restarting node in global and per-Peer-level") - - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": True} - } - } - } - } - }, - }, - } - }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - step("Verify on R2 that R1 advertises GR capabilities as a restarting node") - - 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 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) - - step( - "Bring up BGP on R1 and remove Peer-level GR" - " config from R1 following by a session reset" - ) - - start_router_daemons(tgen, "r1", ["bgpd"]) - - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": False} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart": False} - } - } - } - } - }, - } - } - } - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - step("Verify on R2 that R1 still advertises GR capabilities as a restarting node") - - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - } - } - }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - 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 Routes are still present \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 Routes are still present \n Error {}".format( - tc_name, result - ) - - step("Kill BGP on 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 Routes are still present \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 Routes are still present \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_48_p1(request): - """ - Test Objective : transition from Peer-level disabled to Global Restart - Global Mode : GR Restarting - PerPeer Mode : GR Disabled - GR Mode effective : GR Disabled - - """ - - 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 and" - " GR Disabled in per-Peer-level" - ) - - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - }, - } - }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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 " - "r1: routes are still present in ZEBRA\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, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r2: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - result = verify_rib( - tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r2: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - - step("Bring up BGP on R1 and remove Peer-level GR config from R1") - - start_router_daemons(tgen, "r1", ["bgpd"]) - - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": False} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": False} - } - } - } - } - }, - } - } - } - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - step("Verify on R2 that R1 advertises GR capabilities as a restarting node") - - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - } - } - }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, - } - - 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 Routes are still present \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 Routes are still present \n Error {}".format( - tc_name, result - ) - - step("Kill BGP on 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 Routes are still present \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 Routes are still present \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_49_p1(request): - """ - Test Objective : Peer-level inherit from Global 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": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - "r2": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - step( - "Verify that R2 receives GR restarting capabilities" - " from R1 based on inheritence" - ) - - 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) - - write_test_footer(tc_name) - - -def BGP_GR_TC_52_p1(request): - """ - Test Objective : Transition from Peer-level disbale to Global inherit helper - Global Mode : None - PerPeer Mode : GR Disable - GR Mode effective : GR Disable - - """ - - 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 disabled node at per Peer-level for R2" - " & R2 as GR restarting node" - ) - - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": True} - } - } - } - } - }, - } - } - }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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 = "r2" - peer = "r1" - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - 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 = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - 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 R2") - - kill_router_daemons(tgen, "r2", ["bgpd"]) - - step( - "Verify that R2 keeps the stale entries in FIB & R1 doesn't keep RIB & FIB entries." - ) - - for addr_type in ADDR_TYPES: - dut = "r2" - peer = "r1" - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - 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 = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - result = verify_bgp_rib( - tgen, addr_type, dut, input_topo, next_hop, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - result = verify_rib( - tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - - step("Bring up BGP on R2 and remove Peer-level GR config from R1") - - start_router_daemons(tgen, "r2", ["bgpd"]) - - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": False} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1-link1": {"graceful-restart-disable": False} - } - } - } - } - }, - } - } - } - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - step( - "Verify on R2 that R1 advertises GR capabilities as a helper node from global inherit" - ) - - input_dict = { - "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - 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 = "r2" - peer = "r1" - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} :Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - dut = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - 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 Routes are still present \n Error {}".format( - tc_name, result - ) - - step("Kill BGP on R2") - - kill_router_daemons(tgen, "r2", ["bgpd"]) - - step( - "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" - ) - - for addr_type in ADDR_TYPES: - dut = "r2" - peer = "r1" - protocol = "bgp" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_1 - ) - input_topo = {"r1": topo["routers"]["r1"]} - result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) - assert ( - result is True - ), "Testcase {} :Failed \n Routes are still present \n Error {}".format( - tc_name, result - ) - - dut = "r1" - peer = "r2" - next_hop = next_hop_per_address_family( - tgen, dut, peer, addr_type, NEXT_HOP_IP_2 - ) - input_topo = {"r2": topo["routers"]["r2"]} - 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 Routes are still present \n Error {}".format( - tc_name, result - ) - - 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_topo1/test_bgp_gr_functionality_topo1-4.py b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py new file mode 100644 index 0000000000..791ca37eae --- /dev/null +++ b/tests/topotests/bgp_gr_functionality_topo1/test_bgp_gr_functionality_topo1-4.py @@ -0,0 +1,1686 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF") +# in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test BGP Gracefull Restart functionality. +Basic Common Test steps for all the test case below : +- Create topology (setup module) + Creating 2 routers topology, r1, r2 in IBGP +- Bring up topology +- Verify for bgp to converge +- Configure BGP Garceful Restart on both the routers. + +1. Transition from Peer-level helper to Global Restarting +2. Transition from Peer-level helper to Global inherit helper +3. Transition from Peer-level restarting to Global inherit helper +4. Default GR functional mode is Helper. +5. Verify that the restarting node sets "R" bit while sending the + BGP open messages after the node restart, only if GR is enabled. +6. Verify if restarting node resets R bit in BGP open message + during normal BGP session flaps as well, even when GR restarting + mode is enabled. Here link flap happen due to interface UP/DOWN. +7. Verify if restarting node resets R bit in BGP + open message during normal BGP session flaps when GR is disabled. +8. Verify that restarting nodes set "F" bit while sending + the BGP open messages after it restarts, only when BGP GR is enabled. +9. Verify that only GR helper routers keep the stale + route entries, not any GR disabled router. +10. Verify that GR helper routers keeps all the routes received + from restarting node if both the routers are configured as + GR restarting node. +11. Verify that GR helper routers delete all the routes + received from a node if both the routers are configured as GR + helper node. +12. After BGP neighborship is established and GR capability is exchanged, + transition restarting router to disabled state and vice versa. +13. After BGP neighborship is established and GR capability is exchanged, + transition restarting router to disabled state and vice versa. +14. Verify that restarting nodes reset "F" bit while sending + the BGP open messages after it's restarts, when BGP GR is **NOT** enabled. +15. Verify that only GR helper routers keep the stale + route entries, not any GR disabled router. +16. Transition from Global Restarting to Disable and then Global + Disable to Restarting. +17. Transition from Global Helper to Disable and then Global + Disable to Helper. +18. Transition from Global Restart to Helper and then Global + Helper to Restart, Global Mode : GR Restarting + PerPeer Mode : GR Helper + GR Mode effective : GR Helper +19. Transition from Peer-level helper to Global Restarting, + Global Mode : GR Restarting + PerPeer Mode : GR Restarting + GR Mode effective : GR Restarting +20. Transition from Peer-level restart to Global Restart + Global Mode : GR Restarting + PerPeer Mode : GR Restarting + GR Mode effective : GR Restarting +21. Transition from Peer-level disabled to Global Restart + Global Mode : GR Restarting + PerPeer Mode : GR Disabled + GR Mode effective : GR Disabled +22. Peer-level inherit from Global Restarting + Global Mode : GR Restart + PerPeer Mode : None + GR Mode effective : GR Restart +23. Transition from Peer-level disbale to Global inherit helper + Global Mode : None + PerPeer Mode : GR Disable + GR Mode effective : GR Disable + +These tests have been broken up into 4 sub python scripts because +the totality of this run was fairly significant. +""" + +import os +import sys +import time +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("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +# Import topoJson from lib, to create topology and initial configuration +from lib.topojson import build_config_from_json +from lib.bgp import ( + clear_bgp, + verify_bgp_rib, + verify_graceful_restart, + create_router_bgp, + verify_r_bit, + verify_f_bit, + verify_bgp_convergence, + verify_bgp_convergence_from_running_config, +) + +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, + shutdown_bringup_interface, + step, + get_frr_ipv6_linklocal, + required_linux_kernel_version, +) + +pytestmark = [pytest.mark.bgpd] + + +# Global variables +NEXT_HOP_IP = {"ipv4": "192.168.1.10", "ipv6": "fd00:0:0:1::10"} +NEXT_HOP_IP_1 = {"ipv4": "192.168.0.1", "ipv6": "fd00::1"} +NEXT_HOP_IP_2 = {"ipv4": "192.168.0.2", "ipv6": "fd00::2"} +BGP_CONVERGENCE = False +GR_RESTART_TIMER = 20 +PREFERRED_NEXT_HOP = "link_local" + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + global ADDR_TYPES + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.16") + if result is not True: + pytest.skip("Kernel requirements are not met") + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_gr_topojson_topo1.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Api call verify whether BGP is converged + ADDR_TYPES = check_address_types() + + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): + """ + This function groups the repetitive function calls into one function. + """ + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][peer]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][dut]["links"]["r2-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + return True + + +def next_hop_per_address_family( + tgen, dut, peer, addr_type, next_hop_dict, preferred_next_hop=PREFERRED_NEXT_HOP +): + """ + This function returns link_local or global next_hop per address-family + """ + + intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"] + if addr_type == "ipv6" and "link_local" in preferred_next_hop: + next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface) + else: + next_hop = next_hop_dict[addr_type] + + return next_hop + + +def BGP_GR_TC_50_p1(request): + """ + Test Objective : Transition from Peer-level helper to Global inherit helper + Global Mode : None + PerPeer Mode : Helper + GR Mode effective : GR Helper + + """ + + 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 helper node at per Peer-level for R2" + " and configure R2 as global restarting node." + ) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step("Verify on R2 that R1 advertises GR capabilities as a helper node") + + 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 + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Kill BGP on R2") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + step( + "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Bring up BGP on R2 and remove Peer-level GR config from R1 ") + + start_router_daemons(tgen, "r2", ["bgpd"]) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": False} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": False} + } + } + } + } + }, + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, "r1", neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + step("Verify on R2 that R1 still advertises GR capabilities as a helper node") + + input_dict = { + "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + 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 + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Kill BGP on R2") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + step( + "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, "r2", "r1", addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, "r2", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + next_hop = next_hop_per_address_family( + tgen, "r1", "r2", addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib(tgen, addr_type, "r1", input_topo, next_hop) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_rib(tgen, addr_type, "r1", input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} : Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Start BGP on R2") + + start_router_daemons(tgen, "r2", ["bgpd"]) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_46_p1(request): + """ + Test Objective : transition from Peer-level helper to Global Restarting + Global Mode : GR Restarting + PerPeer Mode : GR Helper + GR Mode effective : GR Helper + + """ + + 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 and R2 as GR restarting node in global" + " and helper in per-Peer-level" + ) + + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": True} + } + } + } + } + }, + }, + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step("Verify on R2 that R1 advertises GR capabilities as a restarting node") + + 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 = "r2" + peer = "r1" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + 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 = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + 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 R2") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + step( + "Verify that R1 keeps the stale entries in RIB & FIB and R2 keeps stale entries in FIB using" + ) + + for addr_type in ADDR_TYPES: + dut = "r2" + peer = "r1" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + 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 = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + 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( + "Bring up BGP on R1 and remove Peer-level GR config" + " from R1 following by a session reset" + ) + + start_router_daemons(tgen, "r2", ["bgpd"]) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": False} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-helper": False} + } + } + } + } + }, + } + } + } + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step("Verify on R2 that R1 advertises GR capabilities as a restarting node") + + input_dict = { + "r1": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + 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 Routes are still present \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 Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Kill BGP on R1") + + kill_router_daemons(tgen, "r1", ["bgpd"]) + + step( + "Verify that R1 keeps the stale entries in FIB command 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 Routes are still present \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 Routes are still present \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_47_p1(request): + """ + Test Objective : transition from Peer-level restart to Global Restart + Global Mode : GR Restarting + PerPeer Mode : GR Restarting + GR Mode effective : GR Restarting + + """ + + 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 and R2 as GR restarting node in global and per-Peer-level") + + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": True} + } + } + } + } + }, + }, + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step("Verify on R2 that R1 advertises GR capabilities as a restarting node") + + 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 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) + + step( + "Bring up BGP on R1 and remove Peer-level GR" + " config from R1 following by a session reset" + ) + + start_router_daemons(tgen, "r1", ["bgpd"]) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": False} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart": False} + } + } + } + } + }, + } + } + } + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step("Verify on R2 that R1 still advertises GR capabilities as a restarting node") + + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + 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 Routes are still present \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 Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Kill BGP on 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 Routes are still present \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 Routes are still present \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_48_p1(request): + """ + Test Objective : transition from Peer-level disabled to Global Restart + Global Mode : GR Restarting + PerPeer Mode : GR Disabled + GR Mode effective : GR Disabled + + """ + + 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 and" + " GR Disabled in per-Peer-level" + ) + + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": True} + } + } + } + } + }, + }, + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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 " + "r1: routes are still present in ZEBRA\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, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "r2: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "r2: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + + step("Bring up BGP on R1 and remove Peer-level GR config from R1") + + start_router_daemons(tgen, "r1", ["bgpd"]) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": False} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": False} + } + } + } + } + }, + } + } + } + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step("Verify on R2 that R1 advertises GR capabilities as a restarting node") + + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, + } + + 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 Routes are still present \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 Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Kill BGP on 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 Routes are still present \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 Routes are still present \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_49_p1(request): + """ + Test Objective : Peer-level inherit from Global 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": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + "r2": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step( + "Verify that R2 receives GR restarting capabilities" + " from R1 based on inheritence" + ) + + 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) + + write_test_footer(tc_name) + + +def BGP_GR_TC_52_p1(request): + """ + Test Objective : Transition from Peer-level disbale to Global inherit helper + Global Mode : None + PerPeer Mode : GR Disable + GR Mode effective : GR Disable + + """ + + 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 disabled node at per Peer-level for R2" + " & R2 as GR restarting node" + ) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": True} + } + } + } + } + }, + } + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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 = "r2" + peer = "r1" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + 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 = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + 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 R2") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + step( + "Verify that R2 keeps the stale entries in FIB & R1 doesn't keep RIB & FIB entries." + ) + + for addr_type in ADDR_TYPES: + dut = "r2" + peer = "r1" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + 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 = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + result = verify_bgp_rib( + tgen, addr_type, dut, input_topo, next_hop, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + result = verify_rib( + tgen, addr_type, dut, input_topo, next_hop, protocol, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + + step("Bring up BGP on R2 and remove Peer-level GR config from R1") + + start_router_daemons(tgen, "r2", ["bgpd"]) + + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": False} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {"graceful-restart-disable": False} + } + } + } + } + }, + } + } + } + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + step( + "Verify on R2 that R1 advertises GR capabilities as a helper node from global inherit" + ) + + input_dict = { + "r1": {"bgp": {"graceful-restart": {"graceful-restart-helper": True}}}, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + 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 = "r2" + peer = "r1" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} :Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + dut = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + 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 Routes are still present \n Error {}".format( + tc_name, result + ) + + step("Kill BGP on R2") + + kill_router_daemons(tgen, "r2", ["bgpd"]) + + step( + "Verify that R2 keeps the stale entries in FIB & R1 keeps stale entries in RIB & FIB" + ) + + for addr_type in ADDR_TYPES: + dut = "r2" + peer = "r1" + protocol = "bgp" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_1 + ) + input_topo = {"r1": topo["routers"]["r1"]} + result = verify_rib(tgen, addr_type, dut, input_topo, next_hop, protocol) + assert ( + result is True + ), "Testcase {} :Failed \n Routes are still present \n Error {}".format( + tc_name, result + ) + + dut = "r1" + peer = "r2" + next_hop = next_hop_per_address_family( + tgen, dut, peer, addr_type, NEXT_HOP_IP_2 + ) + input_topo = {"r2": topo["routers"]["r2"]} + 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 Routes are still present \n Error {}".format( + tc_name, result + ) + + 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 new file mode 100644 index 0000000000..064fde1633 --- /dev/null +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-1.py @@ -0,0 +1,1515 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF") +# in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test BGP Graceful Restart functionality. +Basic Common Test steps for all the test case below : +- Create topology (setup module) + Creating 7 routers topology +- Bring up topology +- Verify for bgp to converge +- Configure BGP Graceful Restart on both the routers. + +TC_1_2: + Verify that EOR message is sent out only after initial convergence + Verify whether EOR message is received from all the peers after restart +TC_3: + Verify the selection deferral timer functionality when EOR is not sent + by the helper router +TC_11: + Verify that selection-deferral timer sets the maximum time to + avoid deadlock during which the best-path +TC_10: + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. +TC_15: + Test Objective : Test GR scenarios by enabling Graceful Restart + for multiple address families.. +TC_16: + Test Objective : Verify BGP-GR feature when restarting node + is a transit router for it's iBGP peers. +TC_18: + Test Objective : Verify that GR helper router deletes stale routes + received from restarting node, if GR capability is not present in +TC_19: + Test Objective : Verify that GR routers keeps all the routes + received from restarting node if both the routers are +TC_26: + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. +TC_28: + Test Objective : Verify if helper node goes down before restarting + node comes up online, helper node sets the R-bit to avoid dead-lock +TC_29: + Test Objective : Change timers on the fly, and + verify if it takes immediate effect. +TC_33: + Test Objective : Helper router receives same prefixes from two + different routers (GR-restarting and GR-disabled). Keeps the +TC_34_1: + Test Objective : Restarting node doesn't preserve forwarding + state, helper router should not keep the stale entries. +TC_34_2: + Test Objective : Restarting node doesn't preserve the forwarding + state verify the behaviour on helper node, if it still keeps the +TC_32: + Test Objective : Restarting node is connected to multiple helper + nodes, one of them doesn't send EOR to restarting router. Verify +TC_37: + Test Objective : Verify if helper node restarts before sending the + EOR message, restarting node doesn't wait until stale path timer +TC_30: + Test Objective : Restarting node removes stale routes from Zebra + after receiving an EOR from helper router. + +""" + +import os +import sys +import time +import pytest +from time import sleep + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +# Import topoJson from lib, to create topology and initial configuration +from lib.topojson import build_config_from_json +from lib.bgp import ( + clear_bgp, + 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, +) + +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, + step, + get_frr_ipv6_linklocal, + required_linux_kernel_version, +) + +pytestmark = [pytest.mark.bgpd] + + +# Global variables +BGP_CONVERGENCE = False +GR_RESTART_TIMER = 5 +GR_SELECT_DEFER_TIMER = 5 +GR_STALEPATH_TIMER = 5 +PREFERRED_NEXT_HOP = "link_local" +NEXT_HOP_4 = ["192.168.1.1", "192.168.4.2"] +NEXT_HOP_6 = ["fd00:0:0:1::1", "fd00:0:0:4::2"] + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.16") + if result is not True: + pytest.skip("Kernel requirements are not met") + + global ADDR_TYPES + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_gr_topojson_topo2.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Api call verify whether BGP is converged + ADDR_TYPES = check_address_types() + + for addr_type in ADDR_TYPES: + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): + """ + This function groups the repetitive function calls into one function. + """ + + logger.info("configure_gr_followed_by_clear: dut %s peer %s", dut, peer) + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][peer]["links"][dut][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][dut]["links"][peer][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + return True + + +def next_hop_per_address_family(tgen, dut, peer, addr_type, next_hop_dict): + """ + This function returns link_local or global next_hop per address-family + """ + + intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"] + if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: + next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface) + else: + next_hop = next_hop_dict[addr_type] + + return next_hop + + +def test_BGP_GR_TC_1_2_p0(request): + """ + Verify that EOR message is sent out only after initial convergence + Verify whether EOR message is received from all the peers after 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) + + logger.info( + "Verify EOR Sent and Received : BGP_GR_TC_1_2 >> " + "BGP GR [Helper Mode]R3-----R1[Restart Mode] " + ) + + # Configure graceful-restart + input_dict = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + "preserve-fw-state": True, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + }, + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes received from router R3 + dut = "r1" + input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("R1 goes for reload") + kill_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying RIB routes + input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("Starting bgpd process") + start_router_daemons(tgen, "r1", ["bgpd"]) + logger.info("R1 is UP Now") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes received from router R3 + input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying EOR on restarting router + result = verify_eor(tgen, topo, addr_type, input_dict, dut="r3", peer="r1") + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_3_p0(request): + """ + Verify the selection deferral timer functionality when EOR is not sent + by the helper router + """ + + 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) + + logger.info( + " Verify route download to RIB: BGP_GR_TC_3 >> " + "BGP GR [Helper Mode]R1-----R2[Restart Mode] " + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "disable-eor": True, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + }, + } + }, + "r2": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + "preserve-fw-state": True, + "timer": {"select-defer-time": GR_SELECT_DEFER_TIMER}, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": {"dest_link": {"r2": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": {"dest_link": {"r2": {"graceful-restart": True}}} + } + } + }, + }, + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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 + ) + + # Verifying BGP RIB routes received from router R1 + dut = "r2" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("R2 goes for reload ") + kill_router_daemons(tgen, "r2", ["bgpd"]) + + logger.info("R2 is about to come up now") + start_router_daemons(tgen, "r2", ["bgpd"]) + logger.info("R2 is UP Now") + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes received from router R1 + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verify EOR on restarting router + result = verify_eor( + tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r2: EOR is set to True\n Error: {}".format( + tc_name, result + ) + + logger.info( + "Waiting for selection deferral timer({} sec)..".format(GR_SELECT_DEFER_TIMER) + ) + sleep(GR_SELECT_DEFER_TIMER) + + for addr_type in ADDR_TYPES: + # Verifying RIB routes + result = verify_rib(tgen, addr_type, "r2", input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_TC_11_p0(request): + """ + Verify that selection-deferral timer sets the maximum time to + avoid deadlock during which the best-path + selection process is deferred, after a peer session was restarted + """ + + 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) + + logger.info("Verify EOR Sent after deferral timeout : BGP_GR_TC_11") + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + "select-defer-time": GR_SELECT_DEFER_TIMER, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": {"dest_link": {"r1": {"graceful-restart": True}}}, + "r3": {"dest_link": {"r1": {"graceful-restart": True}}}, + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": {"dest_link": {"r1": {"graceful-restart": True}}}, + "r3": {"dest_link": {"r1": {"graceful-restart": True}}}, + } + } + }, + }, + } + }, + "r3": { + "bgp": { + "graceful-restart": {"disable-eor": True}, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + }, + } + }, + } + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + clear_bgp(tgen, addr_type, "r1") + clear_bgp(tgen, addr_type, "r3") + + result = verify_bgp_convergence_from_running_config(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes received from router R1 + dut = "r1" + input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("R1 goes for reload") + kill_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("Starting bgpd process") + start_router_daemons(tgen, "r1", ["bgpd"]) + logger.info("R1 is UP Now") + + for addr_type in ADDR_TYPES: + # Verify EOR on restarting router + result = verify_eor( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( + tc_name, result + ) + + logger.info( + "Waiting for selection deferral timer({} sec).. ".format( + GR_SELECT_DEFER_TIMER + 2 + ) + ) + sleep(GR_SELECT_DEFER_TIMER + 2) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes received from router R1 + input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying EOR on restarting router + result = verify_eor( + tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_10_p2(request): + """ + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. + """ + + 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("Test Setup: [Helper Mode]R3-----R1[Restart Mode] initialized") + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "next_hop_self": True, + "graceful-restart": True, + "activate": "ipv6", + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "next_hop_self": True, + "graceful-restart": True, + "activate": "ipv4", + } + } + } + } + } + }, + } + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "graceful-restart-helper": True, + "activate": "ipv6", + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "graceful-restart-helper": True, + "activate": "ipv4", + } + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + step( + "Verifying GR config and operational state for addr_type {}".format( + addr_type + ) + ) + + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes + dut = "r3" + input_topo = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # verify multi address family + result = verify_gr_address_family( + tgen, + topo, + addr_type, + "ipv4Unicast", + dut="r1", + peer="r3", + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # verify multi address family + result = verify_gr_address_family( + tgen, + topo, + addr_type, + "ipv6Unicast", + dut="r1", + peer="r3", + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # verify multi address family + result = verify_gr_address_family( + tgen, + topo, + addr_type, + "ipv4Unicast", + dut="r3", + peer="r1", + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # verify multi address family + result = verify_gr_address_family( + tgen, + topo, + addr_type, + "ipv6Unicast", + dut="r3", + peer="r1", + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Killing bgpd on r1") + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + input_topo = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Starting bgpd on r1") + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + input_topo = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def BGP_GR_16_p2(request): + """ + Test Objective : Verify BGP-GR feature when restarting node + is a transit router for it's iBGP peers. + """ + + 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) + + logger.info( + "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] initialized" + ) + + # Configure graceful-restart and timers + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "graceful-restart": True, + "next_hop_self": True, + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "graceful-restart": True, + "next_hop_self": True, + } + } + } + } + } + }, + } + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info( + "[Step 2] : Test Setup " + "[Helper Mode]R3-----R1[Restart Mode]" + "--------R6[Helper Mode] initialized" + ) + + # Configure graceful-restart and timers + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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 + ) + + # Verifying BGP RIB routes + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + result = verify_bgp_convergence_from_running_config(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_18_p1(request): + """ + Test Objective : Verify that GR helper router deletes stale routes + received from restarting node, if GR capability is not present in + restarting node's OPEN message. + """ + + 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) + + logger.info( + "[Step 1] : Test Setup " "[Helper Mode]R6-----R1[Restart Mode] initialized" + ) + + # Configure graceful-restart and timers + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r6": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r6": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + } + } + }, + "r6": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r6": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r6": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r6") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r6" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info( + "[Step 2] : Test Setup " + "[Helper Mode]R6-----R1[Restart Mode]" + "--------R2[Helper Mode] initialized" + ) + + # Configure graceful-restart and timers + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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 + ) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes + dut = "r2" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Step 3] : Configure R1 to prevent sending EOR") + + # Modify graceful-restart config to prevent sending EOR + input_dict_3 = {"r1": {"bgp": {"graceful-restart": {"disable-eor": True}}}} + + result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) + + # Modify configuration to delete routes + network = {"ipv4": "101.0.20.1/32", "ipv6": "1::1/128"} + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "advertise_networks": [ + { + "network": network[addr_type], + "no_of_network": 5, + "delete": True, + } + ] + } + } + } + } + } + } + + result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Modify graceful-restart config + input_dict_3 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-disable": True} + } + }, + "r6": { + "dest_link": { + "r1": {"graceful-restart-disable": True} + } + }, + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-disable": True} + } + }, + "r6": { + "dest_link": { + "r1": {"graceful-restart-disable": True} + } + }, + } + } + }, + } + } + } + } + + result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + + logger.info("[Step 4] : Bring up the BGPd daemon on R1 for 30" " seconds..") + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + dut = "r6" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r6: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying BGP RIB routes + dut = "r2" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r2: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + logger.info(" Expected behavior: {}".format(result)) + + 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-2.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py new file mode 100644 index 0000000000..4356c4d591 --- /dev/null +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-2.py @@ -0,0 +1,1216 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF") +# in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test BGP Graceful Restart functionality. +Basic Common Test steps for all the test case below : +- Create topology (setup module) + Creating 7 routers topology +- Bring up topology +- Verify for bgp to converge +- Configure BGP Graceful Restart on both the routers. + +TC_1_2: + Verify that EOR message is sent out only after initial convergence + Verify whether EOR message is received from all the peers after restart +TC_3: + Verify the selection deferral timer functionality when EOR is not sent + by the helper router +TC_11: + Verify that selection-deferral timer sets the maximum time to + avoid deadlock during which the best-path +TC_10: + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. +TC_15: + Test Objective : Test GR scenarios by enabling Graceful Restart + for multiple address families.. +TC_16: + Test Objective : Verify BGP-GR feature when restarting node + is a transit router for it's iBGP peers. +TC_18: + Test Objective : Verify that GR helper router deletes stale routes + received from restarting node, if GR capability is not present in +TC_19: + Test Objective : Verify that GR routers keeps all the routes + received from restarting node if both the routers are +TC_26: + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. +TC_28: + Test Objective : Verify if helper node goes down before restarting + node comes up online, helper node sets the R-bit to avoid dead-lock +TC_29: + Test Objective : Change timers on the fly, and + verify if it takes immediate effect. +TC_33: + Test Objective : Helper router receives same prefixes from two + different routers (GR-restarting and GR-disabled). Keeps the +TC_34_1: + Test Objective : Restarting node doesn't preserve forwarding + state, helper router should not keep the stale entries. +TC_34_2: + Test Objective : Restarting node doesn't preserve the forwarding + state verify the behaviour on helper node, if it still keeps the +TC_32: + Test Objective : Restarting node is connected to multiple helper + nodes, one of them doesn't send EOR to restarting router. Verify +TC_37: + Test Objective : Verify if helper node restarts before sending the + EOR message, restarting node doesn't wait until stale path timer +TC_30: + Test Objective : Restarting node removes stale routes from Zebra + after receiving an EOR from helper router. + +""" + +import os +import sys +import time +import pytest +from time import sleep + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +# Import topoJson from lib, to create topology and initial configuration +from lib.topojson import build_config_from_json +from lib.bgp import ( + clear_bgp, + 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, +) + +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, + step, + get_frr_ipv6_linklocal, + required_linux_kernel_version, +) + +pytestmark = [pytest.mark.bgpd] + + +# Global variables +BGP_CONVERGENCE = False +GR_RESTART_TIMER = 5 +GR_SELECT_DEFER_TIMER = 5 +GR_STALEPATH_TIMER = 5 +PREFERRED_NEXT_HOP = "link_local" +NEXT_HOP_4 = ["192.168.1.1", "192.168.4.2"] +NEXT_HOP_6 = ["fd00:0:0:1::1", "fd00:0:0:4::2"] + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.16") + if result is not True: + pytest.skip("Kernel requirements are not met") + + global ADDR_TYPES + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_gr_topojson_topo2.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Api call verify whether BGP is converged + ADDR_TYPES = check_address_types() + + for addr_type in ADDR_TYPES: + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): + """ + This function groups the repetitive function calls into one function. + """ + + logger.info("configure_gr_followed_by_clear: dut %s peer %s", dut, peer) + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][peer]["links"][dut][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][dut]["links"][peer][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + return True + + +def next_hop_per_address_family(tgen, dut, peer, addr_type, next_hop_dict): + """ + This function returns link_local or global next_hop per address-family + """ + + intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"] + if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: + next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface) + else: + next_hop = next_hop_dict[addr_type] + + return next_hop + + +def test_BGP_GR_26_p2(request): + """ + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. + """ + + 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) + + logger.info( + "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] initialized" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "graceful-restart": True, + "next_hop_self": True, + "activate": "ipv6", + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "graceful-restart": True, + "next_hop_self": True, + "activate": "ipv4", + } + } + } + } + } + }, + } + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "graceful-restart-helper": True, + "activate": "ipv6", + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": { + "graceful-restart-helper": True, + "activate": "ipv4", + } + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r3", peer="r1" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes + dut = "r3" + input_topo = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + input_topo = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + input_topo = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_topo) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # verify multi address family + result = verify_gr_address_family( + tgen, + topo, + addr_type, + "ipv4Unicast", + dut="r1", + peer="r3", + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # verify multi address family + result = verify_gr_address_family( + tgen, + topo, + addr_type, + "ipv6Unicast", + dut="r1", + peer="r3", + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # verify multi address family + result = verify_gr_address_family( + tgen, + topo, + addr_type, + "ipv4Unicast", + dut="r3", + peer="r1", + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # verify multi address family + result = verify_gr_address_family( + tgen, + topo, + addr_type, + "ipv6Unicast", + dut="r3", + peer="r1", + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_chaos_28_p1(request): + """ + Test Objective : Verify if helper node goes down before restarting + node comes up online, helper node sets the R-bit to avoid dead-lock + till SDT expiry. + """ + + 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) + + logger.info( + "Test Case: test_BGP_GR_chaos_28 :" + "[Helper Mode]R3-----R1[Restart Mode] initialized" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + } + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Step 1] : Kill BGPd daemon on R1..") + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Step 2] : Kill BGPd daemon on R3..") + + # Kill BGPd daemon on R3 + kill_router_daemons(tgen, "r3", ["bgpd"]) + + logger.info("[Step 3] : Start BGPd daemon on R1..") + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Step 4] : Start BGPd daemon on R3..") + + # Start BGPd daemon on R3 + start_router_daemons(tgen, "r3", ["bgpd"]) + + # Verify r_bit + for addr_type in ADDR_TYPES: + result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r3", peer="r1") + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_chaos_29_p1(request): + """ + Test Objective : Change timers on the fly, and + verify if it takes immediate effect. + """ + + 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) + + logger.info( + " Test Case : test_BGP_GR_chaos_29" + " BGP GR [Helper Mode]R3-----R1[Restart Mode]" + " and [restart-time 150]R1 initialized" + ) + + # Configure graceful-restart and timers + input_dict = { + "r1": { + "bgp": { + "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER}}, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + }, + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verify graceful-restart timers + input_dict_2 = { + "r1": { + "bgp": { + "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER + 5}} + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r1": { + "bgp": { + "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER}} + } + } + } + + result = verify_graceful_restart_timers( + tgen, topo, addr_type, input_dict_2, dut="r3", peer="r1" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes before shutting down BGPd daemon + dut = "r3" + input_dict = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Step 2] : Kill BGPd daemon on R1..") + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Step 3] : Wait for {} seconds..".format(GR_RESTART_TIMER)) + + # Waiting for GR_RESTART_TIMER + sleep(GR_RESTART_TIMER) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes before shutting down BGPd daemon + input_dict = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + logger.info(" Expected behavior: {}".format(result)) + + logger.info("[Step 4] : Start BGPd daemon on R1..") + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + write_test_footer(tc_name) + + +def test_BGP_GR_chaos_33_p1(request): + """ + Test Objective : Helper router receives same prefixes from two + different routers (GR-restarting and GR-disabled). Keeps the + stale entry only for GR-restarting node(next-hop is correct). + """ + + 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) + + logger.info( + " Test Case : test_BGP_GR_chaos_33 " + "BGP GR " + "[Restart Mode]R1--R3[Helper Mode]--R4[Disabled Mode]" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + } + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {"graceful-restart-disable": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4": {"graceful-restart-disable": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Step 2] : Advertise same networks from R1 and R4..") + + # Api call to delete advertised networks + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + { + "network": "200.0.20.1/32", + "no_of_network": 2, + } + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "2001::1/128", "no_of_network": 2} + ] + } + }, + } + } + }, + "r4": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "advertise_networks": [ + {"network": "200.0.20.1/32", "no_of_network": 2} + ] + } + }, + "ipv6": { + "unicast": { + "advertise_networks": [ + {"network": "2001::1/128", "no_of_network": 2} + ] + } + }, + } + } + }, + } + + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + # Verifying RIB routes + dut = "r3" + peer1 = "r1" + peer2 = "r4" + intf1 = topo["routers"][peer1]["links"][dut]["interface"] + intf2 = topo["routers"][peer2]["links"][dut]["interface"] + + if addr_type == "ipv4": + next_hop_4 = NEXT_HOP_4 + result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_4) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + if addr_type == "ipv6": + if "link_local" in PREFERRED_NEXT_HOP: + next_hop1 = get_frr_ipv6_linklocal(tgen, peer1, intf=intf1) + next_hop2 = get_frr_ipv6_linklocal(tgen, peer2, intf=intf2) + + next_hop_6 = [next_hop1, next_hop2] + else: + next_hop_6 = NEXT_HOP_6 + + result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Step 3] : Kill BGPd daemon on R1 and R4..") + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + # Kill BGPd daemon on R4 + kill_router_daemons(tgen, "r4", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying RIB routes + next_hop_6 = ["fd00:0:0:1::1"] + if addr_type == "ipv4": + next_hop_4 = NEXT_HOP_4[0] + + result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_4) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + if addr_type == "ipv6": + if "link_local" in PREFERRED_NEXT_HOP: + next_hop_6 = get_frr_ipv6_linklocal(tgen, peer1, intf=intf1) + else: + next_hop_6 = NEXT_HOP_6[0] + + result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6) + + # Verifying RIB routes + if addr_type == "ipv4": + next_hop_4 = NEXT_HOP_4[1] + result = verify_rib( + tgen, addr_type, dut, input_dict_2, next_hop_4, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + if addr_type == "ipv6": + if "link_local" in PREFERRED_NEXT_HOP: + next_hop_6 = get_frr_ipv6_linklocal(tgen, peer2, intf=intf2) + else: + next_hop_6 = NEXT_HOP_6[1] + + result = verify_rib( + tgen, addr_type, dut, input_dict_2, next_hop_6, expected=False + ) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + logger.info("[Step 4] : Start BGPd daemon on R1 and R4..") + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + # Start BGPd daemon on R4 + start_router_daemons(tgen, "r4", ["bgpd"]) + + write_test_footer(tc_name) + + +def test_BGP_GR_chaos_34_2_p1(request): + """ + Test Objective : Restarting node doesn't preserve the forwarding + state verify the behaviour on helper node, if it still keeps the + stale routes. + """ + + 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) + + logger.info( + " Test Case : test_BGP_GR_chaos_34 " + "BGP GR " + "[Restart Mode]R1---R3[Helper Mode]" + ) + + logger.info("[Step 1] : Configure restarting" " router R1 to prevent ") + logger.info("[Step 2] : Reset the session" " between R1 and R3..") + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "graceful-restart": {"preserve-fw-state": True, "disable-eor": True}, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + }, + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verify f-bit before killing BGPd daemon + result = verify_f_bit(tgen, topo, addr_type, input_dict, "r3", "r1") + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes after starting BGPd daemon + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Step 3] : Kill BGPd daemon on R1..") + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Step 4] : Withdraw/delete the prefixes " "originated from R1..") + + # Api call to delete advertised networks + network = {"ipv4": "101.0.20.1/32", "ipv6": "1::1/128"} + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "advertise_networks": [ + { + "network": network[addr_type], + "no_of_network": 5, + "delete": True, + } + ] + } + } + } + } + } + } + + result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Step 5] : Remove the CLI from R1's config to " "set the F-bit..") + + # Modify graceful-restart config not to set f-bit + # and write to /etc/frr + input_dict_2 = {"r1": {"bgp": {"graceful-restart": {"preserve-fw-state": False}}}} + + result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + + logger.info("[Step 6] : Bring up the BGPd daemon on R1 again..") + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verify f-bit after starting BGPd daemon + result = verify_f_bit( + tgen, topo, addr_type, input_dict, "r3", "r1", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format( + tc_name, result + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying BGP RIB routes after starting BGPd daemon + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + logger.info(" Expected behavior: {}".format(result)) + + 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-3.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py new file mode 100644 index 0000000000..86d676dd8b --- /dev/null +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-3.py @@ -0,0 +1,1367 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF") +# in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test BGP Graceful Restart functionality. +Basic Common Test steps for all the test case below : +- Create topology (setup module) + Creating 7 routers topology +- Bring up topology +- Verify for bgp to converge +- Configure BGP Graceful Restart on both the routers. + +TC_1_2: + Verify that EOR message is sent out only after initial convergence + Verify whether EOR message is received from all the peers after restart +TC_3: + Verify the selection deferral timer functionality when EOR is not sent + by the helper router +TC_11: + Verify that selection-deferral timer sets the maximum time to + avoid deadlock during which the best-path +TC_10: + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. +TC_15: + Test Objective : Test GR scenarios by enabling Graceful Restart + for multiple address families.. +TC_16: + Test Objective : Verify BGP-GR feature when restarting node + is a transit router for it's iBGP peers. +TC_18: + Test Objective : Verify that GR helper router deletes stale routes + received from restarting node, if GR capability is not present in +TC_19: + Test Objective : Verify that GR routers keeps all the routes + received from restarting node if both the routers are +TC_26: + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. +TC_28: + Test Objective : Verify if helper node goes down before restarting + node comes up online, helper node sets the R-bit to avoid dead-lock +TC_29: + Test Objective : Change timers on the fly, and + verify if it takes immediate effect. +TC_33: + Test Objective : Helper router receives same prefixes from two + different routers (GR-restarting and GR-disabled). Keeps the +TC_34_1: + Test Objective : Restarting node doesn't preserve forwarding + state, helper router should not keep the stale entries. +TC_34_2: + Test Objective : Restarting node doesn't preserve the forwarding + state verify the behaviour on helper node, if it still keeps the +TC_32: + Test Objective : Restarting node is connected to multiple helper + nodes, one of them doesn't send EOR to restarting router. Verify +TC_37: + Test Objective : Verify if helper node restarts before sending the + EOR message, restarting node doesn't wait until stale path timer +TC_30: + Test Objective : Restarting node removes stale routes from Zebra + after receiving an EOR from helper router. + +""" + +import os +import sys +import time +import pytest +from time import sleep + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +# Import topoJson from lib, to create topology and initial configuration +from lib.topojson import build_config_from_json +from lib.bgp import ( + clear_bgp, + 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, +) + +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, + step, + get_frr_ipv6_linklocal, + required_linux_kernel_version, +) + +pytestmark = [pytest.mark.bgpd] + + +# Global variables +BGP_CONVERGENCE = False +GR_RESTART_TIMER = 5 +GR_SELECT_DEFER_TIMER = 5 +GR_STALEPATH_TIMER = 5 +PREFERRED_NEXT_HOP = "link_local" +NEXT_HOP_4 = ["192.168.1.1", "192.168.4.2"] +NEXT_HOP_6 = ["fd00:0:0:1::1", "fd00:0:0:4::2"] + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.16") + if result is not True: + pytest.skip("Kernel requirements are not met") + + global ADDR_TYPES + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_gr_topojson_topo2.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Api call verify whether BGP is converged + ADDR_TYPES = check_address_types() + + for addr_type in ADDR_TYPES: + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): + """ + This function groups the repetitive function calls into one function. + """ + + logger.info("configure_gr_followed_by_clear: dut %s peer %s", dut, peer) + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][peer]["links"][dut][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][dut]["links"][peer][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + return True + + +def next_hop_per_address_family(tgen, dut, peer, addr_type, next_hop_dict): + """ + This function returns link_local or global next_hop per address-family + """ + + intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"] + if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: + next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface) + else: + next_hop = next_hop_dict[addr_type] + + return next_hop + + +def test_BGP_GR_chaos_34_1_p1(request): + """ + Test Objective : Restarting node doesn't preserve forwarding + state, helper router should not keep the stale entries. + """ + + 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) + + logger.info( + " Test Case : test_BGP_GR_chaos_31 " + "BGP GR " + "[Restart Mode]R1---R3[Helper Mode]" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "graceful-restart": { + "preserve-fw-state": True, + "timer": {"restart-time": GR_RESTART_TIMER}, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + }, + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes after starting BGPd daemon + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info( + "[Step 1] : Remove the preserve-fw-state command" + " from restarting node R1's config" + ) + + # Configure graceful-restart to set f-bit as False + input_dict_2 = {"r1": {"bgp": {"graceful-restart": {"preserve-fw-state": False}}}} + + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + logger.info("[Step 2] : Reset the session between R1 and R3..") + + # Reset sessions + for addr_type in ADDR_TYPES: + clear_bgp(tgen, addr_type, "r1") + + result = verify_bgp_convergence_from_running_config(tgen, topo) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + # Verify f-bit after starting BGPd daemon + result = verify_f_bit( + tgen, topo, addr_type, input_dict_2, "r3", "r1", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format( + tc_name, result + ) + logger.info(" Expected behavior: {}".format(result)) + + logger.info("[Step 3] : Kill BGPd daemon on R1..") + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + # Waiting for GR_RESTART_TIMER + logger.info("Waiting for {} sec..".format(GR_RESTART_TIMER)) + sleep(GR_RESTART_TIMER) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + input_dict = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + write_test_footer(tc_name) + + +def test_BGP_GR_chaos_32_p1(request): + """ + Test Objective : Restarting node is connected to multiple helper + nodes, one of them doesn't send EOR to restarting router. Verify + that only after SDT restarting node send EOR to all helper peers + excluding the prefixes originated by faulty router. + """ + + 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) + + logger.info( + " Test Case : test_BGP_GR_chaos_32 " + "BGP GR " + "[Restart Mode]R1---R3&R5[Helper Mode]" + ) + + logger.info( + "[Step 1] : Change the mode on R1 be a restarting" " node on global level" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "graceful-restart": {"graceful-restart": True}, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"next_hop_self": True}}}, + "r5": {"dest_link": {"r1": {"graceful-restart": True}}}, + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"next_hop_self": True}}}, + "r5": {"dest_link": {"r1": {"graceful-restart": True}}}, + } + } + }, + }, + } + }, + "r5": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r5": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r5": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r5") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r5" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes after starting BGPd daemon + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r5"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Step 2] : Kill BGPd daemon on R1..") + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Step 3] : Withdraw all the advertised prefixes from R5") + + # Api call to delete advertised networks + network = {"ipv4": "105.0.20.1/32", "ipv6": "5::1/128"} + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r5": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "advertise_networks": [ + { + "network": network[addr_type], + "no_of_network": 5, + "delete": True, + } + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + logger.info( + "[Step 4] : Stop the helper router R5 from sending EOR" " message using CLI" + ) + + # Modify graceful-restart config to prevent sending EOR + input_dict_3 = {"r5": {"bgp": {"graceful-restart": {"disable-eor": True}}}} + + result = create_router_bgp(tgen, topo, input_dict_3) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + logger.info("[Step 5] : Bring up the BGPd daemon on R1..") + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verify EOR is disabled + result = verify_eor( + tgen, topo, addr_type, input_dict_3, dut="r5", peer="r1", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r5: EOR is set to TRUE\n Error: {}".format( + tc_name, result + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying BGP RIB routes after starting BGPd daemon + input_dict_1 = {key: topo["routers"][key] for key in ["r5"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + logger.info(" Expected behavior: {}".format(result)) + + write_test_footer(tc_name) + + +def test_BGP_GR_chaos_37_p1(request): + """ + Test Objective : Verify if helper node restarts before sending the + EOR message, restarting node doesn't wait until stale path timer + expiry to do the best path selection and sends an EOR + """ + + 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) + + logger.info( + " Test Case : test_BGP_GR_chaos_37 " + "BGP GR " + "[Restart Mode]R1---R3[Helper Mode]" + ) + + logger.info( + "[Step 1] : Configure restarting router R3 to prevent " "sending an EOR.." + ) + + logger.info("[Step 2] : Reset the session between R3 and R1..") + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + } + } + }, + "r3": { + "bgp": { + "graceful-restart": {"disable-eor": True}, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + }, + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verify EOR is disabled + result = verify_eor( + tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format( + tc_name, result + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying BGP RIB routes after starting BGPd daemon + dut = "r1" + input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Step 3] : Kill BGPd daemon on R1..") + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Step 4] : Start BGPd daemon on R1..") + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Step 5] : Kill BGPd daemon on R3..") + + # Kill BGPd daemon on R3 + kill_router_daemons(tgen, "r3", ["bgpd"]) + + # Modify graceful-restart config to prevent sending EOR + input_dict_2 = {"r3": {"bgp": {"graceful-restart": {"disable-eor": True}}}} + + result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) + + logger.info("[Step 6] : Start BGPd daemon on R3..") + + # Start BGPd daemon on R3 + start_router_daemons(tgen, "r3", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verify r_bit + result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r3") + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes + input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verify EOR is send from R1 to R3 + input_dict_3 = {"r1": {"bgp": {"graceful-restart": {"disable-eor": True}}}} + + result = verify_eor( + tgen, topo, addr_type, input_dict_3, dut="r1", peer="r3", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +def test_BGP_GR_chaos_30_p1(request): + """ + Test Objective : Restarting node removes stale routes from Zebra + after receiving an EOR from helper router. + """ + + 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) + + logger.info( + " Test Case : test_BGP_GR_chaos_30 " + "BGP GR [Helper Mode]R3-----R1[Restart Mode] " + ) + + # Configure graceful-restart and timers + input_dict = { + "r1": { + "bgp": { + "graceful-restart": {"preserve-fw-state": True}, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + }, + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes before shutting down BGPd daemon + dut = "r1" + input_dict = {key: topo["routers"][key] for key in ["r3"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + logger.info("[Step 2] : Kill BGPd daemon on R1..") + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + logger.info("[Step 3] : Withdraw advertised prefixes from R3...") + + # Api call to delete advertised networks + network = {"ipv4": "103.0.20.1/32", "ipv6": "3::1/128"} + for addr_type in ADDR_TYPES: + input_dict = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "advertise_networks": [ + { + "network": network[addr_type], + "no_of_network": 5, + "delete": True, + } + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + logger.info("[Step 4] : Start BGPd daemon on R1..") + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes before shutting down BGPd daemon + input_dict = {key: topo["routers"][key] for key in ["r3"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + logger.info(" Expected behavior: {}".format(result)) + + write_test_footer(tc_name) + + +def test_BGP_GR_15_p2(request): + """ + Test Objective : Test GR scenarios by enabling Graceful Restart + for multiple address families.. + """ + + 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) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r6": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r6": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + } + } + }, + "r6": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r6": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r6": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r6") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r6" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + logger.info( + "[Step 2] : Test Setup " + "[Helper Mode]R6-----R1[Restart Mode]" + "--------R2[Helper Mode] Initilized" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + } + } + }, + "r2": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + dut = "r6" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def BGP_GR_TC_7_p1(request): + """ + Verify that BGP restarting node deletes all the routes received from peer + if BGP Graceful capability is not present in BGP Open message from the + peer + """ + + 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) + + logger.info( + " Verify route download to RIB: BGP_GR_TC_7 >> " + "BGP GR [Helper Mode]R3-----R1[Restart Mode] " + ) + + # Configure graceful-restart + input_dict = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + "r1": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + "preserve-fw-state": True, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": {"dest_link": {"r1": {"graceful-restart": True}}} + } + } + }, + }, + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes received from router R1 + dut = "r1" + input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + logger.info("R1 goes for reload") + kill_router_daemons(tgen, "r1", ["bgpd"]) + + # Change the configuration on router R1 + input_dict_2 = { + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-disable": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-disable": True} + } + } + } + } + }, + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + # Change the configuration on R1 + network = {"ipv4": "103.0.20.1/32", "ipv6": "3::1/128"} + for addr_type in ADDR_TYPES: + input_dict_2 = { + "r3": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "advertise_networks": [ + { + "network": network[addr_type], + "no_of_network": 5, + "delete": True, + } + ] + } + } + } + } + } + } + + result = create_router_bgp(tgen, topo, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + logger.info("R1 is about to come up now") + start_router_daemons(tgen, "r1", ["bgpd"]) + logger.info("R1 is UP Now") + + # Wait for RIB stale timeout + logger.info("Verify routes are not present" "in restart router") + + for addr_type in ADDR_TYPES: + # Verifying RIB routes + dut = "r1" + input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} + result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + + 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-4.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py new file mode 100644 index 0000000000..889f47f377 --- /dev/null +++ b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2-4.py @@ -0,0 +1,1024 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF") +# in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test BGP Graceful Restart functionality. +Basic Common Test steps for all the test case below : +- Create topology (setup module) + Creating 7 routers topology +- Bring up topology +- Verify for bgp to converge +- Configure BGP Graceful Restart on both the routers. + +TC_1_2: + Verify that EOR message is sent out only after initial convergence + Verify whether EOR message is received from all the peers after restart +TC_3: + Verify the selection deferral timer functionality when EOR is not sent + by the helper router +TC_11: + Verify that selection-deferral timer sets the maximum time to + avoid deadlock during which the best-path +TC_10: + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. +TC_15: + Test Objective : Test GR scenarios by enabling Graceful Restart + for multiple address families.. +TC_16: + Test Objective : Verify BGP-GR feature when restarting node + is a transit router for it's iBGP peers. +TC_18: + Test Objective : Verify that GR helper router deletes stale routes + received from restarting node, if GR capability is not present in +TC_19: + Test Objective : Verify that GR routers keeps all the routes + received from restarting node if both the routers are +TC_26: + Test Objective : Test GR scenarios on helper router by enabling + Graceful Restart for multiple address families. +TC_28: + Test Objective : Verify if helper node goes down before restarting + node comes up online, helper node sets the R-bit to avoid dead-lock +TC_29: + Test Objective : Change timers on the fly, and + verify if it takes immediate effect. +TC_33: + Test Objective : Helper router receives same prefixes from two + different routers (GR-restarting and GR-disabled). Keeps the +TC_34_1: + Test Objective : Restarting node doesn't preserve forwarding + state, helper router should not keep the stale entries. +TC_34_2: + Test Objective : Restarting node doesn't preserve the forwarding + state verify the behaviour on helper node, if it still keeps the +TC_32: + Test Objective : Restarting node is connected to multiple helper + nodes, one of them doesn't send EOR to restarting router. Verify +TC_37: + Test Objective : Verify if helper node restarts before sending the + EOR message, restarting node doesn't wait until stale path timer +TC_30: + Test Objective : Restarting node removes stale routes from Zebra + after receiving an EOR from helper router. + +These tests have been broken up into 4 sub python scripts because +the totality of run time for this script was greater than 10 minutes +""" + +import os +import sys +import time +import pytest +from time import sleep + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +# Import topoJson from lib, to create topology and initial configuration +from lib.topojson import build_config_from_json +from lib.bgp import ( + clear_bgp, + 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, +) + +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, + step, + get_frr_ipv6_linklocal, + required_linux_kernel_version, +) + +pytestmark = [pytest.mark.bgpd] + + +# Global variables +BGP_CONVERGENCE = False +GR_RESTART_TIMER = 5 +GR_SELECT_DEFER_TIMER = 5 +GR_STALEPATH_TIMER = 5 +PREFERRED_NEXT_HOP = "link_local" +NEXT_HOP_4 = ["192.168.1.1", "192.168.4.2"] +NEXT_HOP_6 = ["fd00:0:0:1::1", "fd00:0:0:4::2"] + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.16") + if result is not True: + pytest.skip("Kernel requirements are not met") + + global ADDR_TYPES + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_gr_topojson_topo2.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Api call verify whether BGP is converged + ADDR_TYPES = check_address_types() + + for addr_type in ADDR_TYPES: + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): + """ + This function groups the repetitive function calls into one function. + """ + + logger.info("configure_gr_followed_by_clear: dut %s peer %s", dut, peer) + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][peer]["links"][dut][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, dut, neighbor=neighbor) + + for addr_type in ADDR_TYPES: + neighbor = topo["routers"][dut]["links"][peer][addr_type].split("/")[0] + clear_bgp(tgen, addr_type, peer, neighbor=neighbor) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + return True + + +def next_hop_per_address_family(tgen, dut, peer, addr_type, next_hop_dict): + """ + This function returns link_local or global next_hop per address-family + """ + + intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"] + if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: + next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface) + else: + next_hop = next_hop_dict[addr_type] + + return next_hop + + +def test_BGP_GR_TC_23_p1(request): + """ + Verify that helper routers are deleting stale routes after stale route + timer's expiry. If all the routes are not received from restating node + after 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) + + logger.info( + "Verify Stale Routes are deleted on helper: BGP_GR_TC_23 >> " + "BGP GR [Helper Mode]R1-----R2[Restart Mode] " + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "graceful-restart": {"timer": {"stalepath-time": GR_STALEPATH_TIMER}}, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + }, + } + }, + "r2": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + "preserve-fw-state": True, + }, + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": {"dest_link": {"r2": {"graceful-restart": True}}} + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": {"dest_link": {"r2": {"graceful-restart": True}}} + } + } + }, + }, + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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) + + # Verifying BGP RIB routes received from router R1 + dut = "r1" + input_dict_1 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + logger.info("R2 goes for reload") + kill_router_daemons(tgen, "r2", ["bgpd"]) + + # Modify configuration to delete routes and include disable-eor + input_dict_3 = {"r2": {"bgp": {"graceful-restart": {"disable-eor": True}}}} + + result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) + + # Modify configuration to delete routes and include disable-eor + network = {"ipv4": "102.0.20.1/32", "ipv6": "2::1/128"} + for addr_type in ADDR_TYPES: + input_dict_3 = { + "r2": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "advertise_networks": [ + { + "network": network[addr_type], + "no_of_network": 3, + "delete": True, + } + ] + } + } + } + } + } + } + + result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + logger.info("BGPd comes up for r2") + start_router_daemons(tgen, "r2", ["bgpd"]) + + # Wait for stalepath timer + logger.info("Waiting for stalepath timer({} sec..)".format(GR_STALEPATH_TIMER)) + sleep(GR_STALEPATH_TIMER) + + for addr_type in ADDR_TYPES: + clear_bgp(tgen, addr_type, "r2") + + # Verifying RIB routes + dut = "r1" + network = {"ipv4": "102.0.20.4/32", "ipv6": "2::4/128"} + for addr_type in ADDR_TYPES: + input_dict_1 = { + "r1": { + "bgp": { + "address_family": { + addr_type: { + "unicast": { + "advertise_networks": [ + {"network": network[addr_type], "no_of_network": 2} + ] + } + } + } + } + } + } + + # Verify EOR on helper router + result = verify_eor( + tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False + ) + assert ( + result is not True + ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( + tc_name, result + ) + + # Verifying BGP RIB routes received from router R1 + dut = "r1" + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_BGP_GR_20_p1(request): + """ + Test Objective : Verify that GR routers delete all the routes + received from a node if both the routers are configured as GR + helper node + """ + + 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) + + logger.info( + "[Step 1] : Test Setup " "[Restart Mode]R3-----R1[Restart Mode] Initilized" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in BGP RIB\n Error: {}".format( + tc_name, result + ) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) + assert result is not True, ( + "Testcase {} : Failed \n " + "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) + ) + logger.info(" Expected behavior: {}".format(result)) + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r1", ["bgpd"]) + + for addr_type in ADDR_TYPES: + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_BGP_GR_21_p2(request): + """ + Test Objective : VVerify BGP-GR feature when helper node is + a transit router for it's eBGP peers. + """ + + 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) + + logger.info( + "[Step 1] : Test Setup " "[Helper Mode]R6-----R1[Restart Mode] Initilized" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r1": {"graceful-restart-disable": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r6": { + "dest_link": { + "r1": {"graceful-restart-disable": True} + } + } + } + } + }, + } + } + }, + "r6": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r6": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r6": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r6") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r6" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + logger.info( + "[Step 2] : Test Setup " + "[Restart Mode]R2-----[Helper Mode]R1[Disable Mode]" + "--------R6[Helper Mode] Initilized" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + "r2": { + "bgp": { + "graceful-restart": { + "graceful-restart": True, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r2", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + dut = "r6" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r2", ["bgpd"]) + + for addr_type in ADDR_TYPES: + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes after bringing up BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r6" + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + write_test_footer(tc_name) + + +def test_BGP_GR_22_p2(request): + """ + Test Objective : Verify BGP-GR feature when helper node + is a transit router for it's iBGP peers. + """ + + 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) + + logger.info( + "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] Initilized" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "graceful-restart-disable": True, + "next_hop_self": True, + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1": { + "graceful-restart-disable": True, + "next_hop_self": True, + } + } + } + } + } + }, + } + } + }, + "r3": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") + + for addr_type in ADDR_TYPES: + result = verify_graceful_restart( + tgen, topo, addr_type, input_dict, dut="r1", peer="r3" + ) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + logger.info( + "[Step 2] : Test Setup " + "[Restart Mode]R2-----[Helper Mode]R1[Disable Mode]" + "--------R3[Helper Mode] Initilized" + ) + + # Configure graceful-restart + input_dict = { + "r1": { + "bgp": { + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1": {"graceful-restart-helper": True} + } + } + } + } + }, + } + } + }, + "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") + + 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) + + # Verifying BGP RIB routes + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r3" + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Kill BGPd daemon on R1 + kill_router_daemons(tgen, "r2", ["bgpd"]) + + for addr_type in ADDR_TYPES: + # Verifying BGP RIB routes + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r3" + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Start BGPd daemon on R1 + start_router_daemons(tgen, "r2", ["bgpd"]) + + for addr_type in ADDR_TYPES: + result = verify_bgp_convergence(tgen, topo) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r3" + input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying BGP RIB routes + dut = "r3" + input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + # Verifying RIB routes before shutting down BGPd daemon + result = verify_rib(tgen, addr_type, dut, input_dict_2) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + 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.py b/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py deleted file mode 100644 index 52ad7813c5..0000000000 --- a/tests/topotests/bgp_gr_functionality_topo2/test_bgp_gr_functionality_topo2.py +++ /dev/null @@ -1,4358 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2019 by VMware, Inc. ("VMware") -# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF") -# in this file. -# -# Permission to use, copy, modify, and/or distribute this software -# for any purpose with or without fee is hereby granted, provided -# that the above copyright notice and this permission notice appear -# in all copies. -# -# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY -# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, -# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS -# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE -# OF THIS SOFTWARE. -# - -""" -Following tests are covered to test BGP Graceful Restart functionality. -Basic Common Test steps for all the test case below : -- Create topology (setup module) - Creating 7 routers topology -- Bring up topology -- Verify for bgp to converge -- Configure BGP Graceful Restart on both the routers. - -TC_1_2: - Verify that EOR message is sent out only after initial convergence - Verify whether EOR message is received from all the peers after restart -TC_3: - Verify the selection deferral timer functionality when EOR is not sent - by the helper router -TC_11: - Verify that selection-deferral timer sets the maximum time to - avoid deadlock during which the best-path -TC_10: - Test Objective : Test GR scenarios on helper router by enabling - Graceful Restart for multiple address families. -TC_15: - Test Objective : Test GR scenarios by enabling Graceful Restart - for multiple address families.. -TC_16: - Test Objective : Verify BGP-GR feature when restarting node - is a transit router for it's iBGP peers. -TC_18: - Test Objective : Verify that GR helper router deletes stale routes - received from restarting node, if GR capability is not present in -TC_19: - Test Objective : Verify that GR routers keeps all the routes - received from restarting node if both the routers are -TC_26: - Test Objective : Test GR scenarios on helper router by enabling - Graceful Restart for multiple address families. -TC_28: - Test Objective : Verify if helper node goes down before restarting - node comes up online, helper node sets the R-bit to avoid dead-lock -TC_29: - Test Objective : Change timers on the fly, and - verify if it takes immediate effect. -TC_33: - Test Objective : Helper router receives same prefixes from two - different routers (GR-restarting and GR-disabled). Keeps the -TC_34_1: - Test Objective : Restarting node doesn't preserve forwarding - state, helper router should not keep the stale entries. -TC_34_2: - Test Objective : Restarting node doesn't preserve the forwarding - state verify the behaviour on helper node, if it still keeps the -TC_32: - Test Objective : Restarting node is connected to multiple helper - nodes, one of them doesn't send EOR to restarting router. Verify -TC_37: - Test Objective : Verify if helper node restarts before sending the - EOR message, restarting node doesn't wait until stale path timer -TC_30: - Test Objective : Restarting node removes stale routes from Zebra - after receiving an EOR from helper router. - -""" - -import os -import sys -import time -import pytest -from time import sleep - -# Save the Current Working Directory to find configuration files. -CWD = os.path.dirname(os.path.realpath(__file__)) -sys.path.append(os.path.join("../")) -sys.path.append(os.path.join("../lib/")) - -# pylint: disable=C0413 -# Import topogen and topotest helpers -from lib.topogen import Topogen, get_topogen -from lib.topolog import logger - -# Required to instantiate the topology builder class. - -# Import topoJson from lib, to create topology and initial configuration -from lib.topojson import build_config_from_json -from lib.bgp import ( - clear_bgp, - 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, -) - -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, - step, - get_frr_ipv6_linklocal, - required_linux_kernel_version, -) - -pytestmark = [pytest.mark.bgpd] - - -# Global variables -BGP_CONVERGENCE = False -GR_RESTART_TIMER = 5 -GR_SELECT_DEFER_TIMER = 5 -GR_STALEPATH_TIMER = 5 -PREFERRED_NEXT_HOP = "link_local" -NEXT_HOP_4 = ["192.168.1.1", "192.168.4.2"] -NEXT_HOP_6 = ["fd00:0:0:1::1", "fd00:0:0:4::2"] - - -def setup_module(mod): - """ - Sets up the pytest environment - - * `mod`: module name - """ - - # Required linux kernel version for this suite to run. - result = required_linux_kernel_version("4.16") - if result is not True: - pytest.skip("Kernel requirements are not met") - - global ADDR_TYPES - - testsuite_run_time = time.asctime(time.localtime(time.time())) - logger.info("Testsuite start time: {}".format(testsuite_run_time)) - logger.info("=" * 40) - - logger.info("Running setup_module to create topology") - - # This function initiates the topology build with Topogen... - json_file = "{}/bgp_gr_topojson_topo2.json".format(CWD) - tgen = Topogen(json_file, mod.__name__) - global topo - topo = tgen.json_topo - # ... and here it calls Mininet initialization functions. - - # Starting topology, create tmp files which are loaded to routers - # to start deamons and then start routers - start_topology(tgen) - - # Creating configuration from JSON - build_config_from_json(tgen, topo) - - # Api call verify whether BGP is converged - ADDR_TYPES = check_address_types() - - for addr_type in ADDR_TYPES: - BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) - assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( - BGP_CONVERGENCE - ) - - logger.info("Running setup_module() done") - - -def teardown_module(mod): - """ - Teardown the pytest environment - - * `mod`: module name - """ - - logger.info("Running teardown_module to delete topology") - - tgen = get_topogen() - - # Stop toplogy and Remove tmp files - tgen.stop_topology() - - logger.info( - "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) - ) - logger.info("=" * 40) - - -def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut, peer): - """ - This function groups the repetitive function calls into one function. - """ - - logger.info("configure_gr_followed_by_clear: dut %s peer %s", dut, peer) - - result = create_router_bgp(tgen, topo, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - for addr_type in ADDR_TYPES: - neighbor = topo["routers"][peer]["links"][dut][addr_type].split("/")[0] - clear_bgp(tgen, addr_type, dut, neighbor=neighbor) - - for addr_type in ADDR_TYPES: - neighbor = topo["routers"][dut]["links"][peer][addr_type].split("/")[0] - clear_bgp(tgen, addr_type, peer, neighbor=neighbor) - - result = verify_bgp_convergence_from_running_config(tgen) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - return True - - -def next_hop_per_address_family(tgen, dut, peer, addr_type, next_hop_dict): - """ - This function returns link_local or global next_hop per address-family - """ - - intferface = topo["routers"][peer]["links"]["{}-link1".format(dut)]["interface"] - if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: - next_hop = get_frr_ipv6_linklocal(tgen, peer, intf=intferface) - else: - next_hop = next_hop_dict[addr_type] - - return next_hop - - -def test_BGP_GR_TC_1_2_p0(request): - """ - Verify that EOR message is sent out only after initial convergence - Verify whether EOR message is received from all the peers after 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) - - logger.info( - "Verify EOR Sent and Received : BGP_GR_TC_1_2 >> " - "BGP GR [Helper Mode]R3-----R1[Restart Mode] " - ) - - # Configure graceful-restart - input_dict = { - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - "preserve-fw-state": True, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - }, - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes received from router R3 - dut = "r1" - input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("R1 goes for reload") - kill_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying RIB routes - input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("Starting bgpd process") - start_router_daemons(tgen, "r1", ["bgpd"]) - logger.info("R1 is UP Now") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes received from router R3 - input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying EOR on restarting router - result = verify_eor(tgen, topo, addr_type, input_dict, dut="r3", peer="r1") - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_3_p0(request): - """ - Verify the selection deferral timer functionality when EOR is not sent - by the helper router - """ - - 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) - - logger.info( - " Verify route download to RIB: BGP_GR_TC_3 >> " - "BGP GR [Helper Mode]R1-----R2[Restart Mode] " - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "disable-eor": True, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - }, - } - }, - "r2": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - "preserve-fw-state": True, - "timer": {"select-defer-time": GR_SELECT_DEFER_TIMER}, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": {"dest_link": {"r2": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": {"dest_link": {"r2": {"graceful-restart": True}}} - } - } - }, - }, - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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 - ) - - # Verifying BGP RIB routes received from router R1 - dut = "r2" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("R2 goes for reload ") - kill_router_daemons(tgen, "r2", ["bgpd"]) - - logger.info("R2 is about to come up now") - start_router_daemons(tgen, "r2", ["bgpd"]) - logger.info("R2 is UP Now") - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes received from router R1 - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verify EOR on restarting router - result = verify_eor( - tgen, topo, addr_type, input_dict, dut="r2", peer="r1", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r2: EOR is set to True\n Error: {}".format( - tc_name, result - ) - - logger.info( - "Waiting for selection deferral timer({} sec)..".format(GR_SELECT_DEFER_TIMER) - ) - sleep(GR_SELECT_DEFER_TIMER) - - for addr_type in ADDR_TYPES: - # Verifying RIB routes - result = verify_rib(tgen, addr_type, "r2", input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_11_p0(request): - """ - Verify that selection-deferral timer sets the maximum time to - avoid deadlock during which the best-path - selection process is deferred, after a peer session was restarted - """ - - 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) - - logger.info("Verify EOR Sent after deferral timeout : BGP_GR_TC_11") - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - "select-defer-time": GR_SELECT_DEFER_TIMER, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": {"dest_link": {"r1": {"graceful-restart": True}}}, - "r3": {"dest_link": {"r1": {"graceful-restart": True}}}, - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": {"dest_link": {"r1": {"graceful-restart": True}}}, - "r3": {"dest_link": {"r1": {"graceful-restart": True}}}, - } - } - }, - }, - } - }, - "r3": { - "bgp": { - "graceful-restart": {"disable-eor": True}, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - }, - } - }, - } - - result = create_router_bgp(tgen, topo, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, "r1") - clear_bgp(tgen, addr_type, "r3") - - result = verify_bgp_convergence_from_running_config(tgen, topo) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes received from router R1 - dut = "r1" - input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("R1 goes for reload") - kill_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("Starting bgpd process") - start_router_daemons(tgen, "r1", ["bgpd"]) - logger.info("R1 is UP Now") - - for addr_type in ADDR_TYPES: - # Verify EOR on restarting router - result = verify_eor( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( - tc_name, result - ) - - logger.info( - "Waiting for selection deferral timer({} sec).. ".format( - GR_SELECT_DEFER_TIMER + 2 - ) - ) - sleep(GR_SELECT_DEFER_TIMER + 2) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes received from router R1 - input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying EOR on restarting router - result = verify_eor( - tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_10_p2(request): - """ - Test Objective : Test GR scenarios on helper router by enabling - Graceful Restart for multiple address families. - """ - - 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("Test Setup: [Helper Mode]R3-----R1[Restart Mode] initialized") - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": { - "next_hop_self": True, - "graceful-restart": True, - "activate": "ipv6", - } - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": { - "next_hop_self": True, - "graceful-restart": True, - "activate": "ipv4", - } - } - } - } - } - }, - } - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": { - "graceful-restart-helper": True, - "activate": "ipv6", - } - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": { - "graceful-restart-helper": True, - "activate": "ipv4", - } - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - step( - "Verifying GR config and operational state for addr_type {}".format( - addr_type - ) - ) - - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - dut = "r3" - input_topo = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # verify multi address family - result = verify_gr_address_family( - tgen, - topo, - addr_type, - "ipv4Unicast", - dut="r1", - peer="r3", - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # verify multi address family - result = verify_gr_address_family( - tgen, - topo, - addr_type, - "ipv6Unicast", - dut="r1", - peer="r3", - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # verify multi address family - result = verify_gr_address_family( - tgen, - topo, - addr_type, - "ipv4Unicast", - dut="r3", - peer="r1", - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # verify multi address family - result = verify_gr_address_family( - tgen, - topo, - addr_type, - "ipv6Unicast", - dut="r3", - peer="r1", - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - step("Killing bgpd on r1") - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - input_topo = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - step("Starting bgpd on r1") - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - input_topo = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def BGP_GR_16_p2(request): - """ - Test Objective : Verify BGP-GR feature when restarting node - is a transit router for it's iBGP peers. - """ - - 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) - - logger.info( - "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] initialized" - ) - - # Configure graceful-restart and timers - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": { - "graceful-restart": True, - "next_hop_self": True, - } - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": { - "graceful-restart": True, - "next_hop_self": True, - } - } - } - } - } - }, - } - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info( - "[Step 2] : Test Setup " - "[Helper Mode]R3-----R1[Restart Mode]" - "--------R6[Helper Mode] initialized" - ) - - # Configure graceful-restart and timers - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - } - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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 - ) - - # Verifying BGP RIB routes - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - result = verify_bgp_convergence_from_running_config(tgen, topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_18_p1(request): - """ - Test Objective : Verify that GR helper router deletes stale routes - received from restarting node, if GR capability is not present in - restarting node's OPEN message. - """ - - 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) - - logger.info( - "[Step 1] : Test Setup " "[Helper Mode]R6-----R1[Restart Mode] initialized" - ) - - # Configure graceful-restart and timers - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r6": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r6": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - } - } - }, - "r6": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r6": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r6": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r6") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r6" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info( - "[Step 2] : Test Setup " - "[Helper Mode]R6-----R1[Restart Mode]" - "--------R2[Helper Mode] initialized" - ) - - # Configure graceful-restart and timers - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - } - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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 - ) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - dut = "r2" - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Step 3] : Configure R1 to prevent sending EOR") - - # Modify graceful-restart config to prevent sending EOR - input_dict_3 = {"r1": {"bgp": {"graceful-restart": {"disable-eor": True}}}} - - result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) - - # Modify configuration to delete routes - network = {"ipv4": "101.0.20.1/32", "ipv6": "1::1/128"} - for addr_type in ADDR_TYPES: - input_dict_3 = { - "r1": { - "bgp": { - "address_family": { - addr_type: { - "unicast": { - "advertise_networks": [ - { - "network": network[addr_type], - "no_of_network": 5, - "delete": True, - } - ] - } - } - } - } - } - } - - result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Modify graceful-restart config - input_dict_3 = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-disable": True} - } - }, - "r6": { - "dest_link": { - "r1": {"graceful-restart-disable": True} - } - }, - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-disable": True} - } - }, - "r6": { - "dest_link": { - "r1": {"graceful-restart-disable": True} - } - }, - } - } - }, - } - } - } - } - - result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) - assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) - - logger.info("[Step 4] : Bring up the BGPd daemon on R1 for 30" " seconds..") - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - dut = "r6" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r6: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying BGP RIB routes - dut = "r2" - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r2: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r6: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - write_test_footer(tc_name) - - -def test_BGP_GR_26_p2(request): - """ - Test Objective : Test GR scenarios on helper router by enabling - Graceful Restart for multiple address families. - """ - - 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) - - logger.info( - "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] initialized" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": { - "graceful-restart": True, - "next_hop_self": True, - "activate": "ipv6", - } - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": { - "graceful-restart": True, - "next_hop_self": True, - "activate": "ipv4", - } - } - } - } - } - }, - } - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": { - "graceful-restart-helper": True, - "activate": "ipv6", - } - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": { - "graceful-restart-helper": True, - "activate": "ipv4", - } - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r3", peer="r1" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes - dut = "r3" - input_topo = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - input_topo = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - input_topo = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_topo) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # verify multi address family - result = verify_gr_address_family( - tgen, - topo, - addr_type, - "ipv4Unicast", - dut="r1", - peer="r3", - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # verify multi address family - result = verify_gr_address_family( - tgen, - topo, - addr_type, - "ipv6Unicast", - dut="r1", - peer="r3", - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # verify multi address family - result = verify_gr_address_family( - tgen, - topo, - addr_type, - "ipv4Unicast", - dut="r3", - peer="r1", - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # verify multi address family - result = verify_gr_address_family( - tgen, - topo, - addr_type, - "ipv6Unicast", - dut="r3", - peer="r1", - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_chaos_28_p1(request): - """ - Test Objective : Verify if helper node goes down before restarting - node comes up online, helper node sets the R-bit to avoid dead-lock - till SDT expiry. - """ - - 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) - - logger.info( - "Test Case: test_BGP_GR_chaos_28 :" - "[Helper Mode]R3-----R1[Restart Mode] initialized" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - } - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Step 1] : Kill BGPd daemon on R1..") - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Step 2] : Kill BGPd daemon on R3..") - - # Kill BGPd daemon on R3 - kill_router_daemons(tgen, "r3", ["bgpd"]) - - logger.info("[Step 3] : Start BGPd daemon on R1..") - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Step 4] : Start BGPd daemon on R3..") - - # Start BGPd daemon on R3 - start_router_daemons(tgen, "r3", ["bgpd"]) - - # Verify r_bit - for addr_type in ADDR_TYPES: - result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r3", peer="r1") - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_chaos_29_p1(request): - """ - Test Objective : Change timers on the fly, and - verify if it takes immediate effect. - """ - - 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) - - logger.info( - " Test Case : test_BGP_GR_chaos_29" - " BGP GR [Helper Mode]R3-----R1[Restart Mode]" - " and [restart-time 150]R1 initialized" - ) - - # Configure graceful-restart and timers - input_dict = { - "r1": { - "bgp": { - "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER}}, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - }, - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verify graceful-restart timers - input_dict_2 = { - "r1": { - "bgp": { - "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER + 5}} - } - } - } - - result = create_router_bgp(tgen, topo, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - for addr_type in ADDR_TYPES: - input_dict_2 = { - "r1": { - "bgp": { - "graceful-restart": {"timer": {"restart-time": GR_RESTART_TIMER}} - } - } - } - - result = verify_graceful_restart_timers( - tgen, topo, addr_type, input_dict_2, dut="r3", peer="r1" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes before shutting down BGPd daemon - dut = "r3" - input_dict = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Step 2] : Kill BGPd daemon on R1..") - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Step 3] : Wait for {} seconds..".format(GR_RESTART_TIMER)) - - # Waiting for GR_RESTART_TIMER - sleep(GR_RESTART_TIMER) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes before shutting down BGPd daemon - input_dict = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - logger.info("[Step 4] : Start BGPd daemon on R1..") - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - write_test_footer(tc_name) - - -def test_BGP_GR_chaos_33_p1(request): - """ - Test Objective : Helper router receives same prefixes from two - different routers (GR-restarting and GR-disabled). Keeps the - stale entry only for GR-restarting node(next-hop is correct). - """ - - 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) - - logger.info( - " Test Case : test_BGP_GR_chaos_33 " - "BGP GR " - "[Restart Mode]R1--R3[Helper Mode]--R4[Disabled Mode]" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - } - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - "r4": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r4": {"graceful-restart-disable": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r4": {"graceful-restart-disable": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Step 2] : Advertise same networks from R1 and R4..") - - # Api call to delete advertised networks - input_dict_2 = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "advertise_networks": [ - { - "network": "200.0.20.1/32", - "no_of_network": 2, - } - ] - } - }, - "ipv6": { - "unicast": { - "advertise_networks": [ - {"network": "2001::1/128", "no_of_network": 2} - ] - } - }, - } - } - }, - "r4": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "advertise_networks": [ - {"network": "200.0.20.1/32", "no_of_network": 2} - ] - } - }, - "ipv6": { - "unicast": { - "advertise_networks": [ - {"network": "2001::1/128", "no_of_network": 2} - ] - } - }, - } - } - }, - } - - result = create_router_bgp(tgen, topo, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - for addr_type in ADDR_TYPES: - # Verifying RIB routes - dut = "r3" - peer1 = "r1" - peer2 = "r4" - intf1 = topo["routers"][peer1]["links"][dut]["interface"] - intf2 = topo["routers"][peer2]["links"][dut]["interface"] - - if addr_type == "ipv4": - next_hop_4 = NEXT_HOP_4 - result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_4) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - if addr_type == "ipv6": - if "link_local" in PREFERRED_NEXT_HOP: - next_hop1 = get_frr_ipv6_linklocal(tgen, peer1, intf=intf1) - next_hop2 = get_frr_ipv6_linklocal(tgen, peer2, intf=intf2) - - next_hop_6 = [next_hop1, next_hop2] - else: - next_hop_6 = NEXT_HOP_6 - - result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Step 3] : Kill BGPd daemon on R1 and R4..") - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - # Kill BGPd daemon on R4 - kill_router_daemons(tgen, "r4", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying RIB routes - next_hop_6 = ["fd00:0:0:1::1"] - if addr_type == "ipv4": - next_hop_4 = NEXT_HOP_4[0] - - result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_4) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - if addr_type == "ipv6": - if "link_local" in PREFERRED_NEXT_HOP: - next_hop_6 = get_frr_ipv6_linklocal(tgen, peer1, intf=intf1) - else: - next_hop_6 = NEXT_HOP_6[0] - - result = verify_rib(tgen, addr_type, dut, input_dict_2, next_hop_6) - - # Verifying RIB routes - if addr_type == "ipv4": - next_hop_4 = NEXT_HOP_4[1] - result = verify_rib( - tgen, addr_type, dut, input_dict_2, next_hop_4, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - if addr_type == "ipv6": - if "link_local" in PREFERRED_NEXT_HOP: - next_hop_6 = get_frr_ipv6_linklocal(tgen, peer2, intf=intf2) - else: - next_hop_6 = NEXT_HOP_6[1] - - result = verify_rib( - tgen, addr_type, dut, input_dict_2, next_hop_6, expected=False - ) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - logger.info("[Step 4] : Start BGPd daemon on R1 and R4..") - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - # Start BGPd daemon on R4 - start_router_daemons(tgen, "r4", ["bgpd"]) - - write_test_footer(tc_name) - - -def test_BGP_GR_chaos_34_2_p1(request): - """ - Test Objective : Restarting node doesn't preserve the forwarding - state verify the behaviour on helper node, if it still keeps the - stale routes. - """ - - 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) - - logger.info( - " Test Case : test_BGP_GR_chaos_34 " - "BGP GR " - "[Restart Mode]R1---R3[Helper Mode]" - ) - - logger.info("[Step 1] : Configure restarting" " router R1 to prevent ") - logger.info("[Step 2] : Reset the session" " between R1 and R3..") - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "graceful-restart": {"preserve-fw-state": True, "disable-eor": True}, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - }, - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verify f-bit before killing BGPd daemon - result = verify_f_bit(tgen, topo, addr_type, input_dict, "r3", "r1") - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes after starting BGPd daemon - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Step 3] : Kill BGPd daemon on R1..") - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Step 4] : Withdraw/delete the prefixes " "originated from R1..") - - # Api call to delete advertised networks - network = {"ipv4": "101.0.20.1/32", "ipv6": "1::1/128"} - for addr_type in ADDR_TYPES: - input_dict_2 = { - "r1": { - "bgp": { - "address_family": { - addr_type: { - "unicast": { - "advertise_networks": [ - { - "network": network[addr_type], - "no_of_network": 5, - "delete": True, - } - ] - } - } - } - } - } - } - - result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Step 5] : Remove the CLI from R1's config to " "set the F-bit..") - - # Modify graceful-restart config not to set f-bit - # and write to /etc/frr - input_dict_2 = {"r1": {"bgp": {"graceful-restart": {"preserve-fw-state": False}}}} - - result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) - - logger.info("[Step 6] : Bring up the BGPd daemon on R1 again..") - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verify f-bit after starting BGPd daemon - result = verify_f_bit( - tgen, topo, addr_type, input_dict, "r3", "r1", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format( - tc_name, result - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying BGP RIB routes after starting BGPd daemon - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - write_test_footer(tc_name) - - -def test_BGP_GR_chaos_34_1_p1(request): - """ - Test Objective : Restarting node doesn't preserve forwarding - state, helper router should not keep the stale entries. - """ - - 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) - - logger.info( - " Test Case : test_BGP_GR_chaos_31 " - "BGP GR " - "[Restart Mode]R1---R3[Helper Mode]" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "graceful-restart": { - "preserve-fw-state": True, - "timer": {"restart-time": GR_RESTART_TIMER}, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - }, - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes after starting BGPd daemon - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info( - "[Step 1] : Remove the preserve-fw-state command" - " from restarting node R1's config" - ) - - # Configure graceful-restart to set f-bit as False - input_dict_2 = {"r1": {"bgp": {"graceful-restart": {"preserve-fw-state": False}}}} - - result = create_router_bgp(tgen, topo, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - logger.info("[Step 2] : Reset the session between R1 and R3..") - - # Reset sessions - for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, "r1") - - result = verify_bgp_convergence_from_running_config(tgen, topo) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - for addr_type in ADDR_TYPES: - # Verify f-bit after starting BGPd daemon - result = verify_f_bit( - tgen, topo, addr_type, input_dict_2, "r3", "r1", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r3: F-bit is set to True\n Error: {}".format( - tc_name, result - ) - logger.info(" Expected behavior: {}".format(result)) - - logger.info("[Step 3] : Kill BGPd daemon on R1..") - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - # Waiting for GR_RESTART_TIMER - logger.info("Waiting for {} sec..".format(GR_RESTART_TIMER)) - sleep(GR_RESTART_TIMER) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - input_dict = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - write_test_footer(tc_name) - - -def test_BGP_GR_chaos_32_p1(request): - """ - Test Objective : Restarting node is connected to multiple helper - nodes, one of them doesn't send EOR to restarting router. Verify - that only after SDT restarting node send EOR to all helper peers - excluding the prefixes originated by faulty router. - """ - - 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) - - logger.info( - " Test Case : test_BGP_GR_chaos_32 " - "BGP GR " - "[Restart Mode]R1---R3&R5[Helper Mode]" - ) - - logger.info( - "[Step 1] : Change the mode on R1 be a restarting" " node on global level" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "graceful-restart": {"graceful-restart": True}, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"next_hop_self": True}}}, - "r5": {"dest_link": {"r1": {"graceful-restart": True}}}, - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"next_hop_self": True}}}, - "r5": {"dest_link": {"r1": {"graceful-restart": True}}}, - } - } - }, - }, - } - }, - "r5": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r5": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r5": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r5") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r5" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes after starting BGPd daemon - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r5"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Step 2] : Kill BGPd daemon on R1..") - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Step 3] : Withdraw all the advertised prefixes from R5") - - # Api call to delete advertised networks - network = {"ipv4": "105.0.20.1/32", "ipv6": "5::1/128"} - for addr_type in ADDR_TYPES: - input_dict_2 = { - "r5": { - "bgp": { - "address_family": { - addr_type: { - "unicast": { - "advertise_networks": [ - { - "network": network[addr_type], - "no_of_network": 5, - "delete": True, - } - ] - } - } - } - } - } - } - - result = create_router_bgp(tgen, topo, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result - ) - - logger.info( - "[Step 4] : Stop the helper router R5 from sending EOR" " message using CLI" - ) - - # Modify graceful-restart config to prevent sending EOR - input_dict_3 = {"r5": {"bgp": {"graceful-restart": {"disable-eor": True}}}} - - result = create_router_bgp(tgen, topo, input_dict_3) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - logger.info("[Step 5] : Bring up the BGPd daemon on R1..") - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verify EOR is disabled - result = verify_eor( - tgen, topo, addr_type, input_dict_3, dut="r5", peer="r1", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r5: EOR is set to TRUE\n Error: {}".format( - tc_name, result - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying BGP RIB routes after starting BGPd daemon - input_dict_1 = {key: topo["routers"][key] for key in ["r5"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - write_test_footer(tc_name) - - -def test_BGP_GR_chaos_37_p1(request): - """ - Test Objective : Verify if helper node restarts before sending the - EOR message, restarting node doesn't wait until stale path timer - expiry to do the best path selection and sends an EOR - """ - - 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) - - logger.info( - " Test Case : test_BGP_GR_chaos_37 " - "BGP GR " - "[Restart Mode]R1---R3[Helper Mode]" - ) - - logger.info( - "[Step 1] : Configure restarting router R3 to prevent " "sending an EOR.." - ) - - logger.info("[Step 2] : Reset the session between R3 and R1..") - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - } - } - }, - "r3": { - "bgp": { - "graceful-restart": {"disable-eor": True}, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - }, - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verify EOR is disabled - result = verify_eor( - tgen, topo, addr_type, input_dict, dut="r3", peer="r1", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r3: EOR is set to True\n Error: {}".format( - tc_name, result - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying BGP RIB routes after starting BGPd daemon - dut = "r1" - input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Step 3] : Kill BGPd daemon on R1..") - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Step 4] : Start BGPd daemon on R1..") - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Step 5] : Kill BGPd daemon on R3..") - - # Kill BGPd daemon on R3 - kill_router_daemons(tgen, "r3", ["bgpd"]) - - # Modify graceful-restart config to prevent sending EOR - input_dict_2 = {"r3": {"bgp": {"graceful-restart": {"disable-eor": True}}}} - - result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error {}".format(tc_name, result) - - logger.info("[Step 6] : Start BGPd daemon on R3..") - - # Start BGPd daemon on R3 - start_router_daemons(tgen, "r3", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verify r_bit - result = verify_r_bit(tgen, topo, addr_type, input_dict, dut="r1", peer="r3") - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes - input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verify EOR is send from R1 to R3 - input_dict_3 = {"r1": {"bgp": {"graceful-restart": {"disable-eor": True}}}} - - result = verify_eor( - tgen, topo, addr_type, input_dict_3, dut="r1", peer="r3", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( - tc_name, result - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_chaos_30_p1(request): - """ - Test Objective : Restarting node removes stale routes from Zebra - after receiving an EOR from helper router. - """ - - 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) - - logger.info( - " Test Case : test_BGP_GR_chaos_30 " - "BGP GR [Helper Mode]R3-----R1[Restart Mode] " - ) - - # Configure graceful-restart and timers - input_dict = { - "r1": { - "bgp": { - "graceful-restart": {"preserve-fw-state": True}, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - }, - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes before shutting down BGPd daemon - dut = "r1" - input_dict = {key: topo["routers"][key] for key in ["r3"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict) - assert result is True, "Testcase {} : Failed \n Error {}".format( - tc_name, result - ) - - logger.info("[Step 2] : Kill BGPd daemon on R1..") - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - logger.info("[Step 3] : Withdraw advertised prefixes from R3...") - - # Api call to delete advertised networks - network = {"ipv4": "103.0.20.1/32", "ipv6": "3::1/128"} - for addr_type in ADDR_TYPES: - input_dict = { - "r3": { - "bgp": { - "address_family": { - addr_type: { - "unicast": { - "advertise_networks": [ - { - "network": network[addr_type], - "no_of_network": 5, - "delete": True, - } - ] - } - } - } - } - } - } - - result = create_router_bgp(tgen, topo, input_dict) - assert result is True, "Testcase {} : Failed \n Error: {}".format( - tc_name, result - ) - - logger.info("[Step 4] : Start BGPd daemon on R1..") - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes before shutting down BGPd daemon - input_dict = {key: topo["routers"][key] for key in ["r3"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r1: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - write_test_footer(tc_name) - - -def test_BGP_GR_15_p2(request): - """ - Test Objective : Test GR scenarios by enabling Graceful Restart - for multiple address families.. - """ - - 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) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r6": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r6": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - } - } - }, - "r6": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r6": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r6": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r6") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r6" - ) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - logger.info( - "[Step 2] : Test Setup " - "[Helper Mode]R6-----R1[Restart Mode]" - "--------R2[Helper Mode] Initilized" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - } - } - }, - "r2": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r2": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - dut = "r6" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - result = verify_bgp_convergence(tgen, topo) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - write_test_footer(tc_name) - - -def BGP_GR_TC_7_p1(request): - """ - Verify that BGP restarting node deletes all the routes received from peer - if BGP Graceful capability is not present in BGP Open message from the - peer - """ - - 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) - - logger.info( - " Verify route download to RIB: BGP_GR_TC_7 >> " - "BGP GR [Helper Mode]R3-----R1[Restart Mode] " - ) - - # Configure graceful-restart - input_dict = { - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - "r1": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - "preserve-fw-state": True, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": {"dest_link": {"r1": {"graceful-restart": True}}} - } - } - }, - }, - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes received from router R1 - dut = "r1" - input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - logger.info("R1 goes for reload") - kill_router_daemons(tgen, "r1", ["bgpd"]) - - # Change the configuration on router R1 - input_dict_2 = { - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-disable": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-disable": True} - } - } - } - } - }, - } - } - } - } - - result = create_router_bgp(tgen, topo, input_dict_2) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - # Change the configuration on R1 - network = {"ipv4": "103.0.20.1/32", "ipv6": "3::1/128"} - for addr_type in ADDR_TYPES: - input_dict_2 = { - "r3": { - "bgp": { - "address_family": { - addr_type: { - "unicast": { - "advertise_networks": [ - { - "network": network[addr_type], - "no_of_network": 5, - "delete": True, - } - ] - } - } - } - } - } - } - - result = create_router_bgp(tgen, topo, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - logger.info("R1 is about to come up now") - start_router_daemons(tgen, "r1", ["bgpd"]) - logger.info("R1 is UP Now") - - # Wait for RIB stale timeout - logger.info("Verify routes are not present" "in restart router") - - for addr_type in ADDR_TYPES: - # Verifying RIB routes - dut = "r1" - input_dict_1 = {key: topo["routers"][key] for key in ["r3"]} - result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r1: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - - write_test_footer(tc_name) - - -def test_BGP_GR_TC_23_p1(request): - """ - Verify that helper routers are deleting stale routes after stale route - timer's expiry. If all the routes are not received from restating node - after 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) - - logger.info( - "Verify Stale Routes are deleted on helper: BGP_GR_TC_23 >> " - "BGP GR [Helper Mode]R1-----R2[Restart Mode] " - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "graceful-restart": {"timer": {"stalepath-time": GR_STALEPATH_TIMER}}, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - }, - } - }, - "r2": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - "preserve-fw-state": True, - }, - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": {"dest_link": {"r2": {"graceful-restart": True}}} - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": {"dest_link": {"r2": {"graceful-restart": True}}} - } - } - }, - }, - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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) - - # Verifying BGP RIB routes received from router R1 - dut = "r1" - input_dict_1 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - logger.info("R2 goes for reload") - kill_router_daemons(tgen, "r2", ["bgpd"]) - - # Modify configuration to delete routes and include disable-eor - input_dict_3 = {"r2": {"bgp": {"graceful-restart": {"disable-eor": True}}}} - - result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) - - # Modify configuration to delete routes and include disable-eor - network = {"ipv4": "102.0.20.1/32", "ipv6": "2::1/128"} - for addr_type in ADDR_TYPES: - input_dict_3 = { - "r2": { - "bgp": { - "address_family": { - addr_type: { - "unicast": { - "advertise_networks": [ - { - "network": network[addr_type], - "no_of_network": 3, - "delete": True, - } - ] - } - } - } - } - } - } - - result = modify_bgp_config_when_bgpd_down(tgen, topo, input_dict_3) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - logger.info("BGPd comes up for r2") - start_router_daemons(tgen, "r2", ["bgpd"]) - - # Wait for stalepath timer - logger.info("Waiting for stalepath timer({} sec..)".format(GR_STALEPATH_TIMER)) - sleep(GR_STALEPATH_TIMER) - - for addr_type in ADDR_TYPES: - clear_bgp(tgen, addr_type, "r2") - - # Verifying RIB routes - dut = "r1" - network = {"ipv4": "102.0.20.4/32", "ipv6": "2::4/128"} - for addr_type in ADDR_TYPES: - input_dict_1 = { - "r1": { - "bgp": { - "address_family": { - addr_type: { - "unicast": { - "advertise_networks": [ - {"network": network[addr_type], "no_of_network": 2} - ] - } - } - } - } - } - } - - # Verify EOR on helper router - result = verify_eor( - tgen, topo, addr_type, input_dict, dut="r1", peer="r2", expected=False - ) - assert ( - result is not True - ), "Testcase {} : Failed \n " "r1: EOR is set to True\n Error: {}".format( - tc_name, result - ) - - # Verifying BGP RIB routes received from router R1 - dut = "r1" - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - write_test_footer(tc_name) - - -def test_BGP_GR_20_p1(request): - """ - Test Objective : Verify that GR routers delete all the routes - received from a node if both the routers are configured as GR - helper node - """ - - 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) - - logger.info( - "[Step 1] : Test Setup " "[Restart Mode]R3-----R1[Restart Mode] Initilized" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in BGP RIB\n Error: {}".format( - tc_name, result - ) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1, expected=False) - assert result is not True, ( - "Testcase {} : Failed \n " - "r3: routes are still present in ZEBRA\n Error: {}".format(tc_name, result) - ) - logger.info(" Expected behavior: {}".format(result)) - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r1", ["bgpd"]) - - for addr_type in ADDR_TYPES: - result = verify_bgp_convergence(tgen, topo) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - write_test_footer(tc_name) - - -def test_BGP_GR_21_p2(request): - """ - Test Objective : VVerify BGP-GR feature when helper node is - a transit router for it's eBGP peers. - """ - - 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) - - logger.info( - "[Step 1] : Test Setup " "[Helper Mode]R6-----R1[Restart Mode] Initilized" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r6": { - "dest_link": { - "r1": {"graceful-restart-disable": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r6": { - "dest_link": { - "r1": {"graceful-restart-disable": True} - } - } - } - } - }, - } - } - }, - "r6": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r6": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r6": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r6") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r6" - ) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - logger.info( - "[Step 2] : Test Setup " - "[Restart Mode]R2-----[Helper Mode]R1[Disable Mode]" - "--------R6[Helper Mode] Initilized" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - "r2": { - "bgp": { - "graceful-restart": { - "graceful-restart": True, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r2", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - dut = "r6" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r2", ["bgpd"]) - - for addr_type in ADDR_TYPES: - result = verify_bgp_convergence(tgen, topo) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes after bringing up BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r6" - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - write_test_footer(tc_name) - - -def test_BGP_GR_22_p2(request): - """ - Test Objective : Verify BGP-GR feature when helper node - is a transit router for it's iBGP peers. - """ - - 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) - - logger.info( - "[Step 1] : Test Setup " "[Helper Mode]R3-----R1[Restart Mode] Initilized" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": { - "graceful-restart-disable": True, - "next_hop_self": True, - } - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r3": { - "dest_link": { - "r1": { - "graceful-restart-disable": True, - "next_hop_self": True, - } - } - } - } - } - }, - } - } - }, - "r3": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r1": { - "dest_link": { - "r3": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r3") - - for addr_type in ADDR_TYPES: - result = verify_graceful_restart( - tgen, topo, addr_type, input_dict, dut="r1", peer="r3" - ) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - logger.info( - "[Step 2] : Test Setup " - "[Restart Mode]R2-----[Helper Mode]R1[Disable Mode]" - "--------R3[Helper Mode] Initilized" - ) - - # Configure graceful-restart - input_dict = { - "r1": { - "bgp": { - "address_family": { - "ipv4": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - "ipv6": { - "unicast": { - "neighbor": { - "r2": { - "dest_link": { - "r1": {"graceful-restart-helper": True} - } - } - } - } - }, - } - } - }, - "r2": {"bgp": {"graceful-restart": {"graceful-restart": True}}}, - } - - configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, dut="r1", peer="r2") - - 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) - - # Verifying BGP RIB routes - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r3" - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Kill BGPd daemon on R1 - kill_router_daemons(tgen, "r2", ["bgpd"]) - - for addr_type in ADDR_TYPES: - # Verifying BGP RIB routes - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r3" - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Start BGPd daemon on R1 - start_router_daemons(tgen, "r2", ["bgpd"]) - - for addr_type in ADDR_TYPES: - result = verify_bgp_convergence(tgen, topo) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r3" - input_dict_1 = {key: topo["routers"][key] for key in ["r1"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_1) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying BGP RIB routes - dut = "r3" - input_dict_2 = {key: topo["routers"][key] for key in ["r2"]} - result = verify_bgp_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - # Verifying RIB routes before shutting down BGPd daemon - result = verify_rib(tgen, addr_type, dut, input_dict_2) - assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) - - 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_topo3/bgp_gr_functionality_topo3.json b/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.json new file mode 100644 index 0000000000..84ddc6119a --- /dev/null +++ b/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.json @@ -0,0 +1,222 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "192.168.0.0", + "ipv4mask": 24, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "192.168.0.0", + "v4mask": 24, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:DB8:F::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "RED" + } + }, + "vrfs": [ + { + "name": "RED", + "id": "1" + } + ], + "bgp": [ + { + "local_as": "100", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + } + } + } + ] + }, + "r2": { + "links": { + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "RED" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "vrfs": [ + { + "name": "RED", + "id": "1" + } + ], + "bgp": [ + { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + } + } + }, + { + "local_as": "200", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + } + } + } + ] + }, + "r3": { + "links": { + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": [ + { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + } + } + } + ] + } + } +}
\ No newline at end of file diff --git a/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py b/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py new file mode 100644 index 0000000000..c19ee06bab --- /dev/null +++ b/tests/topotests/bgp_gr_functionality_topo3/bgp_gr_functionality_topo3.py @@ -0,0 +1,554 @@ +#!/usr/bin/env python +# +# Copyright (c) 2019 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, Inc. ("NetDEF") +# in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +import os +import sys +import time +import pytest +from time import sleep + +import traceback +import ipaddress + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join("../")) +sys.path.append(os.path.join("../lib/")) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib.topogen import Topogen, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +# Import topoJson from lib, to create topology and initial configuration +from lib.topojson import build_config_from_json +from lib.bgp import ( + clear_bgp, + 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, + step, + get_frr_ipv6_linklocal, + create_static_routes, + required_linux_kernel_version, +) + +pytestmark = [pytest.mark.bgpd] + + +# Global variables +BGP_CONVERGENCE = False +GR_RESTART_TIMER = 5 +GR_SELECT_DEFER_TIMER = 5 +GR_STALEPATH_TIMER = 5 +# Global variables +# STATIC_ROUTES=[] +NETWORK1_1 = {"ipv4": "192.0.2.1/32", "ipv6": "2001:DB8::1:1/128"} +NETWORK1_2 = {"ipv4": "192.0.2.2/32", "ipv6": "2001:DB8::2:1/128"} +NETWORK2_1 = {"ipv4": "192.0.2.3/32", "ipv6": "2001:DB8::3:1/128"} +NETWORK2_2 = {"ipv4": "192.0.2.4/32", "ipv6": "2001:DB8::4:1/128"} +NETWORK3_1 = {"ipv4": "192.0.2.5/32", "ipv6": "2001:DB8::5:1/128"} +NETWORK3_2 = {"ipv4": "192.0.2.6/32", "ipv6": "2001:DB8::6:1/128"} +NETWORK4_1 = {"ipv4": "192.0.2.7/32", "ipv6": "2001:DB8::7:1/128"} +NETWORK4_2 = {"ipv4": "192.0.2.8/32", "ipv6": "2001:DB8::8:1/128"} +NETWORK5_1 = {"ipv4": "192.0.2.9/32", "ipv6": "2001:DB8::9:1/128"} +NETWORK5_2 = {"ipv4": "192.0.2.10/32", "ipv6": "2001:DB8::10:1/128"} + +NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} + +PREFERRED_NEXT_HOP = "link_local" + + +def configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, + dut, peer): + """ + result = configure_gr_followed_by_clear(tgen, topo, dut) + assert result is True, \ + "Testcase {} :Failed \n Error {}". \ + format(tc_name, result) + """ + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + for addr_type in ADDR_TYPES: + clear_bgp(tgen, addr_type, dut) + + for addr_type in ADDR_TYPES: + clear_bgp(tgen, addr_type, peer) + + result = verify_bgp_convergence_from_running_config(tgen) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + + return True + +def verify_stale_routes_list(tgen, addr_type, dut, input_dict): + """ + This API is use verify Stale routes on refering the network with next hop value + Parameters + ---------- + * `tgen`: topogen object + * `dut`: input dut router name + * `addr_type` : ip type ipv4/ipv6 + * `input_dict` : input dict, has details of static routes + Usage + ----- + dut = 'r1' + input_dict = { + "r3": { + "static_routes": [ + + { + "network": [NETWORK1_1[addr_type]], + "no_of_ip": 2, + "vrf": "RED" + } + ] + } + } + + result = verify_stale_routes_list(tgen, addr_type, dut, input_dict) + Returns + ------- + errormsg(str) or True + """ + 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(): + if router != dut: + continue + # Verifying RIB routes + command = "show bgp" + # Static routes + sleep(2) + logger.info('Checking router {} BGP RIB:'.format(dut)) + if 'static_routes' in input_dict[routerInput]: + static_routes = input_dict[routerInput]["static_routes"] + for static_route in static_routes: + found_routes = [] + missing_routes = [] + st_found = False + nh_found = False + vrf = static_route.setdefault("vrf", None) + community = static_route.setdefault("community", None) + largeCommunity = \ + static_route.setdefault("largeCommunity", None) + if vrf: + cmd = "{} vrf {} {}".\ + format(command, vrf, addr_type) + if community: + cmd = "{} community {}".\ + format(cmd, community) + if largeCommunity: + cmd = "{} large-community {}".\ + format(cmd, largeCommunity) + else: + cmd = "{} {}".\ + format(command, addr_type) + cmd = "{} json".format(cmd) + rib_routes_json = run_frr_cmd(rnode, cmd, isjson=True) + # Verifying output dictionary rib_routes_json is not empty + if bool(rib_routes_json) == False: + errormsg = "[DUT: {}]: No route found in rib of router". \ + format(router) + return errormsg + elif "warning" in rib_routes_json: + errormsg = "[DUT: {}]: {}". \ + format(router, rib_routes_json["warning"]) + return errormsg + network = static_route["network"] + if "no_of_ip" in static_route: + no_of_ip = static_route["no_of_ip"] + else: + no_of_ip = 1 + # Generating IPs for verification + ip_list = generate_ips(network, no_of_ip) + + for st_rt in ip_list: + st_rt = str(ipaddress.ip_network(st_rt)) + _addr_type = validate_ip_address(st_rt) + if _addr_type != addr_type: + continue + if st_rt in rib_routes_json["routes"]: + st_found = True + + found_routes.append(st_rt) + for mnh in range(0, len(rib_routes_json[ + 'routes'][st_rt])): + found_hops.append([rib_r[ + "ip"] for rib_r in rib_routes_json[ + 'routes'][st_rt][ + mnh]["nexthops"]]) + return found_hops + else: + return 'error msg - no hops found' + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.16") + if result is not True: + pytest.skip("Kernel requirements are not met") + + global ADDR_TYPES + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_gr_functionality_topo3.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Api call verify whether BGP is converged + ADDR_TYPES = check_address_types() + + for addr_type in ADDR_TYPES: + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error:" " {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) +################################################################################ +# +# TEST CASES +# +################################################################################ +def test_bgp_gr_stale_routes(request): + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + + step("Verify the router failures") + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Creating 5 static Routes in Router R3 with NULL0 as Next hop") + for addr_type in ADDR_TYPES: + input_dict_1 = { + "r3": { + "static_routes": [{ + "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type] + }, + { + "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type] + }, + { + "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type] + }, + { + "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type] + }, + { + "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type] + }] + } + } + result = create_static_routes(tgen, input_dict_1) + assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + tc_name, result) + step("verifying Created Route at R3 in VRF default") + for addr_type in ADDR_TYPES: + dut = 'r3' + input_dict_1= {'r3': topo['routers']['r3']} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, \ + "Testcase {} :Failed \n Error {}". \ + format(tc_name, result) + #done + step("verifying Created Route at R2 in VRF default") + for addr_type in ADDR_TYPES: + dut = 'r2' + input_dict_1= {'r2': topo['routers']['r2']} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, \ + "Testcase {} :Failed \n Error {}". \ + format(tc_name, result) + step("importing vrf RED on R2 under Address Family") + for addr_type in ADDR_TYPES: + input_import_vrf={ + "r2": { + "bgp": [ + { + "local_as": 200, + "vrf": "RED", + "address_family": {addr_type: {"unicast": {"import": {"vrf": "default"}}}}, + } + ] + } + } + result = create_router_bgp(tgen, topo,input_import_vrf) + assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) + #done + step("verifying static Routes at R2 in VRF RED") + for addr_type in ADDR_TYPES: + dut = 'r2' + input_dict_1= {'r2': topo['routers']['r2']} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, \ + "Testcase {} :Failed \n Error {}". \ + format(tc_name, result) + + step("verifying static Routes at R1 in VRF RED") + for addr_type in ADDR_TYPES: + dut = 'r1' + input_dict_1= {'r1': topo['routers']['r1']} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, \ + "Testcase {} :Failed \n Error {}". \ + format(tc_name, result) + + step("Configuring Graceful restart at R2 and R3 ") + input_dict = { + "r2": { + + "bgp": { + "local_as": "200", + "graceful-restart": { + "graceful-restart": True, + } + } + }, + "r3": { + "bgp": { + "local_as": "300", + "graceful-restart": { + "graceful-restart": True + } + } + } + } + + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,dut='r2', peer='r3') + + + + step("verify Graceful restart at R2") + for addr_type in ADDR_TYPES: + result = verify_graceful_restart(tgen, topo, addr_type, input_dict, + dut='r2', peer='r3') + assert result is True, \ + "Testcase {} :Failed \n Error {}". \ + format(tc_name, result) + + step("verify Graceful restart at R3") + for addr_type in ADDR_TYPES: + result = verify_graceful_restart(tgen, topo, addr_type, input_dict, + dut='r3', peer='r2') + assert result is True, \ + "Testcase {} :Failed \n Error {}". \ + format(tc_name, result) + + step("Configuring Graceful-restart-disable at R3") + input_dict = { + "r2": { + + "bgp": { + "local_as": "200", + "graceful-restart": { + "graceful-restart": False, + } + } + }, + "r3": { + "bgp": { + "local_as": "300", + "graceful-restart": { + "graceful-restart": False + } + } + } + } + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name,dut='r3', peer='r2') + + step("Verify Graceful-restart-disable at R3") + for addr_type in ADDR_TYPES: + result = verify_graceful_restart(tgen, topo, addr_type, input_dict, + dut='r3', peer='r2') + assert result is True, \ + "Testcase {} :Failed \n Error {}". \ + format(tc_name, result) + + for iteration in range(5): + step("graceful-restart-disable:True at R3") + input_dict = { + "r3": { + "bgp": { + "graceful-restart": { + "graceful-restart-disable": True, + } + } + } + } + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, + dut='r3', peer='r2') + + step("Verifying Routes at R2 on enabling GRD") + dut = 'r2' + for addr_type in ADDR_TYPES: + input_dict_1= {'r2': topo['routers']['r2']} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Verify stale Routes in Router R2 enabling GRD") + for addr_type in ADDR_TYPES: + dut = "r2" + protocol = "bgp" + verify_nh_for_static_rtes = { + "r3": { + "static_routes": [ + + { + "network": [NETWORK1_1[addr_type]], + "no_of_ip": 2, + "vrf": "RED" + } + ] + } + } + bgp_rib_next_hops = verify_stale_routes_list( + tgen, addr_type, dut, verify_nh_for_static_rtes) + assert (len(bgp_rib_next_hops)== 1) is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, bgp_rib_next_hops,expected=True) + + step("graceful-restart-disable:False at R3") + input_dict = { + "r3": { + "bgp": { + "graceful-restart": { + "graceful-restart-disable": False, + } + } + } + } + configure_gr_followed_by_clear(tgen, topo, input_dict, tc_name, + dut='r3', peer='r2') + + step("Verifying Routes at R2 on disabling GRD") + dut = 'r2' + for addr_type in ADDR_TYPES: + input_dict_1= {'r2': topo['routers']['r2']} + result = verify_bgp_rib(tgen, addr_type, dut, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Verify stale Routes in Router R2 on disabling GRD") + for addr_type in ADDR_TYPES: + dut = "r2" + protocol = "bgp" + verify_nh_for_static_rtes = { + "r3": { + "static_routes": [ + + { + "network": [NETWORK1_1[addr_type]], + "no_of_ip": 2, + "vrf": "RED" + } + ] + } + } + bgp_rib_next_hops = verify_stale_routes_list(tgen, addr_type, dut, verify_nh_for_static_rtes) + + stale_route_status=len(bgp_rib_next_hops)== 1 + assert stale_route_status is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, stale_route_status,expected=True) + write_test_footer(tc_name) + diff --git a/tests/topotests/bgp_ipv6_rtadv/r1/zebra.conf b/tests/topotests/bgp_ipv6_rtadv/r1/zebra.conf index f95c3b07a7..1397c7f5fd 100644 --- a/tests/topotests/bgp_ipv6_rtadv/r1/zebra.conf +++ b/tests/topotests/bgp_ipv6_rtadv/r1/zebra.conf @@ -1,5 +1,5 @@ -debug zebra packet recv -debug zebra packet send +! debug zebra packet recv +! debug zebra packet send log stdout interface lo ip address 10.254.254.1/32 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ldpd.conf index 3c6cbddc2a..f7f2714dae 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ldpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r1/ldpd.conf @@ -1,13 +1,13 @@ hostname r1 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ldpd.conf index bfdef21b75..c4056e01a8 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ldpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r2/ldpd.conf @@ -1,13 +1,13 @@ hostname r2 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ldpd.conf index dbf1d72b5f..48956cb996 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ldpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r3/ldpd.conf @@ -1,13 +1,13 @@ hostname r3 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ldpd.conf index 8f3533527d..1d04aa07e7 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ldpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/r4/ldpd.conf @@ -1,13 +1,13 @@ hostname r4 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 4.4.4.4 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py index 789f93b837..6cd92e293d 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_direct/scripts/adjacencies.py @@ -7,11 +7,18 @@ luCommand("ce1", 'vtysh -c "show bgp summary"', " 00:0", "wait", "Adjacencies up luCommand("ce2", 'vtysh -c "show bgp summary"', " 00:0", "wait", "Adjacencies up", 180) luCommand("ce3", 'vtysh -c "show bgp summary"', " 00:0", "wait", "Adjacencies up", 180) luCommand( + "r1", 'vtysh -c "show ip route ospf"', "2.2.2.2", "wait", "OSPF Route has Arrived", 60) +luCommand( "r1", "ping 2.2.2.2 -c 1", " 0. packet loss", "wait", "PE->P2 (loopback) ping", 60 ) luCommand( + "r3", 'vtysh -c "show ip route ospf"', "2.2.2.2", "wait", "OSPF Route has Arrived", 60) +luCommand( "r3", "ping 2.2.2.2 -c 1", " 0. packet loss", "wait", "PE->P2 (loopback) ping", 60 ) + +luCommand( + "r4", 'vtysh -c "show ip route ospf"', "2.2.2.2", "wait", "OSPF Route has Arrived", 60) luCommand( "r4", "ping 2.2.2.2 -c 1", " 0. packet loss", "wait", "PE->P2 (loopback) ping", 60 ) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ldpd.conf index de84f2bc3f..168b2d4802 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ldpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r1/ldpd.conf @@ -2,13 +2,13 @@ hostname r1 log file ldpd.log password zebra ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ldpd.conf index 411ba85ef6..847be20934 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ldpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r2/ldpd.conf @@ -2,13 +2,13 @@ hostname r2 log file ldpd.log password zebra ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ldpd.conf index 6002895f48..a620739ffb 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ldpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r3/ldpd.conf @@ -2,13 +2,13 @@ hostname r3 password zebra log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ldpd.conf b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ldpd.conf index 292e9a7187..617d3a76d5 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ldpd.conf +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/r4/ldpd.conf @@ -2,13 +2,13 @@ hostname r4 password zebra log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 4.4.4.4 diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py index a5f95f94bf..91a7adf997 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_linux_mpls.py @@ -4,7 +4,7 @@ from lib import topotest ret = luCommand( "r2", "ip -M route show", - "\d*(?= via inet 10.0.2.4 dev r2-eth1)", + r"\d*(?= via inet 10.0.2.4 dev r2-eth1)", "wait", "See mpls route to r4", ) @@ -16,7 +16,7 @@ if ret != False and found != None: ret = luCommand( "r2", "ip -M route show", - "\d*(?= via inet 10.0.1.1 dev r2-eth0)", + r"\d*(?= via inet 10.0.1.1 dev r2-eth0)", "wait", "See mpls route to r1", ) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py index c8c03025c2..550ff93ea3 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py @@ -281,10 +281,109 @@ bgpribRequireVpnRoutes( # r1 vtysh -c "show bgp vrf r1-cust1 ipv4" - ######################################################################## # PE routers: VRFs contain routes from remote customer nets ######################################################################## +# First let's spot check and ensure that some of the routes +# have showed up and been best path'd +# After the first two are good. It's probably ok +# to look at the rest of the routes in the vrf +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.1.0.0/24"', + "2 available, best", + "wait", + "Ensure 5.1.0.0 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.1.1.0/24"', + "2 available, best", + "wait", + "Ensure 5.1.1.0 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.1.2.0/24"', + "1 available, best", + "wait", + "Ensure 5.1.2.0 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.1.3.0/24"', + "1 available, best", + "wait", + "Ensure 5.1.3.0 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.4.2.0/24"', + "1 available, best", + "wait", + "Ensure 5.4.2.0 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.4.2.0/24"', + "1 available, best", + "wait", + "Ensure 5.4.3.0 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 6.0.1.0/24"', + "3 available, best", + "wait", + "Ensure 6.0.1.0 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 6.0.2.0/24"', + "3 available, best", + "wait", + "Ensure 6.0.2.0 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 99.0.0.1/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.1 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 99.0.0.2/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.2 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 99.0.0.3/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.3 shows up on r1", + 10, +) +luCommand( + "r1", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 99.0.0.4/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.4 shows up on r1", + 10, +) want_r1_remote_cust1_routes = [ {"p": "5.1.0.0/24", "n": "3.3.3.3", "bp": False}, {"p": "5.1.0.0/24", "n": "99.0.0.1", "bp": True}, @@ -297,9 +396,9 @@ want_r1_remote_cust1_routes = [ {"p": "6.0.1.0/24", "n": "3.3.3.3", "bp": False}, {"p": "6.0.1.0/24", "n": "4.4.4.4", "bp": False}, {"p": "6.0.1.0/24", "n": "99.0.0.1", "bp": True}, - {"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": False}, + {"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": True}, {"p": "6.0.2.0/24", "n": "4.4.4.4", "bp": False}, - {"p": "6.0.2.0/24", "n": "99.0.0.1", "bp": True}, + {"p": "6.0.2.0/24", "n": "99.0.0.1", "bp": False}, {"p": "99.0.0.1/32", "n": "192.168.1.2", "bp": True}, {"p": "99.0.0.2/32", "n": "3.3.3.3"}, {"p": "99.0.0.3/32", "n": "4.4.4.4"}, @@ -314,6 +413,103 @@ bgpribRequireUnicastRoutes( debug=False, ) + +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.1.0.0/24"', + "2 available, best", + "wait", + "Ensure 5.1.0.0 shows up r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.1.1.0/24"', + "2 available, best", + "wait", + "Ensure 5.1.1.0 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.1.2.0/24"', + "1 available, best", + "wait", + "Ensure 5.1.2.0 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.1.3.0/24"', + "1 available, best", + "wait", + "Ensure 5.1.3.0 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.4.3.0/24"', + "1 available, best", + "wait", + "Ensure 5.4.3.0 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.4.3.0/24"', + "1 available, best", + "wait", + "Ensure 5.4.3.0 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.4.3.0/24"', + "1 available, best", + "wait", + "Ensure 5.4.3.0 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 6.0.1.0/24"', + "3 available, best", + "wait", + "Ensure 6.0.1.0 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 6.0.2.0/24"', + "3 available, best", + "wait", + "Ensure 6.0.2.0 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 99.0.0.1/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.1 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 99.0.0.3/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.3 shows up on r3", + 10, +) +luCommand( + "r3", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 99.0.0.4/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.4 shows up on r3", + 10, +) want_r3_remote_cust1_routes = [ {"p": "5.1.0.0/24", "n": "1.1.1.1", "bp": True}, {"p": "5.1.0.0/24", "n": "99.0.0.2", "bp": False}, @@ -326,9 +522,9 @@ want_r3_remote_cust1_routes = [ {"p": "6.0.1.0/24", "n": "1.1.1.1", "bp": True}, {"p": "6.0.1.0/24", "n": "4.4.4.4", "bp": False}, {"p": "6.0.1.0/24", "n": "99.0.0.2", "bp": False}, - {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": False}, + {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": True}, {"p": "6.0.2.0/24", "n": "4.4.4.4", "bp": False}, - {"p": "6.0.2.0/24", "n": "99.0.0.2", "bp": True}, + {"p": "6.0.2.0/24", "n": "99.0.0.2", "bp": False}, {"p": "99.0.0.1/32", "n": "1.1.1.1", "bp": True}, {"p": "99.0.0.3/32", "n": "4.4.4.4", "bp": True}, {"p": "99.0.0.4/32", "n": "4.4.4.4", "bp": True}, @@ -342,6 +538,70 @@ bgpribRequireUnicastRoutes( debug=False, ) +luCommand( + "r4", + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 5.1.0.0/24"', + "2 available, best", + "wait", + "Ensure 5.1.0.0 shows up on r4", + 10, +) +luCommand( + "r4", + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 5.1.1.0/24"', + "2 available, best", + "wait", + "Ensure 5.1.1.0 shows up on r4", + 10, +) +luCommand( + "r4", + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 6.0.1.0/24"', + "4 available, best", + "wait", + "Ensure 6.0.1.0 shows up on r4", + 10, +) +luCommand( + "r4", + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 6.0.2.0/24"', + "4 available, best", + "wait", + "Ensure 6.0.2.0 shows up on r4", + 10, +) +luCommand( + "r4", + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 99.0.0.1/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.1 shows up on r4", + 10, +) +luCommand( + "r4", + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 99.0.0.2/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.2 shows up on r4", + 10, +) +luCommand( + "r4", + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 99.0.0.3/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.3 shows up on r4", + 10, +) +luCommand( + "r4", + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 99.0.0.4/32"', + "1 available, best", + "wait", + "Ensure 99.0.0.4 shows up on r4", + 10, +) want_r4_remote_cust1_routes = [ {"p": "5.1.0.0/24", "n": "1.1.1.1", "bp": True}, {"p": "5.1.0.0/24", "n": "3.3.3.3", "bp": False}, @@ -351,10 +611,10 @@ want_r4_remote_cust1_routes = [ {"p": "6.0.1.0/24", "n": "3.3.3.3", "bp": False}, {"p": "6.0.1.0/24", "n": "99.0.0.3", "bp": False}, {"p": "6.0.1.0/24", "n": "99.0.0.4", "bp": False}, - {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": False}, + {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": True}, {"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": False}, {"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": False}, - {"p": "6.0.2.0/24", "n": "99.0.0.4", "bp": True}, + {"p": "6.0.2.0/24", "n": "99.0.0.4", "bp": False}, {"p": "99.0.0.1/32", "n": "1.1.1.1", "bp": True}, {"p": "99.0.0.2/32", "n": "3.3.3.3", "bp": True}, {"p": "99.0.0.3/32", "n": "192.168.1.2", "bp": True}, @@ -378,9 +638,9 @@ want_r4_remote_cust2_routes = [ {"p": "6.0.1.0/24", "n": "3.3.3.3", "bp": False}, {"p": "6.0.1.0/24", "n": "99.0.0.3", "bp": False}, {"p": "6.0.1.0/24", "n": "99.0.0.4", "bp": False}, - {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": False}, + {"p": "6.0.2.0/24", "n": "1.1.1.1", "bp": True}, {"p": "6.0.2.0/24", "n": "3.3.3.3", "bp": False}, - {"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": True}, + {"p": "6.0.2.0/24", "n": "99.0.0.3", "bp": False}, {"p": "6.0.2.0/24", "n": "99.0.0.4", "bp": False}, {"p": "99.0.0.1/32", "n": "1.1.1.1", "bp": True}, {"p": "99.0.0.2/32", "n": "3.3.3.3", "bp": True}, @@ -574,8 +834,8 @@ luCommand( luCommand( "ce1", 'vtysh -c "show bgp ipv4 uni 6.0.2.0"', - "1 available, best .*192.168.1.1.* Local.* 99.0.0.1 from 0.0.0.0 .99.0.0.1" - + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .First path received" + "2 available, best .*192.168.1.1.* Local.* 99.0.0.1 from 0.0.0.0 .99.0.0.1" + + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .Weight" + ".* Community: 0:67.* Extended Community: RT:89:123.* Large Community: 12:34:11", "pass", "Redundant route 2 details", @@ -583,8 +843,8 @@ luCommand( luCommand( "ce2", 'vtysh -c "show bgp ipv4 uni 6.0.2.0"', - "1 available, best .*192.168.1.1.* Local.* 99.0.0.2 from 0.0.0.0 .99.0.0.2" - + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .First path received" + "2 available, best .*192.168.1.1.* Local.* 99.0.0.2 from 0.0.0.0 .99.0.0.2" + + ".* Origin IGP, metric 100, localpref 100, weight 32768, valid, sourced, local, best .Weight" + ".* Community: 0:67.* Extended Community: RT:89:123.* Large Community: 12:34:12", "pass", "Redundant route 2 details", @@ -603,7 +863,7 @@ luCommand( 'vtysh -c "show bgp ipv4 uni 6.0.2.0"', "2 available, best .*192.168.1.1.* Local.* 192.168.1.1 from 192.168.1.1 .192.168.1.1" + ".* Origin IGP, metric 100, localpref 100, valid, internal" - + ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:14", + + ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:11", "pass", "Redundant route 2 details", ) @@ -612,7 +872,7 @@ luCommand( 'vtysh -c "show bgp vrf ce4-cust2 ipv4 6.0.2.0"', "2 available, best .*192.168.2.1.* Local.* 192.168.2.1 from 192.168.2.1 .192.168.2.1" + ".* Origin IGP, metric 100, localpref 100, valid, internal" - + ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:13", + + ".* Community: 0:67.* Extended Community: RT:52:100 RT:89:123.* Large Community: 12:34:11", "pass", "Redundant route 2 details", ) diff --git a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py index 9f100b7c30..eaa6aa4c30 100644 --- a/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py +++ b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/scale_up.py @@ -21,7 +21,7 @@ for rtr in rtrs: ret = luCommand( rtr, 'vtysh -c "show memory"', - "zebra: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*) .*bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)", + r"zebra: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*) .*bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)", "none", "collect bgpd memory stats", ) @@ -188,7 +188,7 @@ else: ret = luCommand( rtr, 'vtysh -c "show memory"', - "zebra: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*) .*bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)", + r"zebra: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*) .*bgpd: System allocator statistics: Total heap allocated: *(\d*) ([A-Za-z]*)", "none", "collect bgpd memory stats", ) diff --git a/tests/topotests/bgp_link_bw_ip/r4/bgpd.conf b/tests/topotests/bgp_link_bw_ip/r4/bgpd.conf index d34db982c9..88b260f7e2 100644 --- a/tests/topotests/bgp_link_bw_ip/r4/bgpd.conf +++ b/tests/topotests/bgp_link_bw_ip/r4/bgpd.conf @@ -1,9 +1,9 @@ ! log file bgpd.log ! -debug bgp updates -debug bgp zebra -debug bgp bestpath 198.10.1.1/32 +! debug bgp updates +! debug bgp zebra +! debug bgp bestpath 198.10.1.1/32 ! hostname r4 ! diff --git a/tests/topotests/bgp_llgr/__init__.py b/tests/topotests/bgp_llgr/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_llgr/__init__.py diff --git a/tests/topotests/bgp_llgr/r0/bgpd.conf b/tests/topotests/bgp_llgr/r0/bgpd.conf new file mode 100644 index 0000000000..d93ee193bc --- /dev/null +++ b/tests/topotests/bgp_llgr/r0/bgpd.conf @@ -0,0 +1,10 @@ +router bgp 65000 + no bgp ebgp-requires-policy + bgp graceful-restart + bgp graceful-restart restart-time 0 + bgp long-lived-graceful-restart stale-time 20 + neighbor 192.168.0.2 remote-as external + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_llgr/r0/zebra.conf b/tests/topotests/bgp_llgr/r0/zebra.conf new file mode 100644 index 0000000000..4d11b67b26 --- /dev/null +++ b/tests/topotests/bgp_llgr/r0/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 172.16.1.1/32 +! +int r0-eth0 + ip address 192.168.0.1/24 +! diff --git a/tests/topotests/bgp_llgr/r1/bgpd.conf b/tests/topotests/bgp_llgr/r1/bgpd.conf new file mode 100644 index 0000000000..f8c9877730 --- /dev/null +++ b/tests/topotests/bgp_llgr/r1/bgpd.conf @@ -0,0 +1,10 @@ +router bgp 65001 + no bgp ebgp-requires-policy + bgp graceful-restart + bgp graceful-restart restart-time 0 + bgp long-lived-graceful-restart stale-time 20 + neighbor 192.168.1.2 remote-as external + address-family ipv4 unicast + redistribute connected + exit-address-family +! diff --git a/tests/topotests/bgp_llgr/r1/zebra.conf b/tests/topotests/bgp_llgr/r1/zebra.conf new file mode 100644 index 0000000000..1782edc2a5 --- /dev/null +++ b/tests/topotests/bgp_llgr/r1/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ip address 172.16.1.1/32 +! +int r1-eth0 + ip address 192.168.1.1/24 +! diff --git a/tests/topotests/bgp_llgr/r2/bgpd.conf b/tests/topotests/bgp_llgr/r2/bgpd.conf new file mode 100644 index 0000000000..ea8e6beef1 --- /dev/null +++ b/tests/topotests/bgp_llgr/r2/bgpd.conf @@ -0,0 +1,9 @@ +router bgp 65002 + no bgp ebgp-requires-policy + bgp graceful-restart + bgp long-lived-graceful-restart stale-time 20 + neighbor 192.168.0.1 remote-as external + neighbor 192.168.1.1 remote-as external + neighbor 192.168.2.1 remote-as external + address-family ipv4 unicast + neighbor 192.168.1.1 weight 100 diff --git a/tests/topotests/bgp_llgr/r2/zebra.conf b/tests/topotests/bgp_llgr/r2/zebra.conf new file mode 100644 index 0000000000..0fa589f3a9 --- /dev/null +++ b/tests/topotests/bgp_llgr/r2/zebra.conf @@ -0,0 +1,10 @@ +! +int r2-eth0 + ip address 192.168.0.2/24 +! +int r2-eth1 + ip address 192.168.1.2/24 +! +int r2-eth2 + ip address 192.168.2.2/24 +! diff --git a/tests/topotests/bgp_llgr/r3/bgpd.conf b/tests/topotests/bgp_llgr/r3/bgpd.conf new file mode 100644 index 0000000000..d73fdccb1d --- /dev/null +++ b/tests/topotests/bgp_llgr/r3/bgpd.conf @@ -0,0 +1,6 @@ +router bgp 65003 + bgp router-id 192.168.2.1 + no bgp ebgp-requires-policy + bgp graceful-restart + bgp long-lived-graceful-restart stale-time 20 + neighbor 192.168.2.2 remote-as external diff --git a/tests/topotests/bgp_llgr/r3/zebra.conf b/tests/topotests/bgp_llgr/r3/zebra.conf new file mode 100644 index 0000000000..8a7941b5a8 --- /dev/null +++ b/tests/topotests/bgp_llgr/r3/zebra.conf @@ -0,0 +1,4 @@ +! +int r3-eth0 + ip address 192.168.2.1/24 +! diff --git a/tests/topotests/bgp_llgr/test_bgp_llgr.py b/tests/topotests/bgp_llgr/test_bgp_llgr.py new file mode 100644 index 0000000000..df4f401d02 --- /dev/null +++ b/tests/topotests/bgp_llgr/test_bgp_llgr.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python + +# Copyright (c) 2021 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test if BGP Long-lived Graceful Restart capability works: + Check if we can see 172.16.1.1/32 after initial converge in R3. + Check if we can see 172.16.1.1/32 as best selected due to higher weigth in R2. + Kill bgpd in R1. + Check if we can see 172.16.1.1/32 as stale in R2. + Check if we can see 172.16.1.1/32 depreferenced due to LLGR_STALE in R2. + Check if we can see 172.16.1.1/32 after R1 was killed in R3. +""" + +import os +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 ( + kill_router_daemons, + start_router_daemons, + step, +) + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(0, 5): + tgen.add_router("r{}".format(routern)) + + switch = tgen.add_switch("s0") + switch.add_link(tgen.gears["r0"]) + switch.add_link(tgen.gears["r2"]) + + 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["r3"]) + + +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)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_llgr(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r3 = tgen.gears["r3"] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp json")) + expected = { + "routes": { + "172.16.1.1/32": [{"nexthops": [{"ip": "192.168.2.2", "used": True}]}] + } + } + return topotest.json_cmp(output, expected) + + step("Check if we can see 172.16.1.1/32 after initial converge in R3") + test_func = functools.partial(_bgp_converge, r3) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Cannot see 172.16.1.1/32 in r3" + + def _bgp_weight_prefered_route(router): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.1.1/32 json")) + expected = { + "paths": [ + { + "bestpath": {"selectionReason": "Weight"}, + "nexthops": [ + { + "ip": "192.168.1.1", + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + step( + "Check if we can see 172.16.1.1/32 as best selected due to higher weigth in R2" + ) + test_func = functools.partial(_bgp_weight_prefered_route, r2) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert ( + result is None + ), "Prefix 172.16.1.1/32 is not selected as bests path due to weight" + + step("Kill bgpd in R1") + kill_router_daemons(tgen, "r1", ["bgpd"]) + + def _bgp_stale_route(router): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.1.1/32 json")) + expected = {"paths": [{"community": {"string": "llgr-stale"}, "stale": True}]} + return topotest.json_cmp(output, expected) + + step("Check if we can see 172.16.1.1/32 as stale in R2") + test_func = functools.partial(_bgp_stale_route, r2) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Prefix 172.16.1.1/32 is not stale" + + def _bgp_llgr_depreference_route(router): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.1.1/32 json")) + expected = { + "paths": [ + { + "bestpath": {"selectionReason": "First path received"}, + "nexthops": [ + { + "ip": "192.168.0.1", + } + ], + } + ] + } + return topotest.json_cmp(output, expected) + + step("Check if we can see 172.16.1.1/32 depreferenced due to LLGR_STALE in R2") + test_func = functools.partial(_bgp_llgr_depreference_route, r2) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Prefix 172.16.1.1/32 is not depreferenced due to LLGR_STALE" + + step("Check if we can see 172.16.1.1/32 after R1 was killed in R3") + test_func = functools.partial(_bgp_converge, r3) + success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Cannot see 172.16.1.1/32 in r3" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_lu_topo1/R1/bgpd.conf b/tests/topotests/bgp_lu_topo1/R1/bgpd.conf index 1bdb4c7a3e..a164152e0e 100644 --- a/tests/topotests/bgp_lu_topo1/R1/bgpd.conf +++ b/tests/topotests/bgp_lu_topo1/R1/bgpd.conf @@ -1,6 +1,6 @@ ! -debug bgp labelpool -debug bgp zebra +! debug bgp labelpool +! debug bgp zebra ! router bgp 1 bgp router-id 10.0.0.1 diff --git a/tests/topotests/bgp_lu_topo1/R1/zebra.conf b/tests/topotests/bgp_lu_topo1/R1/zebra.conf index 4f6fee579f..f8a9ce4e03 100644 --- a/tests/topotests/bgp_lu_topo1/R1/zebra.conf +++ b/tests/topotests/bgp_lu_topo1/R1/zebra.conf @@ -1,6 +1,6 @@ -debug zebra events -debug zebra dplane -debug zebra mpls +! debug zebra events +! debug zebra dplane +! debug zebra mpls ! interface R1-eth0 ip address 10.0.0.1/24 diff --git a/tests/topotests/bgp_lu_topo1/R2/bgpd.conf b/tests/topotests/bgp_lu_topo1/R2/bgpd.conf index bac608e1c3..d35bbb886b 100644 --- a/tests/topotests/bgp_lu_topo1/R2/bgpd.conf +++ b/tests/topotests/bgp_lu_topo1/R2/bgpd.conf @@ -1,5 +1,5 @@ -debug bgp labelpool -debug bgp zebra +! debug bgp labelpool +! debug bgp zebra ! router bgp 2 bgp router-id 10.0.0.2 diff --git a/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json b/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json index 29e6c2cbf7..9c817e8075 100644 --- a/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json +++ b/tests/topotests/bgp_lu_topo1/R2/labelpool.summ.json @@ -1,8 +1,8 @@ { - "Ledger":506, - "InUse":506, + "Ledger":0, + "InUse":0, "Requests":0, - "LabelChunks":11, + "LabelChunks":0, "Pending":0, "Reconnects":0 } diff --git a/tests/topotests/bgp_lu_topo1/R2/zebra.conf b/tests/topotests/bgp_lu_topo1/R2/zebra.conf index 33ee53efe7..083da3ef9c 100644 --- a/tests/topotests/bgp_lu_topo1/R2/zebra.conf +++ b/tests/topotests/bgp_lu_topo1/R2/zebra.conf @@ -1,7 +1,7 @@ ! -debug zebra events -debug zebra dplane -debug zebra mpls +! debug zebra events +! debug zebra dplane +! debug zebra mpls ! interface R2-eth0 ip address 10.0.0.2/24 diff --git a/tests/topotests/bgp_lu_topo1/R3/bgpd.conf b/tests/topotests/bgp_lu_topo1/R3/bgpd.conf index b42df022e0..31d26ea1ed 100644 --- a/tests/topotests/bgp_lu_topo1/R3/bgpd.conf +++ b/tests/topotests/bgp_lu_topo1/R3/bgpd.conf @@ -1,6 +1,6 @@ log file /tmp/bgpd.log ! -debug bgp updates +! debug bgp updates ! router bgp 2 bgp router-id 10.0.1.3 diff --git a/tests/topotests/bgp_lu_topo1/R3/zebra.conf b/tests/topotests/bgp_lu_topo1/R3/zebra.conf index 524978bff6..ea4a1482dd 100644 --- a/tests/topotests/bgp_lu_topo1/R3/zebra.conf +++ b/tests/topotests/bgp_lu_topo1/R3/zebra.conf @@ -1,8 +1,8 @@ log file /tmp/zebra.log ! -debug zebra events -debug zebra packet detail -debug zebra mpls +! debug zebra events +! debug zebra packet detail +! debug zebra mpls ! interface R3-eth0 ip address 10.0.1.3/24 diff --git a/tests/topotests/bgp_lu_topo2/R1/bgpd.conf b/tests/topotests/bgp_lu_topo2/R1/bgpd.conf new file mode 100644 index 0000000000..9fe4026977 --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R1/bgpd.conf @@ -0,0 +1,29 @@ +! +no log unique-id +! +! debug bgp labelpool +! debug bgp zebra +! +router bgp 1 + bgp router-id 10.0.0.1 + timers bgp 3 9 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.0.2 remote-as 2 +! neighbor 10.0.0.2 solo + neighbor 10.0.0.2 timers connect 10 + neighbor 10.0.4.4 remote-as 4 +! neighbor 10.0.4.4 solo + neighbor 10.0.4.4 timers connect 10 +! + address-family ipv4 unicast + no neighbor 10.0.0.2 activate + no neighbor 10.0.4.4 activate + redistribute connected + exit-address-family + ! + address-family ipv4 labeled-unicast + neighbor 10.0.0.2 activate + neighbor 10.0.4.4 activate + exit-address-family +! diff --git a/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json b/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json new file mode 100644 index 0000000000..77705e8d35 --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R1/labelpool.summ.json @@ -0,0 +1,8 @@ +{ + "Ledger":51, + "InUse":51, + "Requests":0, + "LabelChunks":2, + "Pending":0, + "Reconnects":0 +} diff --git a/tests/topotests/bgp_lu_topo2/R1/zebra.conf b/tests/topotests/bgp_lu_topo2/R1/zebra.conf new file mode 100644 index 0000000000..64c34a3bc3 --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R1/zebra.conf @@ -0,0 +1,13 @@ +! +no log unique-id +! +! debug zebra events +! debug zebra rib det +! debug zebra dplane +! debug zebra mpls +! +interface R1-eth0 + ip address 10.0.0.1/24 +! +interface R1-eth1 + ip address 10.0.4.1/24 diff --git a/tests/topotests/bgp_lu_topo2/R2/bgpd.conf b/tests/topotests/bgp_lu_topo2/R2/bgpd.conf new file mode 100644 index 0000000000..917060c4df --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R2/bgpd.conf @@ -0,0 +1,27 @@ +! +no log unique-id +! +! debug bgp labelpool +! debug bgp zebra +! +router bgp 2 + bgp router-id 10.0.0.2 + no bgp ebgp-requires-policy + no bgp network import-check + timers bgp 3 9 + neighbor 10.0.0.1 remote-as 1 + neighbor 10.0.0.1 timers connect 10 + neighbor 10.0.1.3 remote-as 2 + neighbor 10.0.1.3 update-source 10.0.1.2 + neighbor 10.0.1.3 timers connect 10 +! + address-family ipv4 unicast + network 10.0.0.0/24 + neighbor 10.0.1.3 activate + no neighbor 10.0.0.1 activate + exit-address-family + ! + address-family ipv4 labeled-unicast + neighbor 10.0.0.1 activate + exit-address-family +! diff --git a/tests/topotests/bgp_lu_topo2/R2/labelpool.summ.json b/tests/topotests/bgp_lu_topo2/R2/labelpool.summ.json new file mode 100644 index 0000000000..eb1ae93b6c --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R2/labelpool.summ.json @@ -0,0 +1,8 @@ +{ + "Ledger":1, + "InUse":1, + "Requests":0, + "LabelChunks":1, + "Pending":0, + "Reconnects":0 +} diff --git a/tests/topotests/bgp_lu_topo2/R2/zebra.conf b/tests/topotests/bgp_lu_topo2/R2/zebra.conf new file mode 100644 index 0000000000..f465914f63 --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R2/zebra.conf @@ -0,0 +1,14 @@ +! +no log unique-id +! +! debug zebra events +! debug zebra dplane +! debug zebra mpls +! debug zebra rib det +! +interface R2-eth0 + ip address 10.0.0.2/24 +! +interface R2-eth1 + ip address 10.0.1.2/24 +!
\ No newline at end of file diff --git a/tests/topotests/bgp_lu_topo2/R3/bgpd.conf b/tests/topotests/bgp_lu_topo2/R3/bgpd.conf new file mode 100644 index 0000000000..6443445b80 --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R3/bgpd.conf @@ -0,0 +1,70 @@ +log file /tmp/bgpd.log +no log unique-id +! +! +! debug bgp updates +! +router bgp 2 + bgp router-id 10.0.1.3 + no bgp ebgp-requires-policy + no bgp network import-check + timers bgp 3 9 + neighbor 10.0.1.2 remote-as 2 + neighbor 10.0.1.2 timers connect 10 + ! + address-family ipv4 unicast + neighbor 10.0.1.2 activate + network 10.0.1.0/24 + network 11.0.0.1/32 + network 11.0.0.2/32 + network 11.0.0.3/32 + network 11.0.0.4/32 + network 11.0.0.5/32 + network 11.0.0.6/32 + network 11.0.0.7/32 + network 11.0.0.8/32 + network 11.0.0.9/32 + network 11.0.0.10/32 + network 11.0.0.11/32 + network 11.0.0.12/32 + network 11.0.0.13/32 + network 11.0.0.14/32 + network 11.0.0.15/32 + network 11.0.0.16/32 + network 11.0.0.17/32 + network 11.0.0.18/32 + network 11.0.0.19/32 + network 11.0.0.20/32 + network 11.0.0.21/32 + network 11.0.0.22/32 + network 11.0.0.23/32 + network 11.0.0.24/32 + network 11.0.0.25/32 + network 11.0.0.26/32 + network 11.0.0.27/32 + network 11.0.0.28/32 + network 11.0.0.29/32 + network 11.0.0.30/32 + network 11.0.0.31/32 + network 11.0.0.32/32 + network 11.0.0.33/32 + network 11.0.0.34/32 + network 11.0.0.35/32 + network 11.0.0.36/32 + network 11.0.0.37/32 + network 11.0.0.38/32 + network 11.0.0.39/32 + network 11.0.0.40/32 + network 11.0.0.41/32 + network 11.0.0.42/32 + network 11.0.0.43/32 + network 11.0.0.44/32 + network 11.0.0.45/32 + network 11.0.0.46/32 + network 11.0.0.47/32 + network 11.0.0.48/32 + network 11.0.0.49/32 + network 11.0.0.50/32 + exit-address-family + ! +! diff --git a/tests/topotests/bgp_lu_topo2/R3/staticd.conf b/tests/topotests/bgp_lu_topo2/R3/staticd.conf new file mode 100644 index 0000000000..867fc5a837 --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R3/staticd.conf @@ -0,0 +1,5 @@ +log file /tmp/staticd.log +no log unique-id +! +! +ip route 10.0.4.0/24 10.0.1.2 diff --git a/tests/topotests/bgp_lu_topo2/R3/zebra.conf b/tests/topotests/bgp_lu_topo2/R3/zebra.conf new file mode 100644 index 0000000000..dd24deb214 --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R3/zebra.conf @@ -0,0 +1,11 @@ +log file /tmp/zebra.log +no log unique-id +! +! +! debug zebra events +! debug zebra packet detail +! debug zebra mpls +! +interface R3-eth0 + ip address 10.0.1.3/24 +! diff --git a/tests/topotests/bgp_lu_topo2/R4/bgpd.conf b/tests/topotests/bgp_lu_topo2/R4/bgpd.conf new file mode 100644 index 0000000000..45c81fb93e --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R4/bgpd.conf @@ -0,0 +1,23 @@ +! +no log unique-id +! +! debug bgp labelpool +! debug bgp zebra +! +router bgp 4 + bgp router-id 10.0.4.4 + timers bgp 3 9 + no bgp ebgp-requires-policy + no bgp network import-check + neighbor 10.0.4.1 remote-as 1 + neighbor 10.0.4.1 solo + neighbor 10.0.4.1 timers connect 10 +! + address-family ipv4 unicast + no neighbor 10.0.4.1 activate + exit-address-family + ! + address-family ipv4 labeled-unicast + neighbor 10.0.4.1 activate + exit-address-family +! diff --git a/tests/topotests/bgp_lu_topo2/R4/zebra.conf b/tests/topotests/bgp_lu_topo2/R4/zebra.conf new file mode 100644 index 0000000000..53ffe51e06 --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/R4/zebra.conf @@ -0,0 +1,9 @@ +no log unique-id +! +! debug zebra events +! debug zebra dplane +! debug zebra mpls +! debug zebra rib det +! +interface R4-eth0 + ip address 10.0.4.4/24 diff --git a/tests/topotests/bgp_lu_topo2/test_bgp_lu2.py b/tests/topotests/bgp_lu_topo2/test_bgp_lu2.py new file mode 100644 index 0000000000..fc9d2c433a --- /dev/null +++ b/tests/topotests/bgp_lu_topo2/test_bgp_lu2.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python +# +# test_bgp_lu2.py +# +# Part of FRR/NetDEF Topology Tests +# +# Copyright (c) 2020 by Volta Networks +# Copyright (c) 2021 by Nvidia, Inc. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +test_bgp_lu2.py: Test BGP LU label allocation +""" + +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 +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. + +pytestmark = [pytest.mark.bgpd] + +# +# Basic scenario for BGP-LU. Nodes are directly connected. +# Node 3 is advertising routes to 2, which advertises them +# as BGP-LU to 1; this way we get routes with actual labels, as +# opposed to implicit-null routes in the 2-node case. +# +# R2 is an LER, with MPLS towards R1, and IP towards R3. R1 is an LSR, with +# MPLS on both sides. +# +# +# AS4 BGP-LU AS1 BGP-LU AS2 iBGP AS2 +# +-----+ +-----+ +-----+ +-----+ +# | |.4 .1| |.1 .2| |.2 .3| | +# | 4 +-------------+ 1 +----------------+ 2 +-----------------+ 3 | +# | | 10.0.4.0/24 | | 10.0.0.0/24 | | 10.0.1.0/24 | | +# +-----+ +-----+ +-----+ +-----+ +# +# + + +def build_topo(tgen): + "Build function" + + # This function's only purpose is to define allocation and relationship + # between routers, switches and hosts. + # + # + # Create routers + tgen.add_router("R1") + tgen.add_router("R2") + tgen.add_router("R3") + tgen.add_router("R4") + + # R1-R2 + switch = tgen.add_switch("s1") + switch.add_link(tgen.gears["R1"]) + switch.add_link(tgen.gears["R2"]) + + # R2-R3 + switch = tgen.add_switch("s2") + switch.add_link(tgen.gears["R2"]) + switch.add_link(tgen.gears["R3"]) + + # R1-R4 + switch = tgen.add_switch("s3") + switch.add_link(tgen.gears["R1"]) + switch.add_link(tgen.gears["R4"]) + + +def setup_module(mod): + "Sets up the pytest environment" + # This function initiates the topology build with Topogen... + tgen = Topogen(build_topo, mod.__name__) + + # Skip if no mpls support + if not tgen.hasmpls: + logger.info("MPLS is not available, skipping test") + pytest.skip("MPLS is not available, skipping") + return + + # ... and here it calls Mininet initialization functions. + tgen.start_topology() + + # This is a sample of configuration loading. + router_list = tgen.routers() + + # Enable mpls input for routers, so we can ping + sval = "net.mpls.conf.{}.input" + topotest.sysctl_assure(router_list["R2"], sval.format("R2-eth0"), 1) + topotest.sysctl_assure(router_list["R1"], sval.format("R1-eth0"), 1) + topotest.sysctl_assure(router_list["R1"], sval.format("R1-eth1"), 1) + topotest.sysctl_assure(router_list["R4"], sval.format("R4-eth0"), 1) + + # For all registered routers, load the zebra configuration file + 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_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname)) + ) + + # Have static config for R3 too + if router == router_list["R3"]: + router.load_config( + TopoRouter.RD_STATIC, os.path.join(CWD, "{}/staticd.conf".format(rname)) + ) + + # After loading the configurations, this function loads configured daemons. + tgen.start_router() + + +def teardown_module(mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def check_labelpool(router): + json_file = "{}/{}/labelpool.summ.json".format(CWD, router.name) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, router, "show bgp labelpool summary json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assertmsg = '"{}" JSON output mismatches - Did not converge'.format(router.name) + assert result is None, assertmsg + + +def test_converge_bgplu(): + "Wait for protocol convergence" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # TODO -- enable for debugging + # tgen.mininet_cli() + + r1 = tgen.gears["R1"] + r2 = tgen.gears["R2"] + + check_labelpool(r1) + check_labelpool(r2) + + +def test_ping(): + "Simple ping tests" + + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # + logger.info("Ping from R2 to R3") + router = tgen.gears["R2"] + output = router.run("ping -c 4 -w 4 {}".format("10.0.1.3")) + assert " 0% packet loss" in output, "Ping R2->R3 FAILED" + logger.info("Ping from R2 to R3 ... success") + + # + logger.info("Ping from R4 to R2") + router = tgen.gears["R4"] + output = router.run("ping -c 4 -w 4 {}".format("10.0.0.2")) + assert " 0% packet loss" in output, "Ping R4->R2 FAILED" + logger.info("Ping from R4 to R2 ... success") + + # + logger.info("Ping from R4 to R3") + router = tgen.gears["R4"] + output = router.run("ping -c 4 -w 4 {}".format("10.0.1.3")) + assert " 0% packet loss" in output, "Ping R4->R3 FAILED" + logger.info("Ping from R4 to R3 ... success") + + +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_multiview_topo1/peer1/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py index fbb73f5b6a..09f6ea59e5 100755 --- a/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer1/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py index fbb73f5b6a..09f6ea59e5 100755 --- a/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer2/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py index fbb73f5b6a..09f6ea59e5 100755 --- a/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer3/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py index fbb73f5b6a..09f6ea59e5 100755 --- a/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer4/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py index fbb73f5b6a..09f6ea59e5 100755 --- a/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer5/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py index fbb73f5b6a..09f6ea59e5 100755 --- a/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer6/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py index fbb73f5b6a..09f6ea59e5 100755 --- a/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer7/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py b/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py index fbb73f5b6a..09f6ea59e5 100755 --- a/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py +++ b/tests/topotests/bgp_multiview_topo1/peer8/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer1/exa_readpipe.py b/tests/topotests/bgp_peer_type_multipath_relax/peer1/exa_readpipe.py index 9e689a27e3..0f998c1613 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer1/exa_readpipe.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer1/exa_readpipe.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 "Helper script to read api commands from a pipe and feed them to ExaBGP" import sys diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer2/exa_readpipe.py b/tests/topotests/bgp_peer_type_multipath_relax/peer2/exa_readpipe.py index 9e689a27e3..0f998c1613 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer2/exa_readpipe.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer2/exa_readpipe.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 "Helper script to read api commands from a pipe and feed them to ExaBGP" import sys diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer3/exa_readpipe.py b/tests/topotests/bgp_peer_type_multipath_relax/peer3/exa_readpipe.py index 9e689a27e3..0f998c1613 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer3/exa_readpipe.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer3/exa_readpipe.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 "Helper script to read api commands from a pipe and feed them to ExaBGP" import sys diff --git a/tests/topotests/bgp_peer_type_multipath_relax/peer4/exa_readpipe.py b/tests/topotests/bgp_peer_type_multipath_relax/peer4/exa_readpipe.py index 9e689a27e3..0f998c1613 100644 --- a/tests/topotests/bgp_peer_type_multipath_relax/peer4/exa_readpipe.py +++ b/tests/topotests/bgp_peer_type_multipath_relax/peer4/exa_readpipe.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 "Helper script to read api commands from a pipe and feed them to ExaBGP" import sys diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/__init__.py b/tests/topotests/bgp_route_map_match_ipv6_nexthop/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/__init__.py 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 new file mode 100644 index 0000000000..c2a49252d6 --- /dev/null +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf @@ -0,0 +1,32 @@ +! +ipv6 access-list nh1 permit 2001:db8:1::/64 +ipv6 access-list nh2 permit 2001:db8:2::/64 +ipv6 access-list nh3 permit 2001:db8:3::/64 +! +ipv6 prefix-list nh4 permit 2001:db8:5::/64 le 128 +! +router bgp 65001 + bgp router-id 10.10.10.1 + no bgp ebgp-requires-policy + neighbor 2001:db8::2 remote-as external + address-family ipv6 unicast + neighbor 2001:db8::2 activate + neighbor 2001:db8::2 route-map r2 in + exit-address-family +! +route-map r2 permit 10 + match ipv6 next-hop nh1 + set community 65002:1 +route-map r2 permit 20 + match ipv6 next-hop nh2 + set community 65002:2 +route-map r2 permit 30 + match ipv6 next-hop nh3 + set community 65002:3 +route-map r2 permit 40 + match ipv6 next-hop address 2001:db8:4::1 + set community 65002:4 +route-map r2 permit 50 + match ipv6 next-hop prefix-list nh4 + set community 65002:5 +! diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/zebra.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/zebra.conf new file mode 100644 index 0000000000..1d4374bd8f --- /dev/null +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/zebra.conf @@ -0,0 +1,4 @@ +! +int r1-eth0 + ipv6 address 2001:db8::1/64 +! 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 new file mode 100644 index 0000000000..19dcf3664b --- /dev/null +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf @@ -0,0 +1,33 @@ +! +router bgp 65002 + bgp router-id 10.10.10.2 + no bgp ebgp-requires-policy + neighbor 2001:db8::1 remote-as external + address-family ipv6 unicast + redistribute connected + neighbor 2001:db8::1 activate + neighbor 2001:db8::1 route-map r1 out + exit-address-family +! +ipv6 prefix-list p1 permit 2001:db8:1::1/128 +ipv6 prefix-list p2 permit 2001:db8:2::1/128 +ipv6 prefix-list p3 permit 2001:db8:3::1/128 +ipv6 prefix-list p4 permit 2001:db8:4::1/128 +ipv6 prefix-list p5 permit 2001:db8:5::1/128 +! +route-map r1 permit 10 + match ipv6 address prefix-list p1 + set ipv6 next-hop global 2001:db8:1::1 +route-map r1 permit 20 + match ipv6 address prefix-list p2 + set ipv6 next-hop global 2001:db8:2::1 +route-map r1 permit 30 + match ipv6 address prefix-list p3 + set ipv6 next-hop global 2001:db8:3::1 +route-map r1 permit 40 + match ipv6 address prefix-list p4 + set ipv6 next-hop global 2001:db8:4::1 +route-map r1 permit 50 + match ipv6 address prefix-list p5 + set ipv6 next-hop global 2001:db8:5::1 +! diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/zebra.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/zebra.conf new file mode 100644 index 0000000000..e69345f4f6 --- /dev/null +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/zebra.conf @@ -0,0 +1,11 @@ +! +int lo + ipv6 address 2001:db8:1::1/128 + ipv6 address 2001:db8:2::1/128 + ipv6 address 2001:db8:3::1/128 + ipv6 address 2001:db8:4::1/128 + ipv6 address 2001:db8:5::1/128 +! +int r2-eth0 + ip address 2001:db8::2/64 +! 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 new file mode 100644 index 0000000000..8c86526bf1 --- /dev/null +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py @@ -0,0 +1,121 @@ +#!/usr/bin/env python + +# Copyright (c) 2021 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test if we can match BGP prefixes by next-hop which is +specified by an IPv6 Access-list, prefix-list or just an address. +""" + +import os +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 + +pytestmark = [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)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_route_map_match_ipv6_next_hop_access_list(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears["r1"] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ipv6 route json")) + expected = { + "2001:db8:1::1/128": [ + { + "communities": "65002:1", + } + ], + "2001:db8:2::1/128": [ + { + "communities": "65002:2", + } + ], + "2001:db8:3::1/128": [ + { + "communities": "65002:3", + } + ], + "2001:db8:4::1/128": [ + { + "communities": "65002:4", + } + ], + "2001:db8:5::1/128": [ + { + "communities": "65002:5", + } + ], + } + 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) + assert result is None, "Can't match routes using ipv6 next-hop access-list" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_route_server_client/__init__.py b/tests/topotests/bgp_route_server_client/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_route_server_client/__init__.py diff --git a/tests/topotests/bgp_route_server_client/r1/bgpd.conf b/tests/topotests/bgp_route_server_client/r1/bgpd.conf new file mode 100644 index 0000000000..9826b671f9 --- /dev/null +++ b/tests/topotests/bgp_route_server_client/r1/bgpd.conf @@ -0,0 +1,12 @@ +! +router bgp 65001 + bgp router-id 10.10.10.1 + no bgp ebgp-requires-policy + neighbor 2001:db8:1::1 remote-as external + neighbor 2001:db8:1::1 timers 3 10 + neighbor 2001:db8:1::1 timers connect 5 + address-family ipv6 unicast + redistribute connected + neighbor 2001:db8:1::1 activate + exit-address-family +! diff --git a/tests/topotests/bgp_route_server_client/r1/zebra.conf b/tests/topotests/bgp_route_server_client/r1/zebra.conf new file mode 100644 index 0000000000..08d0be6220 --- /dev/null +++ b/tests/topotests/bgp_route_server_client/r1/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ipv6 address 2001:db8:f::1/128 +! +int r1-eth0 + ipv6 address 2001:db8:1::2/64 +! diff --git a/tests/topotests/bgp_route_server_client/r2/bgpd.conf b/tests/topotests/bgp_route_server_client/r2/bgpd.conf new file mode 100644 index 0000000000..3b0a24b8ba --- /dev/null +++ b/tests/topotests/bgp_route_server_client/r2/bgpd.conf @@ -0,0 +1,17 @@ +router bgp 65000 view RS + bgp router-id 10.10.10.2 + no bgp ebgp-requires-policy + neighbor 2001:db8:1::2 remote-as external + neighbor 2001:db8:1::2 timers 3 10 + neighbor 2001:db8:1::2 timers connect 5 + neighbor 2001:db8:3::2 remote-as external + neighbor 2001:db8:3::2 timers 3 10 + neighbor 2001:db8:3::2 timers connect 5 + address-family ipv6 unicast + redistribute connected + neighbor 2001:db8:1::2 activate + neighbor 2001:db8:3::2 activate + neighbor 2001:db8:1::2 route-server-client + neighbor 2001:db8:3::2 route-server-client + exit-address-family +! diff --git a/tests/topotests/bgp_route_server_client/r2/zebra.conf b/tests/topotests/bgp_route_server_client/r2/zebra.conf new file mode 100644 index 0000000000..806bc4fe32 --- /dev/null +++ b/tests/topotests/bgp_route_server_client/r2/zebra.conf @@ -0,0 +1,7 @@ +! +int r2-eth0 + ipv6 address 2001:db8:1::1/64 +! +int r2-eth1 + ipv6 address 2001:db8:3::1/64 +! diff --git a/tests/topotests/bgp_route_server_client/r3/bgpd.conf b/tests/topotests/bgp_route_server_client/r3/bgpd.conf new file mode 100644 index 0000000000..60a5ffc559 --- /dev/null +++ b/tests/topotests/bgp_route_server_client/r3/bgpd.conf @@ -0,0 +1,12 @@ +! +router bgp 65003 + bgp router-id 10.10.10.3 + no bgp ebgp-requires-policy + neighbor 2001:db8:3::1 remote-as external + neighbor 2001:db8:3::1 timers 3 10 + neighbor 2001:db8:3::1 timers connect 5 + address-family ipv6 unicast + redistribute connected + neighbor 2001:db8:3::1 activate + exit-address-family +! diff --git a/tests/topotests/bgp_route_server_client/r3/zebra.conf b/tests/topotests/bgp_route_server_client/r3/zebra.conf new file mode 100644 index 0000000000..b5511a437c --- /dev/null +++ b/tests/topotests/bgp_route_server_client/r3/zebra.conf @@ -0,0 +1,7 @@ +! +int lo + ipv6 address 2001:db8:f::3/128 +! +int r3-eth0 + ipv6 address 2001:db8:3::2/64 +! 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 new file mode 100644 index 0000000000..21088f7008 --- /dev/null +++ b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py @@ -0,0 +1,143 @@ +#!/usr/bin/env python + +# Copyright (c) 2021 by +# Donatas Abraitis <donatas.abraitis@gmail.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Test if we send ONLY GUA address for route-server-client peers. +""" + +import os +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 + +pytestmark = [pytest.mark.bgpd] + + +def build_topo(tgen): + for routern in range(1, 4): + 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["r3"]) + + +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)) + ) + + tgen.start_router() + + +def teardown_module(mod): + tgen = get_topogen() + tgen.stop_topology() + + +def test_bgp_route_server_client(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r1 = tgen.gears["r1"] + r2 = tgen.gears["r2"] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show bgp ipv6 unicast summary json")) + expected = {"peers": {"2001:db8:1::1": {"state": "Established", "pfxRcd": 2}}} + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, r1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Cannot see BGP sessions to be up" + + def _bgp_prefix_received(router): + output = json.loads(router.vtysh_cmd("show bgp 2001:db8:f::3/128 json")) + expected = { + "prefix": "2001:db8:f::3/128", + "paths": [{"nexthops": [{"ip": "2001:db8:3::2"}]}], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_prefix_received, r1) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Cannot see BGP GUA next hop from r3 in r1" + + def _bgp_single_next_hop(router): + output = json.loads(router.vtysh_cmd("show bgp 2001:db8:f::3/128 json")) + return len(output["paths"][0]["nexthops"]) + + assert ( + _bgp_single_next_hop(r1) == 1 + ), "Not ONLY one Next Hop received for 2001:db8:f::3/128" + + def _bgp_gua_lla_next_hop(router): + output = json.loads(router.vtysh_cmd("show bgp view RS 2001:db8:f::3/128 json")) + expected = { + "prefix": "2001:db8:f::3/128", + "paths": [ + { + "nexthops": [ + { + "ip": "2001:db8:3::2", + "hostname": "r3", + "afi": "ipv6", + "scope": "global", + }, + {"hostname": "r3", "afi": "ipv6", "scope": "link-local"}, + ] + } + ], + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_gua_lla_next_hop, r2) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5) + assert result is None, "Cannot see BGP LLA next hop from r3 in r2" + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf index 8ad2ddc48c..4a8579845c 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce1/zebra.conf @@ -1,8 +1,8 @@ log file /tmp/zebra.log log stdout ! -debug zebra events -debug zebra dplane +! debug zebra events +! debug zebra dplane ! ! interface ce1-eth0 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf index fa2e968e55..5e0aa5d3f0 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce2/zebra.conf @@ -1,8 +1,8 @@ log file /tmp/zebra.log log stdout ! -debug zebra events -debug zebra dplane +! debug zebra events +! debug zebra dplane ! ! interface ce2-eth0 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf index ea91e21bad..fabc11e84d 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce3/zebra.conf @@ -1,8 +1,8 @@ log file /tmp/zebra.log log stdout ! -debug zebra events -debug zebra dplane +! debug zebra events +! debug zebra dplane ! ! interface ce3-eth0 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf index 0866fa9759..e369f41b39 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/ce4/zebra.conf @@ -1,8 +1,8 @@ log file /tmp/zebra.log log stdout ! -debug zebra events -debug zebra dplane +! debug zebra events +! debug zebra dplane ! ! interface ce4-eth0 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r1/isisd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r1/isisd.conf index b5ca993da3..1a148f0628 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r1/isisd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r1/isisd.conf @@ -1,7 +1,7 @@ log stdout debugging ! -debug isis route-events -debug isis events +! debug isis route-events +! debug isis events ! interface r1-eth0 ip router isis ISIS1 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r2/isisd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r2/isisd.conf index 3dfa43831a..396797dfb9 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r2/isisd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r2/isisd.conf @@ -1,7 +1,7 @@ log stdout debugging ! -debug isis route-events -debug isis events +! debug isis route-events +! debug isis events ! interface r2-eth0 ip router isis ISIS1 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf index 9bc4331bae..4fec8af3db 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r2/zebra.conf @@ -1,8 +1,8 @@ log file /tmp/zebra.log log stdout ! -debug zebra events -debug zebra dplane +! debug zebra events +! debug zebra dplane ! ! interface r2-eth0 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r3/isisd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r3/isisd.conf index 578ebafad6..9e52fb6820 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r3/isisd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r3/isisd.conf @@ -1,7 +1,7 @@ log stdout debugging ! -debug isis route-events -debug isis events +! debug isis route-events +! debug isis events ! interface r3-eth0 ip router isis ISIS1 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf index 4d2007e787..e433995593 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r3/zebra.conf @@ -1,8 +1,8 @@ log file /tmp/zebra.log log stdout ! -debug zebra events -debug zebra dplane +! debug zebra events +! debug zebra dplane ! ! interface r3-eth0 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r4/isisd.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r4/isisd.conf index 3e9e9af45f..8de2cf05c5 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r4/isisd.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r4/isisd.conf @@ -1,7 +1,7 @@ log stdout debugging ! -debug isis route-events -debug isis events +! debug isis route-events +! debug isis events ! interface r4-eth0 ip router isis ISIS1 diff --git a/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf b/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf index c48407c108..14580e5b3a 100644 --- a/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf +++ b/tests/topotests/bgp_snmp_mplsl3vpn/r4/zebra.conf @@ -1,8 +1,8 @@ log file /tmp/zebra.log log stdout ! -debug zebra events -debug zebra dplane +! debug zebra events +! debug zebra dplane ! ! interface r4-eth0 diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf index 68b5730a63..8defa0125a 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r1/zebra.conf @@ -7,9 +7,9 @@ log stdout notifications log monitor notifications log commands ! -debug zebra packet -debug zebra dplane -debug zebra kernel +! debug zebra packet +! debug zebra dplane +! debug zebra kernel ! interface eth0 ipv6 address 2001::1/64 diff --git a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf index 91fd92d422..51d9c92235 100644 --- a/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf +++ b/tests/topotests/bgp_srv6l3vpn_to_bgp_vrf/r2/zebra.conf @@ -7,9 +7,9 @@ log stdout notifications log monitor notifications log commands ! -debug zebra packet -debug zebra dplane -debug zebra kernel +! debug zebra packet +! debug zebra dplane +! debug zebra kernel ! interface eth0 ipv6 address 2001::2/64 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 e0cf8c88e6..ffdcd08f80 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 @@ -152,13 +152,14 @@ def check_ping(name, dest_addr, expect_connected): tgen = get_topogen() output = tgen.gears[name].run("ping6 {} -c 1 -w 1".format(dest_addr)) logger.info(output) - assert match in output, "ping fail" + if match not in output: + return "ping fail" match = "{} packet loss".format("0%" if expect_connected else "100%") 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=0.5) + success, result = topotest.run_and_expect(func, None, count=10, wait=1) assert result is None, "Failed" @@ -171,7 +172,7 @@ def check_rib(name, cmd, expected_file): expected = open_json_file("{}/{}".format(CWD, expected_file)) return topotest.json_cmp(output, expected) - logger.info("[+] check {} \"{}\" {}".format(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) diff --git a/tests/topotests/bgp_suppress_fib/r1/bgp_ipv4_allowas.json b/tests/topotests/bgp_suppress_fib/r1/bgp_ipv4_allowas.json new file mode 100644 index 0000000000..bc4d0f4796 --- /dev/null +++ b/tests/topotests/bgp_suppress_fib/r1/bgp_ipv4_allowas.json @@ -0,0 +1,40 @@ +{ + "prefix":"192.168.1.1/32", + "paths":[ + { + "aspath":{ + "string":"2", + "segments":[ + { + "type":"as-sequence", + "list":[ + 2 + ] + } + ], + "length":1 + }, + "origin":"incomplete", + "metric":0, + "valid":true, + "bestpath":{ + "overall":true, + "selectionReason":"First path received" + }, + "nexthops":[ + { + "ip":"10.0.0.2", + "afi":"ipv4", + "metric":0, + "accessible":true, + "used":true + } + ], + "peer":{ + "peerId":"10.0.0.2", + "routerId":"10.0.0.9", + "type":"external" + } + } + ] +} diff --git a/tests/topotests/bgp_suppress_fib/r2/bgp_ipv4_allowas.json b/tests/topotests/bgp_suppress_fib/r2/bgp_ipv4_allowas.json new file mode 100644 index 0000000000..16561ce837 --- /dev/null +++ b/tests/topotests/bgp_suppress_fib/r2/bgp_ipv4_allowas.json @@ -0,0 +1,68 @@ +{ + "prefix":"192.168.1.1/32", + "paths":[ + { + "aspath":{ + "string":"1 2", + "segments":[ + { + "type":"as-sequence", + "list":[ + 1, + 2 + ] + } + ], + "length":2 + }, + "origin":"incomplete", + "valid":true, + "fibInstalled":true, + "nexthops":[ + { + "ip":"10.0.0.1", + "afi":"ipv4", + "metric":0, + "accessible":true, + "used":true + } + ], + "peer":{ + "peerId":"10.0.0.1", + "routerId":"10.0.0.1", + "type":"external" + } + }, + { + "aspath":{ + "string":"Local", + "segments":[ + ], + "length":0 + }, + "origin":"incomplete", + "metric":0, + "weight":32768, + "valid":true, + "sourced":true, + "bestpath":{ + "overall":true, + "selectionReason":"Weight" + }, + "fibInstalled":true, + "nexthops":[ + { + "ip":"10.0.0.10", + "afi":"ipv4", + "metric":0, + "accessible":true, + "used":true + } + ], + "peer":{ + "peerId":"0.0.0.0", + "routerId":"10.0.0.9" + } + } + ] +} diff --git a/tests/topotests/bgp_suppress_fib/r2/bgpd.allowas_in.conf b/tests/topotests/bgp_suppress_fib/r2/bgpd.allowas_in.conf new file mode 100644 index 0000000000..caebb0e922 --- /dev/null +++ b/tests/topotests/bgp_suppress_fib/r2/bgpd.allowas_in.conf @@ -0,0 +1,18 @@ +access-list access seq 10 permit 192.168.1.1/32 +! +ip route 192.168.1.1/32 10.0.0.10 +! +debug bgp bestpath +debug bgp nht +debug bgp updates +debug bgp update-groups +debug bgp zebra +debug zebra rib detail +! +router bgp 2 + address-family ipv4 uni + redistribute static + neighbor 10.0.0.10 allowas-in 1 + neighbor 10.0.0.1 allowas-in 1 + ! +! diff --git a/tests/topotests/bgp_suppress_fib/r2/bgpd.conf b/tests/topotests/bgp_suppress_fib/r2/bgpd.conf index 8321c915e3..ebef2012a8 100644 --- a/tests/topotests/bgp_suppress_fib/r2/bgpd.conf +++ b/tests/topotests/bgp_suppress_fib/r2/bgpd.conf @@ -1,3 +1,6 @@ +debug bgp updates +debug bgp bestpath 40.0.0.0/8 +debug bgp zebra ! router bgp 2 no bgp ebgp-requires-policy diff --git a/tests/topotests/bgp_suppress_fib/r2/no_bgp_ipv4_allowas.json b/tests/topotests/bgp_suppress_fib/r2/no_bgp_ipv4_allowas.json new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/tests/topotests/bgp_suppress_fib/r2/no_bgp_ipv4_allowas.json @@ -0,0 +1 @@ +{} diff --git a/tests/topotests/bgp_suppress_fib/r2/v4_override.json b/tests/topotests/bgp_suppress_fib/r2/v4_override.json new file mode 100644 index 0000000000..f17907f011 --- /dev/null +++ b/tests/topotests/bgp_suppress_fib/r2/v4_override.json @@ -0,0 +1,20 @@ +{ + "40.0.0.0\/8":[ + { + "prefix":"40.0.0.0\/8", + "protocol":"static", + "vrfName":"default", + "selected":true, + "destSelected":true, + "installed":true, + "nexthops":[ + { + "fib":true, + "ip":"10.0.0.10", + "afi":"ipv4", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/bgp_suppress_fib/r3/v4_override.json b/tests/topotests/bgp_suppress_fib/r3/v4_override.json new file mode 100644 index 0000000000..a35d49e9e8 --- /dev/null +++ b/tests/topotests/bgp_suppress_fib/r3/v4_override.json @@ -0,0 +1,4 @@ +{ + "0.0.0.0\/0":[ + ] +} 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 5a22fbbc54..2c87d9d7b0 100644 --- a/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py +++ b/tests/topotests/bgp_suppress_fib/test_bgp_suppress_fib.py @@ -29,6 +29,7 @@ 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__)) sys.path.append(os.path.join(CWD, "../")) @@ -112,6 +113,115 @@ def test_bgp_route(): assert result is None, assertmsg +def test_bgp_better_admin_won(): + "A better Admin distance protocol may come along and knock us out" + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + r2.vtysh_cmd("conf\nip route 40.0.0.0/8 10.0.0.10") + + json_file = "{}/r2/v4_override.json".format(CWD) + expected = json.loads(open(json_file).read()) + + logger.info(expected) + test_func = partial( + topotest.router_json_cmp, r2, "show ip route 40.0.0.0 json", expected + ) + + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"r2" static route did not take over' + assert result is None, assertmsg + + r3 = tgen.gears["r3"] + + json_file = "{}/r3/v4_override.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, r3, "show ip route 40.0.0.0 json", expected + ) + + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"r3" route to 40.0.0.0 should have been lost' + assert result is None, assertmsg + + r2.vtysh_cmd("conf\nno ip route 40.0.0.0/8 10.0.0.10") + + json_file = "{}/r3/v4_route.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, + r3, + "show ip route 40.0.0.0 json", + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"r3" route to 40.0.0.0 did not come back' + assert result is None, assertmsg + + +def test_bgp_allow_as_in(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + r2 = tgen.gears["r2"] + + config_file = "{}/r2/bgpd.allowas_in.conf".format(CWD) + r2.run("vtysh -f {}".format(config_file)) + + json_file = "{}/r2/bgp_ipv4_allowas.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, + r2, + "show bgp ipv4 uni 192.168.1.1/32 json", + expected, + ) + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"r2" static redistribution failed into bgp' + assert result is None, assertmsg + + r1 = tgen.gears["r1"] + + json_file = "{}/r1/bgp_ipv4_allowas.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, + r1, + "show bgp ipv4 uni 192.168.1.1/32 json", + expected, + ) + + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"r1" 192.168.1.1/32 route should have arrived' + assert result is None, assertmsg + + r2.vtysh_cmd("conf\nno ip route 192.168.1.1/32 10.0.0.10") + + json_file = "{}/r2/no_bgp_ipv4_allowas.json".format(CWD) + expected = json.loads(open(json_file).read()) + + test_func = partial( + topotest.router_json_cmp, + r2, + "show bgp ipv4 uni 192.168.1.1/32 json", + expected, + ) + + _, result = topotest.run_and_expect(test_func, None, count=10, wait=0.5) + assertmsg = '"r2" 192.168.1.1/32 route should be gone' + assert result is None, assertmsg + + if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_tcp_mss/bgp_vrf_tcp_mss.json b/tests/topotests/bgp_tcp_mss/bgp_vrf_tcp_mss.json new file mode 100644 index 0000000000..17cee03fa3 --- /dev/null +++ b/tests/topotests/bgp_tcp_mss/bgp_vrf_tcp_mss.json @@ -0,0 +1,222 @@ +{ + "address_types": [ + "ipv4", + "ipv6" + ], + "ipv4base": "20.20.20.0", + "ipv4mask": 24, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.10.10.0", + "v4mask": 24, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 24, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "RED" + } + }, + "vrfs": [ + { + "name": "RED", + "id": "1" + } + ], + "bgp": [ + { + "local_as": "100", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + } + } + } + ] + }, + "r2": { + "links": { + "r1-link1": { + "ipv4": "auto", + "ipv6": "auto", + "vrf": "RED" + }, + "r3-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "vrfs": [ + { + "name": "RED", + "id": "1" + } + ], + "bgp": [ + { + "local_as": "200", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + } + } + }, + { + "local_as": "200", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + } + } + } + ] + }, + "r3": { + "links": { + "r2-link1": { + "ipv4": "auto", + "ipv6": "auto" + } + }, + "bgp": [ + { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link1": {} + } + } + }, + "redistribute": [ + { + "redist_type": "static" + } + ] + } + } + } + } + ] + } + } +}
\ No newline at end of file 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 new file mode 100644 index 0000000000..c48bd8a439 --- /dev/null +++ b/tests/topotests/bgp_tcp_mss/test_bgp_vrf_tcp_mss.py @@ -0,0 +1,766 @@ +#!/usr/bin/env python + +# +# bgp_tcp_mss.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2021 by +# Shreenidhi A R <rshreenidhi@vmware.com> +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +bgp_tcp_mss_vrf.py: + +Need to verify if the tcp-mss value is reflected in the TCP session and in VRF. +""" + +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] + +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.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, + 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 +) + +pytestmark = [pytest.mark.bgpd] +# Global variables +NETWORK1_1 = {"ipv4": "1.1.1.1/32", "ipv6": "1::1/128"} +NETWORK1_2 = {"ipv4": "1.1.1.2/32", "ipv6": "1::2/128"} +NETWORK2_1 = {"ipv4": "2.1.1.1/32", "ipv6": "2::1/128"} +NETWORK2_2 = {"ipv4": "2.1.1.2/32", "ipv6": "2::2/128"} +NETWORK3_1 = {"ipv4": "3.1.1.1/32", "ipv6": "3::1/128"} +NETWORK3_2 = {"ipv4": "3.1.1.2/32", "ipv6": "3::2/128"} +NETWORK4_1 = {"ipv4": "4.1.1.1/32", "ipv6": "4::1/128"} +NETWORK4_2 = {"ipv4": "4.1.1.2/32", "ipv6": "4::2/128"} +NETWORK5_1 = {"ipv4": "5.1.1.1/32", "ipv6": "5::1/128"} +NETWORK5_2 = {"ipv4": "5.1.1.2/32", "ipv6": "5::2/128"} + +NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} + +## File name +TCPDUMP_FILE="test_tcp_packet_test.txt" + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + global topo,TCPDUMP_FILE + + # Required linux kernel version for this suite to run. + result = required_linux_kernel_version("4.15") + if result is not True: + pytest.skip("Kernel requirements are not met") + + testsuite_run_time = time.asctime(time.localtime(time.time())) + step("Testsuite start time: {}".format(testsuite_run_time)) + step("=" * 40) + + step("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_vrf_tcp_mss.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + global ADDR_TYPES + global BGP_CONVERGENCE + ADDR_TYPES = check_address_types() + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module :Failed \n Error: {}".format( + BGP_CONVERGENCE + ) + + step("Running setup_module() done") + +def teardown_module(): + """Teardown the pytest environment""" + + step("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + step( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + step("=" * 40) + + +##################################################### +# +# Testcases +# +##################################################### + +def test_bgp_vrf_tcp_mss(request): + tgen = get_topogen() + tc_name = request.node.name + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + step("Verify the router failures") + if tgen.routers_have_failure(): + check_router_status(tgen) + + step("Configuring 5 static Routes in Router R3 with NULL0 as Next hop") + for addr_type in ADDR_TYPES: + static_routes_input = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + ] + } + } + result = create_static_routes(tgen, static_routes_input) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify the static Routes in R3 on default VRF") + for addr_type in ADDR_TYPES: + static_routes_input = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + ] + } + } + dut = "r3" + result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Verify the static Routes in R2 on default VRF") + for addr_type in ADDR_TYPES: + static_routes_input = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + { + "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + }, + ] + } + } + dut = "r2" + result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("importing default vrf on R2 under VRF RED Address Family") + for addr_type in ADDR_TYPES: + input_import_vrf = { + "r2": { + "bgp": [ + { + "local_as": 200, + "vrf": "RED", + "address_family": { + addr_type: {"unicast": {"import": {"vrf": "default"}}} + }, + } + ] + } + } + result = create_router_bgp(tgen, topo, input_import_vrf) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Verify the static Routes in R2 on RED VRF") + for addr_type in ADDR_TYPES: + static_routes_input = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + ] + } + } + dut = "r2" + result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Verify the static Routes in R1 on RED VRF") + for addr_type in ADDR_TYPES: + static_routes_input = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]] + [NETWORK1_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK2_1[addr_type]] + [NETWORK2_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK3_1[addr_type]] + [NETWORK3_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK4_1[addr_type]] + [NETWORK4_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + { + "network": [NETWORK5_1[addr_type]] + [NETWORK5_2[addr_type]], + "next_hop": NEXT_HOP_IP[addr_type], + "vrf": "RED", + }, + ] + } + } + dut = "r1" + result = verify_bgp_rib(tgen, addr_type, dut, static_routes_input) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + + step("Enabling tcp-mss 150 on Router R1 in VRF RED") + TCP_MSS = 150 + raw_config = { + "r1": { + "raw_config": [ + "router bgp {} vrf {}".format( + topo["routers"]["r1"]["bgp"][0]["local_as"], + topo["routers"]["r1"]["bgp"][0]["vrf"], + ), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r1-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r1-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + }, + } + + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Clearing BGP on R1 and R2 ") + for addr_type in ADDR_TYPES: + clear_bgp(tgen, addr_type, "r1", vrf=topo["routers"]["r1"]["bgp"][0]["vrf"]) + clear_bgp(tgen, addr_type, "r2", vrf=topo["routers"]["r2"]["bgp"][1]["vrf"]) + + step("Verify the BGP Convergence at R1 & R2 after Clear BGP") + r1_convergence = verify_bgp_convergence(tgen, topo, dut="r1") + assert ( + r1_convergence is True + ), "BGP convergence after Clear BGP :Failed \n Error: {}".format(r1_convergence) + r2_convergence = verify_bgp_convergence(tgen, topo, dut="r2") + assert ( + r2_convergence is True + ), "BGP convergence after Clear BGP :Failed \n Error: {}".format(r2_convergence) + + step("Verify the TCP-MSS value on both Router R1 and R2") + for addr_type in ADDR_TYPES: + dut = "r1" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0], + TCP_MSS, + "RED", + ) + assert tcp_mss_result is True, " TCP-MSS mismatch :Failed \n Error: {}".format( + tcp_mss_result + ) + + + + + step("Enabling tcp-mss 500 between R2 and R3 of VRF Default") + TCP_MSS = 500 + raw_config = { + "r2": { + "raw_config": [ + "router bgp {} ".format(topo["routers"]["r2"]["bgp"][0]["local_as"]), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r3"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r3"]["links"]["r2-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + }, + "r3": { + "raw_config": [ + "router bgp {} ".format(topo["routers"]["r3"]["bgp"][0]["local_as"]), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r3-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r3-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + }, + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + + + step("Clear BGP at router R2 and R3") + for addr_type in ADDR_TYPES: + clear_bgp(tgen, topo, "r2", addr_type) + clear_bgp(tgen, topo, "r3", addr_type) + + step("Verify the BGP Convergence at R2 & R3 after Clear BGP") + r1_convergence = verify_bgp_convergence(tgen, topo, dut="r2") + assert ( + r1_convergence is True + ), "BGP convergence after Clear BGP :Failed \n Error: {}".format(r2_convergence) + r2_convergence = verify_bgp_convergence(tgen, topo, dut="r3") + assert ( + r2_convergence is True + ), "BGP convergence after Clear BGP :Failed \n Error: {}".format(r2_convergence) + + step("Verify the TCP-MSS value on both Router R2 and R3") + for addr_type in ADDR_TYPES: + dut = "r2" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r3"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ) + assert tcp_mss_result is True, " TCP-MSS mismatch :Failed \n Error: {}".format( + tcp_mss_result + ) + + dut = "r3" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r2"]["links"]["r3-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ) + assert tcp_mss_result is True, " TCP-MSS mismatch :Failed \n Error: {}".format( + tcp_mss_result + ) + + step("Removing tcp-mss 150 between R1 and R2 of VRF RED ") + TCP_MSS = 150 + raw_config = { + "r1": { + "raw_config": [ + "router bgp {} vrf {}".format( + topo["routers"]["r1"]["bgp"][0]["local_as"], + topo["routers"]["r1"]["bgp"][0]["vrf"], + ), + "no neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r1-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "no neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r1-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + } + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + raw_config = { + "r2": { + "raw_config": [ + "router bgp {} vrf {}".format( + topo["routers"]["r2"]["bgp"][0]["local_as"], + topo["routers"]["r2"]["bgp"][1]["vrf"], + ), + "no neighbor {} tcp-mss {}".format( + topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "no neighbor {} tcp-mss {}".format( + topo["routers"]["r1"]["links"]["r2-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + } + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Verify the TCP-MSS value cleared on both Router R1 and R2") + for addr_type in ADDR_TYPES: + dut = "r1" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r2"]["links"]["r1-link1"][addr_type].split("/")[0], + TCP_MSS, + "RED", + ) + assert ( + tcp_mss_result is not True + ), " TCP-MSS mismatch :Failed \n Error: {}".format(tcp_mss_result) + + dut = "r2" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r1"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + "RED", + ) + assert ( + tcp_mss_result is not True + ), " TCP-MSS mismatch :Failed \n Error: {}".format(tcp_mss_result) + + + step("Removing tcp-mss 500 between R2 and R3 of VRF Default ") + TCP_MSS = 500 + raw_config = { + "r2": { + "raw_config": [ + "router bgp {} ".format(topo["routers"]["r2"]["bgp"][0]["local_as"]), + "no neighbor {} tcp-mss {}".format( + topo["routers"]["r3"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "no neighbor {} tcp-mss {}".format( + topo["routers"]["r3"]["links"]["r2-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + } + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + raw_config = { + "r3": { + "raw_config": [ + "router bgp {} ".format(topo["routers"]["r3"]["bgp"][0]["local_as"]), + "no neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r3-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "no neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r3-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + } + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Verify the TCP-MSS value got cleared on both Router R2 and R3") + for addr_type in ADDR_TYPES: + dut = "r2" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r3"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ) + assert ( + tcp_mss_result is not True + ), " TCP-MSS mismatch :Failed \n Error: {}".format(tcp_mss_result) + + dut = "r3" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r2"]["links"]["r3-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ) + assert ( + tcp_mss_result is not True + ), " TCP-MSS mismatch :Failed \n Error: {}".format(tcp_mss_result) + + step("Configuring different TCP-MSS R2 and R3 ") + TCP_MSS = 500 + raw_config = { + "r2": { + "raw_config": [ + "router bgp {}".format(topo["routers"]["r2"]["bgp"][0]["local_as"]), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r3"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r3"]["links"]["r2-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + } + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + TCP_MSS = 300 + raw_config = { + "r3": { + "raw_config": [ + "router bgp {} ".format(topo["routers"]["r3"]["bgp"][0]["local_as"]), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r3-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r3-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + } + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Verify the TCP-MSS value on both Router R2 and R3") + for addr_type in ADDR_TYPES: + TCP_MSS = 500 + dut = "r2" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r3"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ) + assert tcp_mss_result is True, " TCP-MSS mismatch :Failed \n Error: {}".format( + tcp_mss_result + ) + + TCP_MSS = 300 + dut = "r3" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r2"]["links"]["r3-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ) + assert tcp_mss_result is True, " TCP-MSS mismatch :Failed \n Error: {}".format( + tcp_mss_result + ) + + step("Configure TCP_MSS > MTU on R2 and R3 and it should be 1460 ") + TCP_MSS = 4096 + REF_TCP_MSS = 1460 + raw_config = { + "r2": { + "raw_config": [ + "router bgp {} ".format(topo["routers"]["r2"]["bgp"][0]["local_as"]), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r3"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r3"]["links"]["r2-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + } + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + raw_config = { + "r3": { + "raw_config": [ + "router bgp {} ".format(topo["routers"]["r3"]["bgp"][0]["local_as"]), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r3-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ), + "neighbor {} tcp-mss {}".format( + topo["routers"]["r2"]["links"]["r3-link1"]["ipv6"].split("/")[0], + TCP_MSS, + ), + ] + } + } + result = apply_raw_config(tgen, raw_config) + assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) + + step("Restarting BGP Daemon on R3") + + kill_router_daemons(tgen, "r3", ["bgpd"]) + start_router_daemons(tgen, "r3", ["bgpd"]) + + step( + "Verify the configured TCP-MSS 4096 value on restarting both Daemon both Router R2 and R3 " + ) + for addr_type in ADDR_TYPES: + TCP_MSS = 4096 + dut = "r2" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r3"]["links"]["r2-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ) + assert tcp_mss_result is True, " TCP-MSS mismatch :Failed \n Error: {}".format( + tcp_mss_result + ) + dut = "r3" + tcp_mss_result = verify_tcp_mss( + tgen, + dut, + topo["routers"]["r2"]["links"]["r3-link1"]["ipv4"].split("/")[0], + TCP_MSS, + ) + assert tcp_mss_result is True, " TCP-MSS mismatch :Failed \n Error: {}".format( + tcp_mss_result + ) + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/bgp_vrf_lite_best_path_topo1.json b/tests/topotests/bgp_vrf_lite_best_path_test/bgp_vrf_lite_best_path_topo1.json new file mode 100644 index 0000000000..b1d7d09db8 --- /dev/null +++ b/tests/topotests/bgp_vrf_lite_best_path_test/bgp_vrf_lite_best_path_topo1.json @@ -0,0 +1,563 @@ +{ + "address_types": ["ipv4","ipv6"], + "ipv4base": "10.0.0.0", + "ipv4mask": 30, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 30, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"}, + "r3-link1": {"ipv4": "auto", "ipv6": "auto"}, + "r4-link1": {"ipv4": "auto", "ipv6": "auto"} + }, + "vrfs":[ + { + "name": "ISR", + "id": "1" + } + ], + "bgp": + [ + { + "local_as": "100", + "vrf": "ISR", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "next_hop_self": true + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "next_hop_self": true, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + } + ], + "static_routes":[ + { + "network": ["11.11.11.1/32", "11.11.11.11/32"], + "next_hop":"Null0", + "vrf": "ISR" + }, + { + "network": ["11:11::1/128", "11:11::11/128"], + "next_hop":"Null0", + "vrf": "ISR" + }, + { + "network": ["10.10.10.10/32", "10.10.10.100/32"], + "next_hop":"Null0" + }, + { + "network": ["10:10::10/128", "10:10::100/128"], + "next_hop":"Null0" + } + ], + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + }] + } + }, + "r2": { + "links": { + "r1-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "ISR"}, + "r3-link1": {"ipv4": "auto", "ipv6": "auto"}, + "r4-link1": {"ipv4": "auto", "ipv6": "auto"} + }, + "vrfs":[ + { + "name": "ISR", + "id": "1" + } + ], + "bgp": + [ + { + "local_as": "100", + "vrf": "ISR", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "next_hop_self": true + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "next_hop_self": true, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "100", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + } + ], + "static_routes":[ + { + "network": ["22.22.22.2/32", "22.22.22.22/32"], + "next_hop":"Null0", + "vrf": "ISR" + }, + { + "network": ["22:22::2/128", "22:22::22/128"], + "next_hop":"Null0", + "vrf": "ISR" + }, + { + "network": ["20.20.20.20/32", "20.20.20.200/32"], + "next_hop":"Null0" + }, + { + "network": ["20:20::20/128", "20:20::200/128"], + "next_hop":"Null0" + } + ], + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + }] + } + }, + "r3": { + "links": { + "r1-link1": {"ipv4": "auto", "ipv6": "auto"}, + "r2-link1": {"ipv4": "auto", "ipv6": "auto"} + }, + "bgp": + [ + { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "300", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + } + ], + "static_routes":[ + { + "network": ["30.30.30.3/32", "30.30.30.30/32"], + "next_hop":"Null0" + }, + { + "network": ["30:30::3/128", "30:30::30/128"], + "next_hop":"Null0" + }, + { + "network": ["50.50.50.5/32", "50.50.50.50/32"], + "next_hop":"Null0" + }, + { + "network": ["50:50::5/128", "50:50::50/128"], + "next_hop":"Null0" + } + ], + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + }] + } + }, + "r4": { + "links": { + "r1-link1": {"ipv4": "auto", "ipv6": "auto"}, + "r2-link1": {"ipv4": "auto", "ipv6": "auto"} + }, + "bgp": + [ + { + "local_as": "400", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "400", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + } + ], + "static_routes":[ + { + "network": ["40.40.40.4/32", "40.40.40.40/32"], + "next_hop":"Null0" + }, + { + "network": ["40:40::4/128", "40:40::40/128"], + "next_hop":"Null0" + }, + { + "network": ["50.50.50.5/32", "50.50.50.50/32"], + "next_hop":"Null0" + }, + { + "network": ["50:50::5/128", "50:50::50/128"], + "next_hop":"Null0" + } + ], + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + }] + } + } + } +} diff --git a/tests/topotests/bgp_vrf_lite_best_path_test/bgp_vrf_lite_best_path_topo2.json b/tests/topotests/bgp_vrf_lite_best_path_test/bgp_vrf_lite_best_path_topo2.json new file mode 100644 index 0000000000..0b13882176 --- /dev/null +++ b/tests/topotests/bgp_vrf_lite_best_path_test/bgp_vrf_lite_best_path_topo2.json @@ -0,0 +1,1088 @@ +{ + "address_types": ["ipv4","ipv6"], + "ipv4base": "10.0.0.0", + "ipv4mask": 24, + "ipv6base": "fd00::", + "ipv6mask": 64, + "link_ip_start": { + "ipv4": "10.0.0.0", + "v4mask": 24, + "ipv6": "fd00::", + "v6mask": 64 + }, + "lo_prefix": { + "ipv4": "1.0.", + "v4mask": 32, + "ipv6": "2001:db8:f::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "r3-link1": {"ipv4": "192.168.1.1/24", "ipv6": "fd00:0:0:1::1/120", "vrf": "RED"}, + "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE"}, + "r3-link3": {"ipv4": "192.168.1.1/24", "ipv6": "fd00:0:0:1::1/120", "vrf": "GREEN"}, + "r3-link4": {"ipv4": "auto", "ipv6": "auto"} + }, + "vrfs":[ + {"name": "RED", "id": "1"}, + {"name": "BLUE", "id": "2"}, + {"name": "GREEN", "id": "3"} + ], + "bgp": + [ + { + "local_as": "1", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "1", + "vrf": "BLUE", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link2": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "1", + "vrf": "GREEN", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link3": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "1", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link4": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + } + ], + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + }] + } + }, + "r2": { + "links": { + "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED"}, + "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE"}, + "r3-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "GREEN"}, + "r3-link4": {"ipv4": "auto", "ipv6": "auto"} + }, + "vrfs":[ + {"name": "RED", "id": "1"}, + {"name": "BLUE", "id": "2"}, + {"name": "GREEN", "id": "3"} + ], + "bgp": + [ + { + "local_as": "2", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "2", + "vrf": "BLUE", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link2": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "2", + "vrf": "GREEN", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link3": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "2", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link4": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + } + ], + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + }] + } + }, + "r3": { + "links": { + "r1-link1": {"ipv4": "192.168.1.2/24", "ipv6": "fd00:0:0:1::2/120", "vrf": "RED"}, + "r1-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE"}, + "r1-link3": {"ipv4": "192.168.1.2/24", "ipv6": "fd00:0:0:1::2/120", "vrf": "GREEN"}, + "r1-link4": {"ipv4": "auto", "ipv6": "auto"}, + "r2-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED"}, + "r2-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE"}, + "r2-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "GREEN"}, + "r2-link4": {"ipv4": "auto", "ipv6": "auto"}, + "r4-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED"}, + "r4-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE"}, + "r4-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "GREEN"}, + "r4-link4": {"ipv4": "auto", "ipv6": "auto"}, + "r5-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED"}, + "r5-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE"}, + "r5-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "GREEN"}, + "r5-link4": {"ipv4": "auto", "ipv6": "auto"} + }, + "vrfs":[ + {"name": "RED", "id": "1"}, + {"name": "BLUE", "id": "2"}, + {"name": "GREEN", "id": "3"} + ], + "bgp": + [ + { + "local_as": "3", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": {} + } + }, + "r2": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r4": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r5": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r2": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3-link1": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r5": { + "dest_link": { + "r3-link1": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "3", + "vrf": "BLUE", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link2": {} + } + }, + "r2": { + "dest_link": { + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r4": { + "dest_link": { + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r5": { + "dest_link": { + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r2": { + "dest_link": { + "r3-link2": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r5": { + "dest_link": { + "r3-link2": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "3", + "vrf": "GREEN", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r2": { + "dest_link": { + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r4": { + "dest_link": { + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r5": { + "dest_link": { + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link3": { + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r2": { + "dest_link": { + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r5": { + "dest_link": { + "r3-link3": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + }, + { + "local_as": "3", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r2": { + "dest_link": { + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r4": { + "dest_link": { + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + }, + "r5": { + "dest_link": { + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r2": { + "dest_link": { + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r4": { + "dest_link": { + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + }, + "r5": { + "dest_link": { + "r3-link4": { + "keepalivetimer": 1, + "holddowntimer": 3, + "route_maps": [{ + "name": "rmap_global", + "direction": "in" + }] + } + } + } + } + } + } + } + } + ], + "route_maps": { + "rmap_global": [{ + "action": "permit", + "set": { + "ipv6": { + "nexthop": "prefer-global" + } + } + }] + } + }, + "r4": { + "links": { + "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED"}, + "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE"}, + "r3-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "GREEN"}, + "r3-link4": {"ipv4": "auto", "ipv6": "auto"} + }, + "vrfs":[ + {"name": "RED", "id": "1"}, + {"name": "BLUE", "id": "2"}, + {"name": "GREEN", "id": "3"} + ], + "bgp": + [ + { + "local_as": "4", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + } + } + }, + { + "local_as": "4", + "vrf": "BLUE", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4-link2": {} + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + } + } + }, + { + "local_as": "4", + "vrf": "GREEN", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4-link3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4-link3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + } + } + }, + { + "local_as": "4", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r4-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + } + } + } + ] + }, + "r5": { + "links": { + "r3-link1": {"ipv4": "auto", "ipv6": "auto", "vrf": "RED"}, + "r3-link2": {"ipv4": "auto", "ipv6": "auto", "vrf": "BLUE"}, + "r3-link3": {"ipv4": "auto", "ipv6": "auto", "vrf": "GREEN"}, + "r3-link4": {"ipv4": "auto", "ipv6": "auto"} + }, + "vrfs":[ + {"name": "RED", "id": "1"}, + {"name": "BLUE", "id": "2"}, + {"name": "GREEN", "id": "3"} + ], + "bgp": + [ + { + "local_as": "3", + "vrf": "RED", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5-link1": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + } + } + }, + { + "local_as": "3", + "vrf": "BLUE", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5-link2": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + } + } + }, + { + "local_as": "3", + "vrf": "GREEN", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5-link3": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5-link3": {} + } + } + } + } + } + } + }, + { + "local_as": "3", + "address_family": { + "ipv4": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + }, + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r5-link4": { + "keepalivetimer": 1, + "holddowntimer": 3 + } + } + } + } + } + } + } + } + ] + } + } +} 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 new file mode 100644 index 0000000000..d9d4f4f8b2 --- /dev/null +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo1.py @@ -0,0 +1,916 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2020 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test BGP VRF Lite: + +1. Verify BGP best path selection algorithm works fine when +routes are imported from ISR to default vrf and vice versa. +""" + +import os +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__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# Required to instantiate the topology builder class. + +# 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, + write_test_header, + check_address_types, + write_test_footer, + step, + create_route_maps, + create_prefix_lists, + check_router_status, + get_frr_ipv6_linklocal, + shutdown_bringup_interface, +) + +from lib.topolog import logger +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 + + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + +# Global variables +NETWORK1_1 = {"ipv4": "11.11.11.1/32", "ipv6": "11:11::1/128"} +NETWORK1_2 = {"ipv4": "11.11.11.11/32", "ipv6": "11:11::11/128"} +NETWORK1_3 = {"ipv4": "10.10.10.10/32", "ipv6": "10:10::10/128"} +NETWORK1_4 = {"ipv4": "10.10.10.100/32", "ipv6": "10:10::100/128"} + +NETWORK2_1 = {"ipv4": "22.22.22.2/32", "ipv6": "22:22::2/128"} +NETWORK2_2 = {"ipv4": "22.22.22.22/32", "ipv6": "22:22::22/128"} +NETWORK2_3 = {"ipv4": "20.20.20.20/32", "ipv6": "20:20::20/128"} +NETWORK2_4 = {"ipv4": "20.20.20.200/32", "ipv6": "20:20::200/128"} + +NETWORK3_1 = {"ipv4": "30.30.30.3/32", "ipv6": "30:30::3/128"} +NETWORK3_2 = {"ipv4": "30.30.30.30/32", "ipv6": "30:30::30/128"} +NETWORK3_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"} +NETWORK3_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"} + +NETWORK4_1 = {"ipv4": "40.40.40.4/32", "ipv6": "40:40::4/128"} +NETWORK4_2 = {"ipv4": "40.40.40.40/32", "ipv6": "40:40::40/128"} +NETWORK4_3 = {"ipv4": "50.50.50.5/32", "ipv6": "50:50::5/128"} +NETWORK4_4 = {"ipv4": "50.50.50.50/32", "ipv6": "50:50::50/128"} +NEXT_HOP_IP = {"ipv4": "Null0", "ipv6": "Null0"} +LOOPBACK_1 = { + "ipv4": "10.0.0.7/24", + "ipv6": "fd00:0:0:1::7/64", + "ipv4_mask": "255.255.255.0", + "ipv6_mask": None, +} +LOOPBACK_2 = { + "ipv4": "10.0.0.16/24", + "ipv6": "fd00:0:0:3::5/64", + "ipv4_mask": "255.255.255.0", + "ipv6_mask": None, +} +PREFERRED_NEXT_HOP = "global" + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_vrf_lite_best_path_topo1.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Run these tests for kernel version 4.19 or above + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + "BGP vrf dynamic route leak tests will not run " + '(have kernel "{}", but it requires >= 4.19)'.format(platform.release()) + ) + pytest.skip(error_msg) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + global BGP_CONVERGENCE + global ADDR_TYPES + ADDR_TYPES = check_address_types() + + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(): + """Teardown the pytest environment""" + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +##################################################### +# +# Testcases +# +##################################################### + + +def disable_route_map_to_prefer_global_next_hop(tgen, topo): + """ + This API is to remove prefer global route-map applied on neighbors + + Parameter: + ---------- + * `tgen` : Topogen object + * `topo` : Input JSON data + + Returns: + -------- + True/errormsg + + """ + + logger.info("Remove prefer-global rmap applied on neighbors") + input_dict = { + "r1": { + "bgp": [ + { + "local_as": "100", + "vrf": "ISR", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r1-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + { + "local_as": "100", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + { + "local_as": "100", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r1-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + ] + }, + "r2": { + "bgp": [ + { + "local_as": "100", + "vrf": "ISR", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r2-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + { + "local_as": "100", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r2-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + { + "local_as": "100", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r4": { + "dest_link": { + "r2-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + ] + }, + "r3": { + "bgp": [ + { + "local_as": "300", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r3-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + { + "local_as": "300", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r3-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + ] + }, + "r4": { + "bgp": [ + { + "local_as": "400", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r1": { + "dest_link": { + "r4-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + { + "local_as": "400", + "address_family": { + "ipv6": { + "unicast": { + "neighbor": { + "r2": { + "dest_link": { + "r4-link1": { + "route_maps": [ + { + "name": "rmap_global", + "direction": "in", + "delete": True, + } + ] + } + } + } + } + } + } + }, + }, + ] + }, + } + + result = create_router_bgp(tgen, topo, input_dict) + assert result is True, "Testcase :Failed \n Error: {}".format(result) + + return True + + +def test_bgp_best_path_with_dynamic_import_p0(request): + """ + 1.5.6. Verify BGP best path selection algorithm works fine when + routes are imported from ISR to default vrf and vice versa. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + build_config_from_json(tgen, topo) + + if tgen.routers_have_failure(): + check_router_status(tgen) + + for addr_type in ADDR_TYPES: + + step( + "Redistribute configured static routes into BGP process" " on R1/R2 and R3" + ) + + input_dict_1 = {} + DUT = ["r1", "r2", "r3", "r4"] + VRFS = ["ISR", "ISR", "default", "default"] + AS_NUM = [100, 100, 300, 400] + + for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): + temp = {dut: {"bgp": []}} + input_dict_1.update(temp) + + temp[dut]["bgp"].append( + { + "local_as": as_num, + "vrf": vrf, + "address_family": { + addr_type: { + "unicast": {"redistribute": [{"redist_type": "static"}]} + } + }, + } + ) + + result = create_router_bgp(tgen, topo, input_dict_1) + assert result is True, "Testcase {} :Failed \n Error: {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + + step("Import from default vrf into vrf ISR on R1 and R2 as below") + + input_dict_vrf = {} + DUT = ["r1", "r2"] + VRFS = ["ISR", "ISR"] + AS_NUM = [100, 100] + + for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): + temp = {dut: {"bgp": []}} + input_dict_vrf.update(temp) + + temp[dut]["bgp"].append( + { + "local_as": as_num, + "vrf": vrf, + "address_family": { + addr_type: {"unicast": {"import": {"vrf": "default"}}} + }, + } + ) + + result = create_router_bgp(tgen, topo, input_dict_vrf) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_default = {} + DUT = ["r1", "r2"] + VRFS = ["default", "default"] + AS_NUM = [100, 100] + + for dut, vrf, as_num in zip(DUT, VRFS, AS_NUM): + temp = {dut: {"bgp": []}} + input_dict_default.update(temp) + + temp[dut]["bgp"].append( + { + "local_as": as_num, + "vrf": vrf, + "address_family": { + addr_type: {"unicast": {"import": {"vrf": "ISR"}}} + }, + } + ) + + result = create_router_bgp(tgen, topo, input_dict_default) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step( + "Verify ECMP/Next-hop/Imported routes Vs Locally originated " + "routes/eBGP routes vs iBGP routes --already covered in almost" + " all tests" + ) + + for addr_type in ADDR_TYPES: + + step("Verify Pre-emption") + + input_routes_r3 = { + "r3": {"static_routes": [{"network": [NETWORK3_3[addr_type]]}]} + } + + intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"] + intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"] + + if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: + nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1) + nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1) + else: + nh_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"][addr_type].split("/")[ + 0 + ] + nh_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"][addr_type].split("/")[ + 0 + ] + + result = verify_bgp_rib( + tgen, addr_type, "r1", input_routes_r3, next_hop=[nh_r4_r1] + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Shutdown interface connected to r1 from r4:") + shutdown_bringup_interface(tgen, "r4", intf_r4_r1, False) + + for addr_type in ADDR_TYPES: + + input_routes_r3 = { + "r3": {"static_routes": [{"network": [NETWORK3_3[addr_type]]}]} + } + + intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"] + intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"] + + if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: + nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1) + nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1) + else: + nh_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"][addr_type].split("/")[ + 0 + ] + nh_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"][addr_type].split("/")[ + 0 + ] + + step("Verify next-hop is changed") + result = verify_bgp_rib( + tgen, addr_type, "r1", input_routes_r3, next_hop=[nh_r3_r1] + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Bringup interface connected to r1 from r4:") + shutdown_bringup_interface(tgen, "r4", intf_r4_r1, True) + + for addr_type in ADDR_TYPES: + + input_routes_r3 = { + "r3": {"static_routes": [{"network": [NETWORK3_3[addr_type]]}]} + } + + intf_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"]["interface"] + intf_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"]["interface"] + + if addr_type == "ipv6" and "link_local" in PREFERRED_NEXT_HOP: + nh_r3_r1 = get_frr_ipv6_linklocal(tgen, "r3", intf=intf_r3_r1) + nh_r4_r1 = get_frr_ipv6_linklocal(tgen, "r4", intf=intf_r4_r1) + else: + nh_r3_r1 = topo["routers"]["r3"]["links"]["r1-link1"][addr_type].split("/")[ + 0 + ] + nh_r4_r1 = topo["routers"]["r4"]["links"]["r1-link1"][addr_type].split("/")[ + 0 + ] + + step("Verify next-hop is not chnaged aftr shutdown:") + result = verify_bgp_rib( + tgen, addr_type, "r1", input_routes_r3, next_hop=[nh_r3_r1] + ) + assert result is True, "Testcase {} : Failed \n Error {}".format( + tc_name, result + ) + + step("Active-Standby scenario(as-path prepend and Local pref)") + + for addr_type in ADDR_TYPES: + + step("Create prefix-list") + + input_dict_pf = { + "r1": { + "prefix_lists": { + addr_type: { + "pf_ls_{}".format(addr_type): [ + { + "seqid": 10, + "network": NETWORK3_4[addr_type], + "action": "permit", + } + ] + } + } + } + } + result = create_prefix_lists(tgen, input_dict_pf) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + + step("Create route-map to match prefix-list and set localpref 500") + + input_dict_rm = { + "r1": { + "route_maps": { + "rmap_PATH1_{}".format(addr_type): [ + { + "action": "permit", + "seq_id": 10, + "match": { + addr_type: { + "prefix_lists": "pf_ls_{}".format(addr_type) + } + }, + "set": {"locPrf": 500}, + } + ] + } + } + } + + result = create_route_maps(tgen, input_dict_rm) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + step("Create route-map to match prefix-list and set localpref 600") + + input_dict_rm = { + "r1": { + "route_maps": { + "rmap_PATH2_{}".format(addr_type): [ + { + "action": "permit", + "seq_id": 20, + "match": { + addr_type: { + "prefix_lists": "pf_ls_{}".format(addr_type) + } + }, + "set": {"locPrf": 600}, + } + ] + } + } + } + + result = create_route_maps(tgen, input_dict_rm) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + input_dict_rma = { + "r1": { + "bgp": [ + { + "local_as": "100", + "address_family": { + addr_type: { + "unicast": { + "neighbor": { + "r3": { + "dest_link": { + "r1-link1": { + "route_maps": [ + { + "name": "rmap_PATH1_{}".format( + addr_type + ), + "direction": "in", + } + ] + } + } + }, + "r4": { + "dest_link": { + "r1-link1": { + "route_maps": [ + { + "name": "rmap_PATH2_{}".format( + addr_type + ), + "direction": "in", + } + ] + } + } + }, + } + } + } + }, + } + ] + } + } + + result = create_router_bgp(tgen, topo, input_dict_rma) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + dut = "r1" + attribute = "locPrf" + + for addr_type in ADDR_TYPES: + + step("Verify bestpath is installed as per highest localpref") + + input_routes_r3 = { + "r3": { + "static_routes": [ + {"network": [NETWORK3_3[addr_type], NETWORK3_4[addr_type]]} + ] + } + } + + result = verify_best_path_as_per_bgp_attribute( + tgen, addr_type, dut, input_routes_r3, attribute + ) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + + step("Create route-map to match prefix-list and set localpref 700") + + input_dict_rm = { + "r1": { + "route_maps": { + "rmap_PATH1_{}".format(addr_type): [ + { + "action": "permit", + "seq_id": 10, + "match": { + addr_type: { + "prefix_lists": "pf_ls_{}".format(addr_type) + } + }, + "set": {"locPrf": 700}, + } + ] + } + } + } + + result = create_route_maps(tgen, input_dict_rm) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + + step("Verify bestpath is changed as per highest localpref") + + input_routes_r3 = { + "r3": { + "static_routes": [ + {"network": [NETWORK3_3[addr_type], NETWORK3_4[addr_type]]} + ] + } + } + + result = verify_best_path_as_per_bgp_attribute( + tgen, addr_type, dut, input_routes_r3, attribute + ) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + for addr_type in ADDR_TYPES: + + step("Create route-map to match prefix-list and set as-path prepend") + + input_dict_rm = { + "r1": { + "route_maps": { + "rmap_PATH2_{}".format(addr_type): [ + { + "action": "permit", + "seq_id": 20, + "match": { + addr_type: { + "prefix_lists": "pf_ls_{}".format(addr_type) + } + }, + "set": { + "localpref": 700, + "path": {"as_num": "111", "as_action": "prepend"}, + }, + } + ] + } + } + } + + result = create_route_maps(tgen, input_dict_rm) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + attribute = "path" + + for addr_type in ADDR_TYPES: + + step("Verify bestpath is changed as per shortest as-path") + + input_routes_r3 = { + "r3": { + "static_routes": [ + {"network": [NETWORK3_3[addr_type], NETWORK3_4[addr_type]]} + ] + } + } + + result = verify_best_path_as_per_bgp_attribute( + tgen, addr_type, dut, input_routes_r3, attribute + ) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result + ) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) 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 new file mode 100644 index 0000000000..e930b62706 --- /dev/null +++ b/tests/topotests/bgp_vrf_lite_best_path_test/test_bgp_vrf_lite_best_path_topo2.py @@ -0,0 +1,539 @@ +#!/usr/bin/env python + +# +# Copyright (c) 2021 by VMware, Inc. ("VMware") +# Used Copyright (c) 2018 by Network Device Education Foundation, +# Inc. ("NetDEF") in this file. +# +# Permission to use, copy, modify, and/or distribute this software +# for any purpose with or without fee is hereby granted, provided +# that the above copyright notice and this permission notice appear +# in all copies. +# +# THE SOFTWARE IS PROVIDED "AS IS" AND VMWARE DISCLAIMS ALL WARRANTIES +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL VMWARE BE LIABLE FOR +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY +# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, +# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS +# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE +# OF THIS SOFTWARE. +# + +""" +Following tests are covered to test BGP VRF Lite: +1. Verify that locally imported routes are selected as best path over eBGP imported routes + peers. +2. Verify ECMP for imported routes from different VRFs. +""" + +import os +import sys +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__)) +sys.path.append(os.path.join(CWD, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# Required to instantiate the topology builder class. + +# 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, + write_test_header, + check_address_types, + write_test_footer, + reset_config_on_routers, + verify_rib, + step, + create_static_routes, + check_router_status, + apply_raw_config +) + +from lib.topolog import logger +from lib.bgp import ( + verify_bgp_convergence, + create_router_bgp, + verify_bgp_rib, + verify_bgp_bestpath +) +from lib.topojson import build_config_from_json + +pytestmark = [pytest.mark.bgpd, pytest.mark.staticd] + +# Global variables +NETWORK1_1 = {"ipv4": "11.11.11.1/32", "ipv6": "11:11::1/128"} +NETWORK1_2 = {"ipv4": "11.11.11.11/32", "ipv6": "11:11::11/128"} +NETWORK1_3 = {"ipv4": "10.10.10.1/32", "ipv6": "10:10::1/128"} +NETWORK1_4 = {"ipv4": "10.10.10.100/32", "ipv6": "10:10::100/128"} +NETWORK1_5 = {"ipv4": "110.110.110.1/32", "ipv6": "110:110::1/128"} +NETWORK1_6 = {"ipv4": "110.110.110.100/32", "ipv6": "110:110::100/128"} + +NETWORK2_1 = {"ipv4": "22.22.22.2/32", "ipv6": "22:22::2/128"} +NETWORK2_2 = {"ipv4": "22.22.22.22/32", "ipv6": "22:22::22/128"} +NETWORK2_3 = {"ipv4": "20.20.20.20/32", "ipv6": "20:20::20/128"} +NETWORK2_4 = {"ipv4": "20.20.20.200/32", "ipv6": "20:20::200/128"} +NETWORK2_5 = {"ipv4": "220.220.220.20/32", "ipv6": "220:220::20/128"} +NETWORK2_6 = {"ipv4": "220.220.220.200/32", "ipv6": "220:220::200/128"} + +NETWORK3_1 = {"ipv4": "30.30.30.3/32", "ipv6": "30:30::3/128"} +NETWORK3_2 = {"ipv4": "30.30.30.30/32", "ipv6": "30:30::30/128"} + +PREFIX_LIST = { + "ipv4": ["11.11.11.1", "22.22.22.2", "22.22.22.22"], + "ipv6": ["11:11::1", "22:22::2", "22:22::22"], +} +PREFERRED_NEXT_HOP = "global" +VRF_LIST = ["RED", "BLUE", "GREEN"] +COMM_VAL_1 = "100:100" +COMM_VAL_2 = "500:500" +COMM_VAL_3 = "600:600" +BESTPATH = { + "ipv4": "0.0.0.0", + "ipv6": "::" +} + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/bgp_vrf_lite_best_path_topo2.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen) + + # Run these tests for kernel version 4.19 or above + if version_cmp(platform.release(), "4.19") < 0: + error_msg = ( + "BGP vrf dynamic route leak tests will not run " + '(have kernel "{}", but it requires >= 4.19)'.format(platform.release()) + ) + pytest.skip(error_msg) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + global BGP_CONVERGENCE + global ADDR_TYPES + ADDR_TYPES = check_address_types() + + BGP_CONVERGENCE = verify_bgp_convergence(tgen, topo) + assert BGP_CONVERGENCE is True, "setup_module : Failed \n Error: {}".format( + BGP_CONVERGENCE + ) + + logger.info("Running setup_module() done") + + +def teardown_module(): + """Teardown the pytest environment""" + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +##################################################### +# +# Testcases +# +##################################################### + +def test_dynamic_import_ecmp_imported_routed_diffrent_vrfs_p0(request): + """ + Verify ECMP for imported routes from different VRFs. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + reset_config_on_routers(tgen) + + step("Configure same static routes in tenant vrfs RED and GREEN on router " + "R3 and redistribute in respective BGP process") + + for vrf_name in ["RED", "GREEN"]: + for addr_type in ADDR_TYPES: + if vrf_name == "GREEN": + next_hop_vrf = topo["routers"]["r1"]["links"][ + "r3-link3"][addr_type].split("/")[0] + else: + next_hop_vrf = topo["routers"]["r2"]["links"][ + "r3-link1"][addr_type].split("/")[0] + static_routes = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]], + "next_hop": next_hop_vrf, + "vrf": vrf_name + } + ] + } + } + + result = create_static_routes(tgen, static_routes) + assert result is True, "Testcase {} :Failed \n Error: {}". \ + format(tc_name, result) + + step("Redistribute static route on BGP VRF : {}".format(vrf_name)) + temp = {} + for addr_type in ADDR_TYPES: + temp.update({ + addr_type: { + "unicast": { + "redistribute": [{ + "redist_type": "static" + }] + } + } + }) + + redist_dict = {"r3": {"bgp": [{ + "vrf": vrf_name, "local_as": 3, "address_family": temp + }]}} + + result = create_router_bgp(tgen, topo, redist_dict) + assert result is True, "Testcase {} :Failed \n Error: {}". \ + format(tc_name, result) + + step("Verify that configured static routes are installed in respective " + "BGP table for vrf RED & GREEN") + for vrf_name in ["RED", "GREEN"]: + for addr_type in ADDR_TYPES: + if vrf_name == "GREEN": + next_hop_vrf = topo["routers"]["r1"]["links"][ + "r3-link3"][addr_type].split("/")[0] + else: + next_hop_vrf = topo["routers"]["r2"]["links"][ + "r3-link1"][addr_type].split("/")[0] + static_routes = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]], + "vrf": vrf_name + } + ] + } + } + + result = verify_bgp_rib(tgen, addr_type, "r3", static_routes, + next_hop=next_hop_vrf) + assert result is True, "Testcase {} : Failed \n Error {}". \ + format(tc_name, result) + + result = verify_rib(tgen, addr_type, "r3", static_routes, + next_hop=next_hop_vrf) + assert result is True, "Testcase {} : Failed \n Error {}". \ + format(tc_name, result) + + step("Import vrf RED and GREEN into default vrf and Configure ECMP") + bgp_val = [] + for vrf_name in ["RED", "GREEN"]: + temp = {} + for addr_type in ADDR_TYPES: + temp.update({ + addr_type: { + "unicast": { + "import": { + "vrf": vrf_name + }, + "maximum_paths": { + "ebgp": 2 + } + } + } + }) + + bgp_val.append({ + "local_as": 3, "address_family": temp + }) + + import_dict = {"r3": {"bgp": bgp_val}} + + result = create_router_bgp(tgen, topo, import_dict) + assert result is True, "Testcase {} :Failed \n Error: {}". \ + format(tc_name, result) + + step("Configure bgp bestpath on router r3") + r3_raw_config = { + "r3": { + "raw_config": [ + "router bgp 3", + "bgp bestpath as-path multipath-relax" + ] + } + } + result = apply_raw_config(tgen, r3_raw_config) + assert result is True, "Testcase {} :Failed \n Error: {}". \ + format(tc_name, result) + + step("Verify that routes are imported with two different next-hop vrfs " + "and IPs. Additionally R3 must do ECMP for both the routes.") + + for addr_type in ADDR_TYPES: + next_hop_vrf = [ + topo["routers"]["r2"]["links"]["r3-link1"][addr_type]. \ + split("/")[0], + topo["routers"]["r1"]["links"]["r3-link3"][addr_type]. \ + split("/")[0] + ] + static_routes = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]], + } + ] + } + } + + result = verify_bgp_rib(tgen, addr_type, "r3", static_routes, + next_hop=next_hop_vrf) + assert result is True, "Testcase {} : Failed \n Error {}". \ + format(tc_name, result) + + result = verify_rib(tgen, addr_type, "r3", static_routes, + next_hop=next_hop_vrf) + assert result is True, "Testcase {} : Failed \n Error {}". \ + format(tc_name, result) + + step("Now change the next-hop of static routes in vrf RED and GREEN to " + "same IP address") + for addr_type in ADDR_TYPES: + next_hop_vrf = topo["routers"]["r1"]["links"][ + "r3-link3"][addr_type].split("/")[0] + static_routes = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]], + "next_hop": next_hop_vrf, + "vrf": "RED" + }, + { + "network": [NETWORK1_1[addr_type]], + "next_hop": topo["routers"]["r2"]["links"][ + "r3-link1"][addr_type].split("/")[0], + "vrf": "RED", + "delete": True + } + ] + } + } + + result = create_static_routes(tgen, static_routes) + assert result is True, "Testcase {} :Failed \n Error: {}". \ + format(tc_name, result) + + step("Verify that now routes are imported with two different next-hop " + "vrfs but same IPs. Additionally R3 must do ECMP for both the routes") + + for addr_type in ADDR_TYPES: + next_hop_vrf = [ + topo["routers"]["r1"]["links"]["r3-link3"][addr_type].\ + split("/")[0], + topo["routers"]["r1"]["links"]["r3-link3"][addr_type]. \ + split("/")[0] + ] + static_routes = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_1[addr_type]], + } + ] + } + } + + result = verify_bgp_rib(tgen, addr_type, "r3", static_routes, + next_hop=next_hop_vrf) + assert result is True, "Testcase {} : Failed \n Error {}". \ + format(tc_name, result) + + result = verify_rib(tgen, addr_type, "r3", static_routes, + next_hop=next_hop_vrf) + assert result is True, "Testcase {} : Failed \n Error {}". \ + format(tc_name, result) + + write_test_footer(tc_name) + + +def test_locally_imported_routes_selected_as_bestpath_over_ebgp_imported_routes_p0(request): + """ + Verify ECMP for imported routes from different VRFs. + """ + + tgen = get_topogen() + tc_name = request.node.name + write_test_header(tc_name) + if tgen.routers_have_failure(): + check_router_status(tgen) + reset_config_on_routers(tgen) + + step("Configure same static routes on R2 and R3 vrfs and redistribute in BGP " + "for GREEN and RED vrf instances") + for dut, network in zip(["r2", "r3"], [ + [NETWORK1_1, NETWORK1_2], [NETWORK1_1, NETWORK1_2]]): + for vrf_name, network_vrf in zip(["RED", "GREEN"], network): + step("Configure static route for VRF : {} on {}".format(vrf_name, + dut)) + for addr_type in ADDR_TYPES: + static_routes = { + dut: { + "static_routes": [ + { + "network": [network_vrf[addr_type]], + "next_hop": "blackhole", + "vrf": vrf_name + } + ] + } + } + + result = create_static_routes(tgen, static_routes) + assert result is True, "Testcase {} :Failed \n Error: {}". \ + format(tc_name, result) + + for dut, as_num in zip(["r2", "r3"], ["2", "3"]): + for vrf_name in ["RED", "GREEN"]: + step("Redistribute static route on BGP VRF : {}".format(vrf_name)) + temp = {} + for addr_type in ADDR_TYPES: + temp.update({ + addr_type: { + "unicast": { + "redistribute": [{ + "redist_type": "static" + }] + } + } + }) + + redist_dict = {dut: {"bgp": [{ + "vrf": vrf_name, "local_as": as_num, "address_family": temp + }]}} + + result = create_router_bgp(tgen, topo, redist_dict) + assert result is True, "Testcase {} :Failed \n Error: {}". \ + format(tc_name, result) + + step("Verify that R2 and R3 has installed redistributed routes in default " + "and RED vrfs and GREEN respectively:") + for dut, network in zip(["r2", "r3"], + [[NETWORK1_1, NETWORK1_2], + [NETWORK1_1, NETWORK1_2]]): + for vrf_name, network_vrf in zip(["RED", "GREEN"], network): + for addr_type in ADDR_TYPES: + static_routes = { + dut: { + "static_routes": [ + { + "network": [network_vrf[addr_type]], + "next_hop": "blackhole", + "vrf": vrf_name + } + ] + } + } + result = verify_bgp_rib(tgen, addr_type, dut, static_routes) + assert result is True, "Testcase {} : Failed \n Error {}". \ + format(tc_name, result) + + step("Import vrf RED's route in vrf GREEN on R3") + temp = {} + for addr_type in ADDR_TYPES: + temp.update({ + addr_type: { + "unicast": { + "import": { + "vrf": "RED" + } + } + } + }) + + import_dict = {"r3": {"bgp": [{ + "vrf": "GREEN", "local_as": 3, "address_family": temp + }]}} + + result = create_router_bgp(tgen, topo, import_dict) + assert result is True, "Testcase {} :Failed \n Error: {}". \ + format(tc_name, result) + + step("Verify that locally imported routes are installed over eBGP imported" + " routes from VRF RED into VRF GREEN") + for addr_type in ADDR_TYPES: + static_routes = { + "r3": { + "static_routes": [ + { + "network": [NETWORK1_2[addr_type]], + "next_hop": "blackhole", + "vrf": "GREEN" + } + ] + } + } + + input_routes = { + "r3": { + addr_type: [ + { + "network": NETWORK1_2[addr_type], + "bestpath": BESTPATH[addr_type], + "vrf": "GREEN" + } + ] + } + } + + result = verify_bgp_bestpath(tgen, addr_type, input_routes) + assert result is True, "Testcase {} : Failed \n Error {}". \ + format(tc_name, result) + + result = verify_rib(tgen, addr_type, "r3", static_routes) + assert result is True, "Testcase {} : Failed \n Error {}". \ + format(tc_name, result) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/zebra.conf b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/zebra.conf index f19c497208..74359a55da 100644 --- a/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/zebra.conf +++ b/tests/topotests/bgp_vrf_lite_ipv6_rtadv/r1/zebra.conf @@ -1,5 +1,5 @@ -debug zebra packet recv -debug zebra packet send +! debug zebra packet recv +! debug zebra packet send log stdout interface loop1 vrf r1-cust1 ip address 10.254.254.1/32 diff --git a/tests/topotests/bgp_vrf_netns/peer1/exa-send.py b/tests/topotests/bgp_vrf_netns/peer1/exa-send.py index 9279cc45ff..ab0eb8ce8f 100755 --- a/tests/topotests/bgp_vrf_netns/peer1/exa-send.py +++ b/tests/topotests/bgp_vrf_netns/peer1/exa-send.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python2 """ exa-send.py: Send a few testroutes with ExaBGP diff --git a/tests/topotests/bgp_vrf_netns/r1/zebra.conf b/tests/topotests/bgp_vrf_netns/r1/zebra.conf index fd0e18f5fd..ed4edfa0bd 100644 --- a/tests/topotests/bgp_vrf_netns/r1/zebra.conf +++ b/tests/topotests/bgp_vrf_netns/r1/zebra.conf @@ -4,4 +4,4 @@ interface r1-eth0 vrf r1-bgp-cust1 ! line vty ! -debug vrf +! debug vrf diff --git a/tests/topotests/config_timing/test_config_timing.py b/tests/topotests/config_timing/test_config_timing.py index c3eb8ed840..7ab8619b01 100644 --- a/tests/topotests/config_timing/test_config_timing.py +++ b/tests/topotests/config_timing/test_config_timing.py @@ -77,8 +77,8 @@ def teardown_module(mod): tgen.stop_topology() -def get_ip_networks(super_prefix, count): - count_log2 = math.log(count, 2) +def get_ip_networks(super_prefix, base_count, count): + count_log2 = math.log(base_count, 2) if count_log2 != int(count_log2): count_log2 = int(count_log2) + 1 else: @@ -94,6 +94,7 @@ def test_static_timing(): pytest.skip(tgen.errors) def do_config( + base_count, count, bad_indices, base_delta, @@ -121,7 +122,7 @@ def test_static_timing(): router.logdir, rname, "{}-routes-{}.conf".format(iptype.lower(), optype) ) with open(config_file, "w") as f: - for i, net in enumerate(get_ip_networks(super_prefix, count)): + for i, net in enumerate(get_ip_networks(super_prefix, base_count, count)): if i in bad_indices: if add: f.write("ip route {} {} bad_input\n".format(net, via)) @@ -170,25 +171,26 @@ def test_static_timing(): bad_indices = [] for ipv6 in [False, True]: base_delta = do_config( - prefix_count, bad_indices, 0, 0, True, ipv6, prefix_base[ipv6][0] + prefix_count, prefix_count, bad_indices, 0, 0, True, ipv6, prefix_base[ipv6][0] ) # Another set of same number of prefixes do_config( - prefix_count, bad_indices, base_delta, 2, True, ipv6, prefix_base[ipv6][1] + prefix_count, prefix_count, bad_indices, base_delta, 3, True, ipv6, prefix_base[ipv6][1] ) # Duplicate config do_config( - prefix_count, bad_indices, base_delta, 2, True, ipv6, prefix_base[ipv6][0] + prefix_count, prefix_count, bad_indices, base_delta, 3, True, ipv6, prefix_base[ipv6][0] ) # Remove 1/2 of duplicate do_config( + prefix_count, prefix_count // 2, bad_indices, base_delta, - 2, + 3, False, ipv6, prefix_base[ipv6][0], @@ -196,15 +198,15 @@ def test_static_timing(): # Add all back in so 1/2 replicate 1/2 new do_config( - prefix_count, bad_indices, base_delta, 2, True, ipv6, prefix_base[ipv6][0] + prefix_count, prefix_count, bad_indices, base_delta, 3, True, ipv6, prefix_base[ipv6][0] ) # remove all delta = do_config( - prefix_count, bad_indices, base_delta, 2, False, ipv6, prefix_base[ipv6][0] + prefix_count, prefix_count, bad_indices, base_delta, 3, False, ipv6, prefix_base[ipv6][0] ) delta += do_config( - prefix_count, bad_indices, base_delta, 2, False, ipv6, prefix_base[ipv6][1] + prefix_count, prefix_count, bad_indices, base_delta, 3, False, ipv6, prefix_base[ipv6][1] ) diff --git a/tests/topotests/conftest.py b/tests/topotests/conftest.py index 7fe6a5aea1..3e1e6eb79b 100755 --- a/tests/topotests/conftest.py +++ b/tests/topotests/conftest.py @@ -9,6 +9,7 @@ import re import subprocess import sys import time +import resource import pytest import lib.fixtures @@ -21,13 +22,6 @@ from lib.topolog import logger from lib.topotest import g_extra_config as topotest_extra_config from lib.topotest import json_cmp_result -try: - from _pytest._code.code import ExceptionInfo - - leak_check_ok = True -except ImportError: - leak_check_ok = False - def pytest_addoption(parser): """ @@ -138,8 +132,7 @@ def pytest_addoption(parser): def check_for_memleaks(): - if not topotest_extra_config["valgrind_memleaks"]: - return + assert topotest_extra_config["valgrind_memleaks"] leaks = [] tgen = get_topogen() @@ -151,21 +144,25 @@ def check_for_memleaks(): existing = tgen.valgrind_existing_files latest = glob.glob(os.path.join(logdir, "*.valgrind.*")) + daemons = set() for vfile in latest: if vfile in existing: continue - with open(vfile) as vf: + existing.append(vfile) + with open(vfile, encoding="ascii") as vf: vfcontent = vf.read() match = re.search(r"ERROR SUMMARY: (\d+) errors", vfcontent) if match and match.group(1) != "0": emsg = "{} in {}".format(match.group(1), vfile) leaks.append(emsg) + daemons.add(re.match(r".*\.valgrind\.(.*)\.\d+", vfile).group(1)) + + if tgen is not None: + tgen.valgrind_existing_files = existing if leaks: - if leak_check_ok: - pytest.fail("Memleaks found:\n\t" + "\n\t".join(leaks)) - else: - logger.error("Memleaks found:\n\t" + "\n\t".join(leaks)) + logger.error("valgrind memleaks found:\n\t%s", "\n\t".join(leaks)) + pytest.fail("valgrind memleaks found for daemons: " + " ".join(daemons)) def pytest_runtest_logstart(nodeid, location): @@ -178,18 +175,21 @@ def pytest_runtest_logfinish(nodeid, location): topolog.logfinish(nodeid, location) -def pytest_runtest_call(): - """ - This function must be run after setup_module(), it does standarized post - setup routines. It is only being used for the 'topology-only' option. - """ +@pytest.hookimpl(hookwrapper=True) +def pytest_runtest_call(item: pytest.Item) -> None: + "Hook the function that is called to execute the test." + + # For topology only run the CLI then exit if topotest_extra_config["topology_only"]: - tgen = get_topogen() - if tgen is not None: - # Allow user to play with the setup. - tgen.cli() + get_topogen().cli() + pytest.exit("exiting after --topology-only") + + # Let the default pytest_runtest_call execute the test function + yield - pytest.exit("the topology executed successfully") + # Check for leaks if requested + if topotest_extra_config["valgrind_memleaks"]: + check_for_memleaks() def pytest_assertrepr_compare(op, left, right): @@ -222,6 +222,9 @@ def pytest_configure(config): is_xdist = True is_worker = True + resource.setrlimit( + resource.RLIMIT_CORE, (resource.RLIM_INFINITY, resource.RLIM_INFINITY) + ) # ----------------------------------------------------- # Set some defaults for the pytest.ini [pytest] section # --------------------------------------------------- @@ -333,7 +336,10 @@ def pytest_configure(config): topotest_extra_config["pause"] = pause assert_feature_windows(pause, "--pause") - topotest_extra_config["topology_only"] = config.getoption("--topology-only") + topology_only = config.getoption("--topology-only") + if topology_only and is_xdist: + pytest.exit("Cannot use --topology-only with distributed test mode") + topotest_extra_config["topology_only"] = topology_only # Check environment now that we have config if not diagnose_env(rundir): @@ -373,12 +379,6 @@ def pytest_runtest_makereport(item, call): else: pause = False - if call.excinfo is None and call.when == "call": - try: - check_for_memleaks() - except: - call.excinfo = ExceptionInfo() - title = "unset" if call.excinfo is None: @@ -509,5 +509,6 @@ def pytest_runtest_makereport(item, call): # # Add common fixtures available to all tests as parameters # + tgen = pytest.fixture(lib.fixtures.tgen) topo = pytest.fixture(lib.fixtures.topo) diff --git a/tests/topotests/eigrp_topo1/r1/zebra.conf b/tests/topotests/eigrp_topo1/r1/zebra.conf index 56ae4a66f4..51579a7d11 100644 --- a/tests/topotests/eigrp_topo1/r1/zebra.conf +++ b/tests/topotests/eigrp_topo1/r1/zebra.conf @@ -1,5 +1,5 @@ log file zebra.log -debug zebra rib detail +! debug zebra rib detail ! hostname r1 ! diff --git a/tests/topotests/evpn_pim_1/leaf1/pimd.conf b/tests/topotests/evpn_pim_1/leaf1/pimd.conf index d85f33d1fc..b54aada022 100644 --- a/tests/topotests/evpn_pim_1/leaf1/pimd.conf +++ b/tests/topotests/evpn_pim_1/leaf1/pimd.conf @@ -1,6 +1,6 @@ -debug pim events -debug pim nht -debug pim zebra +! debug pim events +! debug pim nht +! debug pim zebra ip pim rp 192.168.100.1 ip pim join-prune-interval 5 ! diff --git a/tests/topotests/isis_lfa_topo1/rt1/isisd.conf b/tests/topotests/isis_lfa_topo1/rt1/isisd.conf index 2ad8c12538..833cd66ced 100644 --- a/tests/topotests/isis_lfa_topo1/rt1/isisd.conf +++ b/tests/topotests/isis_lfa_topo1/rt1/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt1 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ipv6 router isis 1 diff --git a/tests/topotests/isis_lfa_topo1/rt1/zebra.conf b/tests/topotests/isis_lfa_topo1/rt1/zebra.conf index 317f1031df..4ce144495c 100644 --- a/tests/topotests/isis_lfa_topo1/rt1/zebra.conf +++ b/tests/topotests/isis_lfa_topo1/rt1/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/isis_lfa_topo1/rt2/isisd.conf b/tests/topotests/isis_lfa_topo1/rt2/isisd.conf index 39ff2570d4..42dee00e60 100644 --- a/tests/topotests/isis_lfa_topo1/rt2/isisd.conf +++ b/tests/topotests/isis_lfa_topo1/rt2/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt2 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ipv6 router isis 1 diff --git a/tests/topotests/isis_lfa_topo1/rt2/zebra.conf b/tests/topotests/isis_lfa_topo1/rt2/zebra.conf index 9feaada791..3372ec5033 100644 --- a/tests/topotests/isis_lfa_topo1/rt2/zebra.conf +++ b/tests/topotests/isis_lfa_topo1/rt2/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/isis_lfa_topo1/rt3/isisd.conf b/tests/topotests/isis_lfa_topo1/rt3/isisd.conf index 8b0c7bd0dc..9dd813cff6 100644 --- a/tests/topotests/isis_lfa_topo1/rt3/isisd.conf +++ b/tests/topotests/isis_lfa_topo1/rt3/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt3 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ipv6 router isis 1 diff --git a/tests/topotests/isis_lfa_topo1/rt3/zebra.conf b/tests/topotests/isis_lfa_topo1/rt3/zebra.conf index 48d732e72a..231b02b9bd 100644 --- a/tests/topotests/isis_lfa_topo1/rt3/zebra.conf +++ b/tests/topotests/isis_lfa_topo1/rt3/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/isis_lfa_topo1/rt4/isisd.conf b/tests/topotests/isis_lfa_topo1/rt4/isisd.conf index 86edee6ab1..7500ff8d7b 100644 --- a/tests/topotests/isis_lfa_topo1/rt4/isisd.conf +++ b/tests/topotests/isis_lfa_topo1/rt4/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt4 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ipv6 router isis 1 diff --git a/tests/topotests/isis_lfa_topo1/rt4/zebra.conf b/tests/topotests/isis_lfa_topo1/rt4/zebra.conf index bff10860cc..2d62924334 100644 --- a/tests/topotests/isis_lfa_topo1/rt4/zebra.conf +++ b/tests/topotests/isis_lfa_topo1/rt4/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/isis_lfa_topo1/rt5/isisd.conf b/tests/topotests/isis_lfa_topo1/rt5/isisd.conf index 7a7cfe557d..5e022e9ad8 100644 --- a/tests/topotests/isis_lfa_topo1/rt5/isisd.conf +++ b/tests/topotests/isis_lfa_topo1/rt5/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt5 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ipv6 router isis 1 diff --git a/tests/topotests/isis_lfa_topo1/rt5/zebra.conf b/tests/topotests/isis_lfa_topo1/rt5/zebra.conf index ee1e46c966..efb7bf6d12 100644 --- a/tests/topotests/isis_lfa_topo1/rt5/zebra.conf +++ b/tests/topotests/isis_lfa_topo1/rt5/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/isis_lfa_topo1/rt6/isisd.conf b/tests/topotests/isis_lfa_topo1/rt6/isisd.conf index 20cb7769a4..d262e8a564 100644 --- a/tests/topotests/isis_lfa_topo1/rt6/isisd.conf +++ b/tests/topotests/isis_lfa_topo1/rt6/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt6 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ipv6 router isis 1 diff --git a/tests/topotests/isis_lfa_topo1/rt6/zebra.conf b/tests/topotests/isis_lfa_topo1/rt6/zebra.conf index 4108078896..31650bd260 100644 --- a/tests/topotests/isis_lfa_topo1/rt6/zebra.conf +++ b/tests/topotests/isis_lfa_topo1/rt6/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt6 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 6.6.6.6/32 diff --git a/tests/topotests/isis_lfa_topo1/rt7/isisd.conf b/tests/topotests/isis_lfa_topo1/rt7/isisd.conf index 713e6d39f4..c2061236c3 100644 --- a/tests/topotests/isis_lfa_topo1/rt7/isisd.conf +++ b/tests/topotests/isis_lfa_topo1/rt7/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt6 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ipv6 router isis 1 diff --git a/tests/topotests/isis_lfa_topo1/rt7/zebra.conf b/tests/topotests/isis_lfa_topo1/rt7/zebra.conf index 353c9efa93..4271ccea11 100644 --- a/tests/topotests/isis_lfa_topo1/rt7/zebra.conf +++ b/tests/topotests/isis_lfa_topo1/rt7/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt7 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 7.7.7.7/32 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt1/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt1/isisd.conf index 90764a0d0f..fc004e429b 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt1/isisd.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt1/isisd.conf @@ -2,11 +2,11 @@ password 1 hostname rt1 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt1/zebra.conf b/tests/topotests/isis_lsp_bits_topo1/rt1/zebra.conf index 9d71d3005f..37b3f27cae 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt1/zebra.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt1/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt2/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt2/isisd.conf index 2bc4c4ad97..d01720f4f0 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt2/isisd.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt2/isisd.conf @@ -1,11 +1,11 @@ hostname rt2 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt2/zebra.conf b/tests/topotests/isis_lsp_bits_topo1/rt2/zebra.conf index 234e10efa9..03acb6f272 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt2/zebra.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt2/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt3/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt3/isisd.conf index 9ad97109b5..a8d589678a 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt3/isisd.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt3/isisd.conf @@ -1,11 +1,11 @@ hostname rt3 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt3/zebra.conf b/tests/topotests/isis_lsp_bits_topo1/rt3/zebra.conf index 9a0defd62b..5f59be19b3 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt3/zebra.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt3/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt4/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt4/isisd.conf index e85412a71d..2d30790f29 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt4/isisd.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt4/isisd.conf @@ -1,11 +1,11 @@ hostname rt4 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 4 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt4/zebra.conf b/tests/topotests/isis_lsp_bits_topo1/rt4/zebra.conf index adcf433249..a567f3b864 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt4/zebra.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt4/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt5/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt5/isisd.conf index 2cab0c88fc..263c3f9478 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt5/isisd.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt5/isisd.conf @@ -1,11 +1,11 @@ hostname rt5 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 2 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt5/zebra.conf b/tests/topotests/isis_lsp_bits_topo1/rt5/zebra.conf index 0f10ce921f..50aedb3940 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt5/zebra.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt5/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt6/isisd.conf b/tests/topotests/isis_lsp_bits_topo1/rt6/isisd.conf index 249f945e0c..505604ef33 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt6/isisd.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt6/isisd.conf @@ -1,11 +1,11 @@ hostname rt6 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 4 diff --git a/tests/topotests/isis_lsp_bits_topo1/rt6/zebra.conf b/tests/topotests/isis_lsp_bits_topo1/rt6/zebra.conf index 6084010a93..4d51d3df84 100644 --- a/tests/topotests/isis_lsp_bits_topo1/rt6/zebra.conf +++ b/tests/topotests/isis_lsp_bits_topo1/rt6/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt6 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 6.6.6.6/32 diff --git a/tests/topotests/isis_rlfa_topo1/rt1/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt1/isisd.conf index a80f30dc7b..f7f0a95e1c 100644 --- a/tests/topotests/isis_rlfa_topo1/rt1/isisd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt1/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt1 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_rlfa_topo1/rt1/ldpd.conf b/tests/topotests/isis_rlfa_topo1/rt1/ldpd.conf index f60fdb9742..eb8589219e 100644 --- a/tests/topotests/isis_rlfa_topo1/rt1/ldpd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt1/ldpd.conf @@ -2,9 +2,9 @@ log file ldpd.log ! hostname rt1 ! -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp zebra +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp zebra ! mpls ldp router-id 10.0.255.1 diff --git a/tests/topotests/isis_rlfa_topo1/rt1/zebra.conf b/tests/topotests/isis_rlfa_topo1/rt1/zebra.conf index 741fc2d02b..6210b29950 100644 --- a/tests/topotests/isis_rlfa_topo1/rt1/zebra.conf +++ b/tests/topotests/isis_rlfa_topo1/rt1/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 10.0.255.1/32 diff --git a/tests/topotests/isis_rlfa_topo1/rt2/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt2/isisd.conf index 7b4c6c50b9..6595052fab 100644 --- a/tests/topotests/isis_rlfa_topo1/rt2/isisd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt2/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt2 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_rlfa_topo1/rt2/ldpd.conf b/tests/topotests/isis_rlfa_topo1/rt2/ldpd.conf index 0a815ef004..25882be67a 100644 --- a/tests/topotests/isis_rlfa_topo1/rt2/ldpd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt2/ldpd.conf @@ -2,9 +2,9 @@ log file ldpd.log ! hostname rt2 ! -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp zebra +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp zebra ! mpls ldp router-id 10.0.255.2 diff --git a/tests/topotests/isis_rlfa_topo1/rt2/zebra.conf b/tests/topotests/isis_rlfa_topo1/rt2/zebra.conf index 657c69bf28..38c561d475 100644 --- a/tests/topotests/isis_rlfa_topo1/rt2/zebra.conf +++ b/tests/topotests/isis_rlfa_topo1/rt2/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 10.0.255.2/32 diff --git a/tests/topotests/isis_rlfa_topo1/rt3/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt3/isisd.conf index 17d58a9d15..a029b7140f 100644 --- a/tests/topotests/isis_rlfa_topo1/rt3/isisd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt3/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt3 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_rlfa_topo1/rt3/ldpd.conf b/tests/topotests/isis_rlfa_topo1/rt3/ldpd.conf index 40f1f5587a..8f2234a207 100644 --- a/tests/topotests/isis_rlfa_topo1/rt3/ldpd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt3/ldpd.conf @@ -2,9 +2,9 @@ log file ldpd.log ! hostname rt3 ! -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp zebra +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp zebra ! mpls ldp router-id 10.0.255.3 diff --git a/tests/topotests/isis_rlfa_topo1/rt3/zebra.conf b/tests/topotests/isis_rlfa_topo1/rt3/zebra.conf index 86f5d2871a..21557645d8 100644 --- a/tests/topotests/isis_rlfa_topo1/rt3/zebra.conf +++ b/tests/topotests/isis_rlfa_topo1/rt3/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 10.0.255.3/32 diff --git a/tests/topotests/isis_rlfa_topo1/rt4/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt4/isisd.conf index 1519fd4c16..86aa6b1f46 100644 --- a/tests/topotests/isis_rlfa_topo1/rt4/isisd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt4/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt4 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_rlfa_topo1/rt4/ldpd.conf b/tests/topotests/isis_rlfa_topo1/rt4/ldpd.conf index 569ecf733e..c8d467c518 100644 --- a/tests/topotests/isis_rlfa_topo1/rt4/ldpd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt4/ldpd.conf @@ -2,9 +2,9 @@ log file ldpd.log ! hostname rt4 ! -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp zebra +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp zebra ! mpls ldp router-id 10.0.255.4 diff --git a/tests/topotests/isis_rlfa_topo1/rt4/zebra.conf b/tests/topotests/isis_rlfa_topo1/rt4/zebra.conf index 1dd09bf83b..4e22813b94 100644 --- a/tests/topotests/isis_rlfa_topo1/rt4/zebra.conf +++ b/tests/topotests/isis_rlfa_topo1/rt4/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 10.0.255.4/32 diff --git a/tests/topotests/isis_rlfa_topo1/rt5/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt5/isisd.conf index caf7477073..e4fc9cdd4c 100644 --- a/tests/topotests/isis_rlfa_topo1/rt5/isisd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt5/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt5 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_rlfa_topo1/rt5/ldpd.conf b/tests/topotests/isis_rlfa_topo1/rt5/ldpd.conf index 519c3d3628..c5fc36a61c 100644 --- a/tests/topotests/isis_rlfa_topo1/rt5/ldpd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt5/ldpd.conf @@ -2,9 +2,9 @@ log file ldpd.log ! hostname rt5 ! -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp zebra +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp zebra ! mpls ldp router-id 10.0.255.5 diff --git a/tests/topotests/isis_rlfa_topo1/rt5/zebra.conf b/tests/topotests/isis_rlfa_topo1/rt5/zebra.conf index 7117a2a2e3..83bbb1ba4d 100644 --- a/tests/topotests/isis_rlfa_topo1/rt5/zebra.conf +++ b/tests/topotests/isis_rlfa_topo1/rt5/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 10.0.255.5/32 diff --git a/tests/topotests/isis_rlfa_topo1/rt6/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt6/isisd.conf index cdf6267236..81319e4264 100644 --- a/tests/topotests/isis_rlfa_topo1/rt6/isisd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt6/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt6 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_rlfa_topo1/rt6/ldpd.conf b/tests/topotests/isis_rlfa_topo1/rt6/ldpd.conf index a5b7062bec..11bed3ce30 100644 --- a/tests/topotests/isis_rlfa_topo1/rt6/ldpd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt6/ldpd.conf @@ -2,9 +2,9 @@ log file ldpd.log ! hostname rt6 ! -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp zebra +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp zebra ! mpls ldp router-id 10.0.255.6 diff --git a/tests/topotests/isis_rlfa_topo1/rt6/zebra.conf b/tests/topotests/isis_rlfa_topo1/rt6/zebra.conf index c6344870b7..1fdd0d4b61 100644 --- a/tests/topotests/isis_rlfa_topo1/rt6/zebra.conf +++ b/tests/topotests/isis_rlfa_topo1/rt6/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt6 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 10.0.255.6/32 diff --git a/tests/topotests/isis_rlfa_topo1/rt7/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt7/isisd.conf index 8ab8fcb232..1f48671e74 100644 --- a/tests/topotests/isis_rlfa_topo1/rt7/isisd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt7/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt7 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_rlfa_topo1/rt7/ldpd.conf b/tests/topotests/isis_rlfa_topo1/rt7/ldpd.conf index 26d428c4c6..6c40ccb33c 100644 --- a/tests/topotests/isis_rlfa_topo1/rt7/ldpd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt7/ldpd.conf @@ -2,9 +2,9 @@ log file ldpd.log ! hostname rt7 ! -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp zebra +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp zebra ! mpls ldp router-id 10.0.255.7 diff --git a/tests/topotests/isis_rlfa_topo1/rt7/zebra.conf b/tests/topotests/isis_rlfa_topo1/rt7/zebra.conf index 4c5e0f1126..114ebd93a6 100644 --- a/tests/topotests/isis_rlfa_topo1/rt7/zebra.conf +++ b/tests/topotests/isis_rlfa_topo1/rt7/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt7 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 10.0.255.7/32 diff --git a/tests/topotests/isis_rlfa_topo1/rt8/isisd.conf b/tests/topotests/isis_rlfa_topo1/rt8/isisd.conf index abdc6a53a5..7675f777a7 100644 --- a/tests/topotests/isis_rlfa_topo1/rt8/isisd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt8/isisd.conf @@ -2,10 +2,10 @@ password 1 hostname rt8 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_rlfa_topo1/rt8/ldpd.conf b/tests/topotests/isis_rlfa_topo1/rt8/ldpd.conf index 1629f82de1..36e7ce12a9 100644 --- a/tests/topotests/isis_rlfa_topo1/rt8/ldpd.conf +++ b/tests/topotests/isis_rlfa_topo1/rt8/ldpd.conf @@ -2,9 +2,9 @@ log file ldpd.log ! hostname rt8 ! -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp zebra +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp zebra ! mpls ldp router-id 10.0.255.8 diff --git a/tests/topotests/isis_rlfa_topo1/rt8/zebra.conf b/tests/topotests/isis_rlfa_topo1/rt8/zebra.conf index f3f10f649a..001e62ed25 100644 --- a/tests/topotests/isis_rlfa_topo1/rt8/zebra.conf +++ b/tests/topotests/isis_rlfa_topo1/rt8/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt8 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 10.0.255.8/32 diff --git a/tests/topotests/isis_snmp/r1/isisd.conf b/tests/topotests/isis_snmp/r1/isisd.conf index dd32d3b8a5..4928341225 100644 --- a/tests/topotests/isis_snmp/r1/isisd.conf +++ b/tests/topotests/isis_snmp/r1/isisd.conf @@ -1,8 +1,8 @@ hostname r1 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets agentx ! router isis 1 diff --git a/tests/topotests/isis_snmp/r1/ldpd.conf b/tests/topotests/isis_snmp/r1/ldpd.conf index 4ec296ca5a..5b1cbfebc9 100644 --- a/tests/topotests/isis_snmp/r1/ldpd.conf +++ b/tests/topotests/isis_snmp/r1/ldpd.conf @@ -1,10 +1,10 @@ hostname r1 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync agentx ! mpls ldp diff --git a/tests/topotests/isis_snmp/r1/zebra.conf b/tests/topotests/isis_snmp/r1/zebra.conf index 6ac341e431..4ca46da805 100644 --- a/tests/topotests/isis_snmp/r1/zebra.conf +++ b/tests/topotests/isis_snmp/r1/zebra.conf @@ -2,10 +2,10 @@ log file zebra.log ! hostname r1 ! -debug zebra kernel -debug zebra rib detailed -debug zebra dplane detailed -debug zebra nht +! debug zebra kernel +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra nht ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/isis_snmp/r2/isisd.conf b/tests/topotests/isis_snmp/r2/isisd.conf index 4403d8913b..9bb8a8d5f9 100644 --- a/tests/topotests/isis_snmp/r2/isisd.conf +++ b/tests/topotests/isis_snmp/r2/isisd.conf @@ -1,8 +1,8 @@ hostname r2 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets agentx ! router isis 1 diff --git a/tests/topotests/isis_snmp/r2/ldpd.conf b/tests/topotests/isis_snmp/r2/ldpd.conf index eb963fe41c..533d2d9d49 100644 --- a/tests/topotests/isis_snmp/r2/ldpd.conf +++ b/tests/topotests/isis_snmp/r2/ldpd.conf @@ -1,10 +1,10 @@ hostname r2 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/isis_snmp/r2/zebra.conf b/tests/topotests/isis_snmp/r2/zebra.conf index 4aa7440c33..9f6e3d5359 100644 --- a/tests/topotests/isis_snmp/r2/zebra.conf +++ b/tests/topotests/isis_snmp/r2/zebra.conf @@ -2,10 +2,10 @@ log file zebra.log ! hostname r2 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/isis_snmp/r3/isisd.conf b/tests/topotests/isis_snmp/r3/isisd.conf index e06fe8c1f9..4daec791b3 100644 --- a/tests/topotests/isis_snmp/r3/isisd.conf +++ b/tests/topotests/isis_snmp/r3/isisd.conf @@ -1,8 +1,8 @@ hostname r3 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets agentx ! router isis 1 diff --git a/tests/topotests/isis_snmp/r3/ldpd.conf b/tests/topotests/isis_snmp/r3/ldpd.conf index 2935caf13b..fae25e0710 100644 --- a/tests/topotests/isis_snmp/r3/ldpd.conf +++ b/tests/topotests/isis_snmp/r3/ldpd.conf @@ -1,10 +1,10 @@ hostname r3 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/isis_snmp/r3/zebra.conf b/tests/topotests/isis_snmp/r3/zebra.conf index 6b76114d4d..4e6bddd296 100644 --- a/tests/topotests/isis_snmp/r3/zebra.conf +++ b/tests/topotests/isis_snmp/r3/zebra.conf @@ -2,10 +2,10 @@ log file zebra.log ! hostname r3 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/isis_snmp/r4/isisd.conf b/tests/topotests/isis_snmp/r4/isisd.conf index 1256141da9..32b07b3cb4 100644 --- a/tests/topotests/isis_snmp/r4/isisd.conf +++ b/tests/topotests/isis_snmp/r4/isisd.conf @@ -1,8 +1,8 @@ hostname r4 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets agentx ! router isis 1 diff --git a/tests/topotests/isis_snmp/r4/ldpd.conf b/tests/topotests/isis_snmp/r4/ldpd.conf index b27952514b..dbffdff42c 100644 --- a/tests/topotests/isis_snmp/r4/ldpd.conf +++ b/tests/topotests/isis_snmp/r4/ldpd.conf @@ -1,10 +1,10 @@ hostname r4 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 4.4.4.4 diff --git a/tests/topotests/isis_snmp/r4/zebra.conf b/tests/topotests/isis_snmp/r4/zebra.conf index fa13601164..66b8ea3de8 100644 --- a/tests/topotests/isis_snmp/r4/zebra.conf +++ b/tests/topotests/isis_snmp/r4/zebra.conf @@ -2,10 +2,10 @@ log file zebra.log ! hostname r4 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/isis_snmp/r5/isisd.conf b/tests/topotests/isis_snmp/r5/isisd.conf index 58859041a9..fe3ca0f3aa 100644 --- a/tests/topotests/isis_snmp/r5/isisd.conf +++ b/tests/topotests/isis_snmp/r5/isisd.conf @@ -1,8 +1,8 @@ hostname r5 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets agentx ! router isis 1 diff --git a/tests/topotests/isis_snmp/r5/ldpd.conf b/tests/topotests/isis_snmp/r5/ldpd.conf index f3ba867a9f..fd273d5dae 100644 --- a/tests/topotests/isis_snmp/r5/ldpd.conf +++ b/tests/topotests/isis_snmp/r5/ldpd.conf @@ -1,10 +1,10 @@ hostname r5 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 5.5.5.5 diff --git a/tests/topotests/isis_snmp/r5/zebra.conf b/tests/topotests/isis_snmp/r5/zebra.conf index 7230129f22..5607fab9cd 100644 --- a/tests/topotests/isis_snmp/r5/zebra.conf +++ b/tests/topotests/isis_snmp/r5/zebra.conf @@ -2,10 +2,10 @@ log file zebra.log ! hostname r5 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/isis_sr_te_topo1/dst/zebra.conf b/tests/topotests/isis_sr_te_topo1/dst/zebra.conf index e873ac8a5c..0c7937b9bb 100644 --- a/tests/topotests/isis_sr_te_topo1/dst/zebra.conf +++ b/tests/topotests/isis_sr_te_topo1/dst/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname dst ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 9.9.9.2/32 diff --git a/tests/topotests/isis_sr_te_topo1/rt1/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt1/isisd.conf index 70ae1b07f5..3d5ac20451 100644 --- a/tests/topotests/isis_sr_te_topo1/rt1/isisd.conf +++ b/tests/topotests/isis_sr_te_topo1/rt1/isisd.conf @@ -2,11 +2,11 @@ password 1 hostname rt1 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_te_topo1/rt1/zebra.conf b/tests/topotests/isis_sr_te_topo1/rt1/zebra.conf index 9d71d3005f..37b3f27cae 100644 --- a/tests/topotests/isis_sr_te_topo1/rt1/zebra.conf +++ b/tests/topotests/isis_sr_te_topo1/rt1/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/isis_sr_te_topo1/rt2/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt2/isisd.conf index 733f26bc62..ba214c92c1 100644 --- a/tests/topotests/isis_sr_te_topo1/rt2/isisd.conf +++ b/tests/topotests/isis_sr_te_topo1/rt2/isisd.conf @@ -1,11 +1,11 @@ hostname rt2 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_te_topo1/rt2/zebra.conf b/tests/topotests/isis_sr_te_topo1/rt2/zebra.conf index dcb0686dc2..f9ac098f4f 100644 --- a/tests/topotests/isis_sr_te_topo1/rt2/zebra.conf +++ b/tests/topotests/isis_sr_te_topo1/rt2/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/isis_sr_te_topo1/rt3/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt3/isisd.conf index 2395906cbf..482d8152c2 100644 --- a/tests/topotests/isis_sr_te_topo1/rt3/isisd.conf +++ b/tests/topotests/isis_sr_te_topo1/rt3/isisd.conf @@ -1,11 +1,11 @@ hostname rt3 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_te_topo1/rt3/zebra.conf b/tests/topotests/isis_sr_te_topo1/rt3/zebra.conf index 3254529386..441c9a3aca 100644 --- a/tests/topotests/isis_sr_te_topo1/rt3/zebra.conf +++ b/tests/topotests/isis_sr_te_topo1/rt3/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/isis_sr_te_topo1/rt4/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt4/isisd.conf index 07a7867cbb..851c6da019 100644 --- a/tests/topotests/isis_sr_te_topo1/rt4/isisd.conf +++ b/tests/topotests/isis_sr_te_topo1/rt4/isisd.conf @@ -1,11 +1,11 @@ hostname rt4 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_te_topo1/rt4/zebra.conf b/tests/topotests/isis_sr_te_topo1/rt4/zebra.conf index 4945897e9d..a2569aa51f 100644 --- a/tests/topotests/isis_sr_te_topo1/rt4/zebra.conf +++ b/tests/topotests/isis_sr_te_topo1/rt4/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/isis_sr_te_topo1/rt5/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt5/isisd.conf index b0fcdede07..4cc54f318c 100644 --- a/tests/topotests/isis_sr_te_topo1/rt5/isisd.conf +++ b/tests/topotests/isis_sr_te_topo1/rt5/isisd.conf @@ -1,11 +1,11 @@ hostname rt5 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_te_topo1/rt5/zebra.conf b/tests/topotests/isis_sr_te_topo1/rt5/zebra.conf index 4cfea1a59f..f62cc8ffd3 100644 --- a/tests/topotests/isis_sr_te_topo1/rt5/zebra.conf +++ b/tests/topotests/isis_sr_te_topo1/rt5/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/isis_sr_te_topo1/rt6/isisd.conf b/tests/topotests/isis_sr_te_topo1/rt6/isisd.conf index 3be24ad24c..8fec87b929 100644 --- a/tests/topotests/isis_sr_te_topo1/rt6/isisd.conf +++ b/tests/topotests/isis_sr_te_topo1/rt6/isisd.conf @@ -1,11 +1,11 @@ hostname rt6 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_te_topo1/rt6/zebra.conf b/tests/topotests/isis_sr_te_topo1/rt6/zebra.conf index 32c6e6c4e0..f2f1a3eefe 100644 --- a/tests/topotests/isis_sr_te_topo1/rt6/zebra.conf +++ b/tests/topotests/isis_sr_te_topo1/rt6/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt6 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 6.6.6.6/32 diff --git a/tests/topotests/isis_sr_topo1/rt1/isisd.conf b/tests/topotests/isis_sr_topo1/rt1/isisd.conf index f441527597..ed09753d20 100644 --- a/tests/topotests/isis_sr_topo1/rt1/isisd.conf +++ b/tests/topotests/isis_sr_topo1/rt1/isisd.conf @@ -2,11 +2,11 @@ password 1 hostname rt1 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_topo1/rt1/zebra.conf b/tests/topotests/isis_sr_topo1/rt1/zebra.conf index 9d71d3005f..37b3f27cae 100644 --- a/tests/topotests/isis_sr_topo1/rt1/zebra.conf +++ b/tests/topotests/isis_sr_topo1/rt1/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/isis_sr_topo1/rt2/isisd.conf b/tests/topotests/isis_sr_topo1/rt2/isisd.conf index 796b6ed32c..9b8efe40e9 100644 --- a/tests/topotests/isis_sr_topo1/rt2/isisd.conf +++ b/tests/topotests/isis_sr_topo1/rt2/isisd.conf @@ -1,11 +1,11 @@ hostname rt2 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_topo1/rt2/zebra.conf b/tests/topotests/isis_sr_topo1/rt2/zebra.conf index dcb0686dc2..f9ac098f4f 100644 --- a/tests/topotests/isis_sr_topo1/rt2/zebra.conf +++ b/tests/topotests/isis_sr_topo1/rt2/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/isis_sr_topo1/rt3/isisd.conf b/tests/topotests/isis_sr_topo1/rt3/isisd.conf index cc2aa1782b..ded8bd1576 100644 --- a/tests/topotests/isis_sr_topo1/rt3/isisd.conf +++ b/tests/topotests/isis_sr_topo1/rt3/isisd.conf @@ -1,11 +1,11 @@ hostname rt3 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_topo1/rt3/zebra.conf b/tests/topotests/isis_sr_topo1/rt3/zebra.conf index 3254529386..441c9a3aca 100644 --- a/tests/topotests/isis_sr_topo1/rt3/zebra.conf +++ b/tests/topotests/isis_sr_topo1/rt3/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/isis_sr_topo1/rt4/isisd.conf b/tests/topotests/isis_sr_topo1/rt4/isisd.conf index 3852b1962b..ba9704531c 100644 --- a/tests/topotests/isis_sr_topo1/rt4/isisd.conf +++ b/tests/topotests/isis_sr_topo1/rt4/isisd.conf @@ -1,11 +1,11 @@ hostname rt4 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_topo1/rt4/zebra.conf b/tests/topotests/isis_sr_topo1/rt4/zebra.conf index 5889901c56..b66a9afcb5 100644 --- a/tests/topotests/isis_sr_topo1/rt4/zebra.conf +++ b/tests/topotests/isis_sr_topo1/rt4/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/isis_sr_topo1/rt5/isisd.conf b/tests/topotests/isis_sr_topo1/rt5/isisd.conf index f7beea796c..3fe7bdf1b2 100644 --- a/tests/topotests/isis_sr_topo1/rt5/isisd.conf +++ b/tests/topotests/isis_sr_topo1/rt5/isisd.conf @@ -1,11 +1,11 @@ hostname rt5 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_topo1/rt5/zebra.conf b/tests/topotests/isis_sr_topo1/rt5/zebra.conf index a0c8f2cd7e..90ceb817fa 100644 --- a/tests/topotests/isis_sr_topo1/rt5/zebra.conf +++ b/tests/topotests/isis_sr_topo1/rt5/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/isis_sr_topo1/rt6/isisd.conf b/tests/topotests/isis_sr_topo1/rt6/isisd.conf index a29b78f0a4..e7a7e2dfd4 100644 --- a/tests/topotests/isis_sr_topo1/rt6/isisd.conf +++ b/tests/topotests/isis_sr_topo1/rt6/isisd.conf @@ -1,11 +1,11 @@ hostname rt6 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_sr_topo1/rt6/zebra.conf b/tests/topotests/isis_sr_topo1/rt6/zebra.conf index 6084010a93..4d51d3df84 100644 --- a/tests/topotests/isis_sr_topo1/rt6/zebra.conf +++ b/tests/topotests/isis_sr_topo1/rt6/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt6 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 6.6.6.6/32 diff --git a/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf index a447a2aa5a..955bd5caa0 100644 --- a/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt1/isisd.conf @@ -2,11 +2,11 @@ password 1 hostname rt1 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_tilfa_topo1/rt1/zebra.conf b/tests/topotests/isis_tilfa_topo1/rt1/zebra.conf index 9d71d3005f..37b3f27cae 100644 --- a/tests/topotests/isis_tilfa_topo1/rt1/zebra.conf +++ b/tests/topotests/isis_tilfa_topo1/rt1/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf index 1a756e2c72..f971c658d4 100644 --- a/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt2/isisd.conf @@ -1,11 +1,11 @@ hostname rt2 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_tilfa_topo1/rt2/zebra.conf b/tests/topotests/isis_tilfa_topo1/rt2/zebra.conf index dcb0686dc2..f9ac098f4f 100644 --- a/tests/topotests/isis_tilfa_topo1/rt2/zebra.conf +++ b/tests/topotests/isis_tilfa_topo1/rt2/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf index 986bf2804a..64f091cfed 100644 --- a/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt3/isisd.conf @@ -1,11 +1,11 @@ hostname rt3 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_tilfa_topo1/rt3/zebra.conf b/tests/topotests/isis_tilfa_topo1/rt3/zebra.conf index 3254529386..441c9a3aca 100644 --- a/tests/topotests/isis_tilfa_topo1/rt3/zebra.conf +++ b/tests/topotests/isis_tilfa_topo1/rt3/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf index 7d411069d1..9223852f79 100644 --- a/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt4/isisd.conf @@ -1,11 +1,11 @@ hostname rt4 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_tilfa_topo1/rt4/zebra.conf b/tests/topotests/isis_tilfa_topo1/rt4/zebra.conf index 4945897e9d..a2569aa51f 100644 --- a/tests/topotests/isis_tilfa_topo1/rt4/zebra.conf +++ b/tests/topotests/isis_tilfa_topo1/rt4/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf index be52eb0322..a08534cf30 100644 --- a/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt5/isisd.conf @@ -1,11 +1,11 @@ hostname rt5 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_tilfa_topo1/rt5/zebra.conf b/tests/topotests/isis_tilfa_topo1/rt5/zebra.conf index 4cfea1a59f..f62cc8ffd3 100644 --- a/tests/topotests/isis_tilfa_topo1/rt5/zebra.conf +++ b/tests/topotests/isis_tilfa_topo1/rt5/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf b/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf index db47622a10..d92f822b8d 100644 --- a/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf +++ b/tests/topotests/isis_tilfa_topo1/rt6/isisd.conf @@ -1,11 +1,11 @@ hostname rt6 log file isisd.log ! -debug isis events -debug isis route-events -debug isis spf-events -debug isis sr-events -debug isis lsp-gen +! debug isis events +! debug isis route-events +! debug isis spf-events +! debug isis sr-events +! debug isis lsp-gen ! interface lo ip router isis 1 diff --git a/tests/topotests/isis_tilfa_topo1/rt6/zebra.conf b/tests/topotests/isis_tilfa_topo1/rt6/zebra.conf index 6084010a93..4d51d3df84 100644 --- a/tests/topotests/isis_tilfa_topo1/rt6/zebra.conf +++ b/tests/topotests/isis_tilfa_topo1/rt6/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt6 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 6.6.6.6/32 diff --git a/tests/topotests/isis_topo1/r1/isisd.conf b/tests/topotests/isis_topo1/r1/isisd.conf index 4e3761e5a1..9c1bfffdfb 100644 --- a/tests/topotests/isis_topo1/r1/isisd.conf +++ b/tests/topotests/isis_topo1/r1/isisd.conf @@ -1,7 +1,7 @@ hostname r1 -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets interface r1-eth0 ip router isis 1 isis hello-interval 2 diff --git a/tests/topotests/isis_topo1/r2/isisd.conf b/tests/topotests/isis_topo1/r2/isisd.conf index 14db0940ec..e8b578939b 100644 --- a/tests/topotests/isis_topo1/r2/isisd.conf +++ b/tests/topotests/isis_topo1/r2/isisd.conf @@ -1,7 +1,7 @@ hostname r2 -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets interface r2-eth0 ip router isis 1 isis hello-interval 2 diff --git a/tests/topotests/isis_topo1/r3/isisd.conf b/tests/topotests/isis_topo1/r3/isisd.conf index 6f36c0fa36..47bfc5359c 100644 --- a/tests/topotests/isis_topo1/r3/isisd.conf +++ b/tests/topotests/isis_topo1/r3/isisd.conf @@ -1,7 +1,7 @@ hostname r3 -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets interface r3-eth0 ip router isis 1 isis hello-interval 2 diff --git a/tests/topotests/isis_topo1/r4/isisd.conf b/tests/topotests/isis_topo1/r4/isisd.conf index 502e035f50..50c876db92 100644 --- a/tests/topotests/isis_topo1/r4/isisd.conf +++ b/tests/topotests/isis_topo1/r4/isisd.conf @@ -1,7 +1,7 @@ hostname r4 -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets interface r4-eth0 ip router isis 1 isis hello-interval 2 diff --git a/tests/topotests/isis_topo1/r5/isisd.conf b/tests/topotests/isis_topo1/r5/isisd.conf index 42493a4991..e0e9200d62 100644 --- a/tests/topotests/isis_topo1/r5/isisd.conf +++ b/tests/topotests/isis_topo1/r5/isisd.conf @@ -1,7 +1,7 @@ hostname r5 -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets interface r5-eth0 ip router isis 1 isis hello-interval 2 diff --git a/tests/topotests/isis_topo1/test_isis_topo1.py b/tests/topotests/isis_topo1/test_isis_topo1.py index df63de76de..94c5faf2e0 100644 --- a/tests/topotests/isis_topo1/test_isis_topo1.py +++ b/tests/topotests/isis_topo1/test_isis_topo1.py @@ -161,9 +161,16 @@ def test_isis_route_installation(): for rname, router in tgen.routers().items(): filename = "{0}/{1}/{1}_route.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) - actual = router.vtysh_cmd("show ip route json", isjson=True) + + def compare_isis_installed_routes(router, expected): + "Helper function to test ISIS routes installed in rib." + actual = router.vtysh_cmd("show ip route json", isjson=True) + 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) assertmsg = "Router '{}' routes mismatch".format(rname) - assert topotest.json_cmp(actual, expected) is None, assertmsg + assert result, assertmsg def test_isis_linux_route_installation(): @@ -197,9 +204,18 @@ def test_isis_route6_installation(): for rname, router in tgen.routers().items(): filename = "{0}/{1}/{1}_route6.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) - actual = router.vtysh_cmd("show ipv6 route json", isjson=True) + + def compare_isis_v6_installed_routes(router, expected): + "Helper function to test ISIS v6 routes installed in rib." + actual = router.vtysh_cmd("show ipv6 route json", isjson=True) + return topotest.json_cmp(actual, 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) assertmsg = "Router '{}' routes mismatch".format(rname) - assert topotest.json_cmp(actual, expected) is None, assertmsg + assert result, assertmsg def test_isis_linux_route6_installation(): diff --git a/tests/topotests/isis_topo1_vrf/r1/isisd.conf b/tests/topotests/isis_topo1_vrf/r1/isisd.conf index 5fb4c14d0b..0e8e490c94 100755 --- a/tests/topotests/isis_topo1_vrf/r1/isisd.conf +++ b/tests/topotests/isis_topo1_vrf/r1/isisd.conf @@ -1,7 +1,7 @@ hostname r1 -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets interface r1-eth0 ip router isis 1 vrf r1-cust1 ipv6 router isis 1 vrf r1-cust1 diff --git a/tests/topotests/isis_topo1_vrf/r2/isisd.conf b/tests/topotests/isis_topo1_vrf/r2/isisd.conf index 0d2bc7ab72..1e9bb9fb7f 100755 --- a/tests/topotests/isis_topo1_vrf/r2/isisd.conf +++ b/tests/topotests/isis_topo1_vrf/r2/isisd.conf @@ -1,7 +1,7 @@ hostname r2 -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets interface r2-eth0 ip router isis 1 vrf r2-cust1 ipv6 router isis 1 vrf r2-cust1 diff --git a/tests/topotests/isis_topo1_vrf/r3/isisd.conf b/tests/topotests/isis_topo1_vrf/r3/isisd.conf index 66092407ab..93a33f6db2 100755 --- a/tests/topotests/isis_topo1_vrf/r3/isisd.conf +++ b/tests/topotests/isis_topo1_vrf/r3/isisd.conf @@ -1,7 +1,7 @@ hostname r3 -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets interface r3-eth0 ip router isis 1 vrf r3-cust1 ipv6 router isis 1 vrf r3-cust1 diff --git a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json index 34892d4a3a..044a6c0438 100644 --- a/tests/topotests/isis_topo1_vrf/r3/r3_topology.json +++ b/tests/topotests/isis_topo1_vrf/r3/r3_topology.json @@ -94,16 +94,16 @@ { "interface": "r3-eth0", "metric": "10", - "next-hop": "r3", + "next-hop": "r1", "parent": "r3(4)", "type": "TE-IS", - "vertex": "r3" + "vertex": "r1" }, { "interface": "r3-eth0", "metric": "10", - "next-hop": "r3", - "parent": "r3(4)", + "next-hop": "r1", + "parent": "r1(4)", "type": "IP TE", "vertex": "10.0.20.0/24" } @@ -121,10 +121,10 @@ { "interface": "r3-eth0", "metric": "10", - "next-hop": "r3", + "next-hop": "r1", "parent": "r3(4)", "type": "TE-IS", - "vertex": "r3" + "vertex": "r1" } ] } diff --git a/tests/topotests/isis_topo1_vrf/r4/isisd.conf b/tests/topotests/isis_topo1_vrf/r4/isisd.conf index 05815e8418..b8c0b77f44 100755 --- a/tests/topotests/isis_topo1_vrf/r4/isisd.conf +++ b/tests/topotests/isis_topo1_vrf/r4/isisd.conf @@ -1,9 +1,9 @@ hostname r4 -debug isis adj-packets -debug isis events -debug isis update-packets -debug isis lsp-gen -debug isis lsp-sched +! debug isis adj-packets +! debug isis events +! debug isis update-packets +! debug isis lsp-gen +! debug isis lsp-sched interface r4-eth0 ip router isis 1 vrf r4-cust1 diff --git a/tests/topotests/isis_topo1_vrf/r5/isisd.conf b/tests/topotests/isis_topo1_vrf/r5/isisd.conf index f663c33fe9..e6febd5dea 100755 --- a/tests/topotests/isis_topo1_vrf/r5/isisd.conf +++ b/tests/topotests/isis_topo1_vrf/r5/isisd.conf @@ -1,7 +1,7 @@ hostname r5 -debug isis adj-packets -debug isis events -debug isis update-packets +! debug isis adj-packets +! debug isis events +! debug isis update-packets interface r5-eth0 ip router isis 1 vrf r5-cust1 ipv6 router isis 1 vrf r5-cust1 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 74d5edecab..ff9ad6150a 100644 --- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py @@ -105,15 +105,21 @@ def setup_module(mod): "ip link add {0}-cust1 type vrf table 1001", "ip link add loop1 type dummy", "ip link set {0}-eth0 master {0}-cust1", - "ip link set {0}-eth1 master {0}-cust1", ] + eth1_cmds = ["ip link set {0}-eth1 master {0}-cust1"] + # For all registered routers, load the zebra configuration file for rname, router in tgen.routers().items(): # create VRF rx-cust1 and link rx-eth0 to rx-cust1 for cmd in cmds: output = tgen.net[rname].cmd(cmd.format(rname)) + # If router has an rX-eth1, link that to vrf also + if "{}-eth1".format(rname) in router.links.keys(): + for cmd in eth1_cmds: + output = output + tgen.net[rname].cmd(cmd.format(rname)) + for rname, router in tgen.routers().items(): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) @@ -169,11 +175,19 @@ def test_isis_route_installation(): for rname, router in tgen.routers().items(): filename = "{0}/{1}/{1}_route.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) - actual = router.vtysh_cmd( - "show ip route vrf {0}-cust1 json".format(rname), isjson=True - ) - assertmsg = "Router '{}' routes mismatch".format(rname) - assert topotest.json_cmp(actual, expected) is None, assertmsg + + def compare_routing_table(router, expected): + "Helper function to ensure zebra rib convergence" + + actual = router.vtysh_cmd( + "show ip route vrf {0}-cust1 json".format(rname), isjson=True + ) + return topotest.json_cmp(actual, expected) + + test_func = functools.partial(compare_routing_table, router, expected) + (result, diff) = topotest.run_and_expect(test_func, None, count=20, wait=1) + assertmsg = "Router '{}' routes mismatch diff: {}".format(rname, diff) + assert result, assertmsg def test_isis_linux_route_installation(): @@ -214,12 +228,18 @@ def test_isis_route6_installation(): for rname, router in tgen.routers().items(): filename = "{0}/{1}/{1}_route6.json".format(CWD, rname) expected = json.loads(open(filename, "r").read()) - actual = router.vtysh_cmd( - "show ipv6 route vrf {}-cust1 json".format(rname), isjson=True - ) - assertmsg = "Router '{}' routes mismatch".format(rname) - assert topotest.json_cmp(actual, expected) is None, assertmsg + def compare_routing_table(router, expected): + "Helper function to ensure zebra rib convergence" + actual = router.vtysh_cmd( + "show ipv6 route vrf {}-cust1 json".format(rname), isjson=True + ) + return topotest.json_cmp(actual, expected) + + test_func = functools.partial(compare_routing_table, router, expected) + (result, diff) = topotest.run_and_expect(test_func, None, count=20, wait=1) + assertmsg = "Router '{}' routes mismatch diff: ".format(rname, diff) + assert result, assertmsg def test_isis_linux_route6_installation(): diff --git a/tests/topotests/ldp_oc_acl_topo1/r1/ldpd.conf b/tests/topotests/ldp_oc_acl_topo1/r1/ldpd.conf index 85bb970fdf..4d5fe38cf1 100644 --- a/tests/topotests/ldp_oc_acl_topo1/r1/ldpd.conf +++ b/tests/topotests/ldp_oc_acl_topo1/r1/ldpd.conf @@ -1,13 +1,13 @@ hostname r1 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/ldp_oc_acl_topo1/r1/show_ip_ospf_neighbor.json b/tests/topotests/ldp_oc_acl_topo1/r1/show_ip_ospf_neighbor.json index aa3f74fc5f..63281e9be3 100644 --- a/tests/topotests/ldp_oc_acl_topo1/r1/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_oc_acl_topo1/r1/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "2.2.2.2":[ { "priority":2, - "state":"Full\/DR", + "converged":"Full", "address":"10.0.1.2", "ifaceName":"r1-eth0:10.0.1.1" } diff --git a/tests/topotests/ldp_oc_acl_topo1/r2/ldpd.conf b/tests/topotests/ldp_oc_acl_topo1/r2/ldpd.conf index e1a552c701..175d3d0cee 100644 --- a/tests/topotests/ldp_oc_acl_topo1/r2/ldpd.conf +++ b/tests/topotests/ldp_oc_acl_topo1/r2/ldpd.conf @@ -1,13 +1,13 @@ hostname r2 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/ldp_oc_acl_topo1/r2/show_ip_ospf_neighbor.json b/tests/topotests/ldp_oc_acl_topo1/r2/show_ip_ospf_neighbor.json index aa68198957..f361d605ce 100644 --- a/tests/topotests/ldp_oc_acl_topo1/r2/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_oc_acl_topo1/r2/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "1.1.1.1":[ { "priority":1, - "state":"Full\/Backup", + "converged":"Full", "address":"10.0.1.1", "ifaceName":"r2-eth0:10.0.1.2" } @@ -11,7 +11,7 @@ "3.3.3.3":[ { "priority":2, - "state":"Full\/Backup", + "converged":"Full", "address":"10.0.2.3", "ifaceName":"r2-eth1:10.0.2.2" } @@ -19,7 +19,7 @@ "4.4.4.4":[ { "priority":3, - "state":"Full\/DR", + "converged":"Full", "address":"10.0.2.4", "ifaceName":"r2-eth1:10.0.2.2" } diff --git a/tests/topotests/ldp_oc_acl_topo1/r3/ldpd.conf b/tests/topotests/ldp_oc_acl_topo1/r3/ldpd.conf index 4e66b140ac..81bd25ac6b 100644 --- a/tests/topotests/ldp_oc_acl_topo1/r3/ldpd.conf +++ b/tests/topotests/ldp_oc_acl_topo1/r3/ldpd.conf @@ -1,13 +1,13 @@ hostname r3 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/ldp_oc_acl_topo1/r3/show_ip_ospf_neighbor.json b/tests/topotests/ldp_oc_acl_topo1/r3/show_ip_ospf_neighbor.json index 905774fc46..38794357ff 100644 --- a/tests/topotests/ldp_oc_acl_topo1/r3/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_oc_acl_topo1/r3/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "2.2.2.2":[ { "priority":1, - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.2.2", "ifaceName":"r3-eth0:10.0.2.3" } @@ -11,7 +11,7 @@ "4.4.4.4":[ { "priority":3, - "state":"Full\/DR", + "converged":"Full", "address":"10.0.2.4", "ifaceName":"r3-eth0:10.0.2.3" } diff --git a/tests/topotests/ldp_oc_acl_topo1/r4/ldpd.conf b/tests/topotests/ldp_oc_acl_topo1/r4/ldpd.conf index 6b7d28f983..9f66d7ba45 100644 --- a/tests/topotests/ldp_oc_acl_topo1/r4/ldpd.conf +++ b/tests/topotests/ldp_oc_acl_topo1/r4/ldpd.conf @@ -1,13 +1,13 @@ hostname r4 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 4.4.4.4 diff --git a/tests/topotests/ldp_oc_acl_topo1/r4/show_ip_ospf_neighbor.json b/tests/topotests/ldp_oc_acl_topo1/r4/show_ip_ospf_neighbor.json index 67593952ca..fccca693b9 100644 --- a/tests/topotests/ldp_oc_acl_topo1/r4/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_oc_acl_topo1/r4/show_ip_ospf_neighbor.json @@ -4,7 +4,7 @@ "2.2.2.2":[ { "priority":1, - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.2.2", "ifaceName":"r4-eth0:10.0.2.4" } @@ -12,7 +12,7 @@ "3.3.3.3":[ { "priority":2, - "state":"Full\/Backup", + "converged":"Full", "address":"10.0.2.3", "ifaceName":"r4-eth0:10.0.2.4" } diff --git a/tests/topotests/ldp_oc_topo1/r1/ldpd.conf b/tests/topotests/ldp_oc_topo1/r1/ldpd.conf index 2a8e023832..fdb9e628b3 100644 --- a/tests/topotests/ldp_oc_topo1/r1/ldpd.conf +++ b/tests/topotests/ldp_oc_topo1/r1/ldpd.conf @@ -1,13 +1,13 @@ hostname r1 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/ldp_oc_topo1/r1/show_ip_ospf_neighbor.json b/tests/topotests/ldp_oc_topo1/r1/show_ip_ospf_neighbor.json index aa3f74fc5f..63281e9be3 100644 --- a/tests/topotests/ldp_oc_topo1/r1/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_oc_topo1/r1/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "2.2.2.2":[ { "priority":2, - "state":"Full\/DR", + "converged":"Full", "address":"10.0.1.2", "ifaceName":"r1-eth0:10.0.1.1" } diff --git a/tests/topotests/ldp_oc_topo1/r2/ldpd.conf b/tests/topotests/ldp_oc_topo1/r2/ldpd.conf index e1a552c701..175d3d0cee 100644 --- a/tests/topotests/ldp_oc_topo1/r2/ldpd.conf +++ b/tests/topotests/ldp_oc_topo1/r2/ldpd.conf @@ -1,13 +1,13 @@ hostname r2 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/ldp_oc_topo1/r2/show_ip_ospf_neighbor.json b/tests/topotests/ldp_oc_topo1/r2/show_ip_ospf_neighbor.json index aa68198957..f361d605ce 100644 --- a/tests/topotests/ldp_oc_topo1/r2/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_oc_topo1/r2/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "1.1.1.1":[ { "priority":1, - "state":"Full\/Backup", + "converged":"Full", "address":"10.0.1.1", "ifaceName":"r2-eth0:10.0.1.2" } @@ -11,7 +11,7 @@ "3.3.3.3":[ { "priority":2, - "state":"Full\/Backup", + "converged":"Full", "address":"10.0.2.3", "ifaceName":"r2-eth1:10.0.2.2" } @@ -19,7 +19,7 @@ "4.4.4.4":[ { "priority":3, - "state":"Full\/DR", + "converged":"Full", "address":"10.0.2.4", "ifaceName":"r2-eth1:10.0.2.2" } diff --git a/tests/topotests/ldp_oc_topo1/r3/ldpd.conf b/tests/topotests/ldp_oc_topo1/r3/ldpd.conf index 4e66b140ac..81bd25ac6b 100644 --- a/tests/topotests/ldp_oc_topo1/r3/ldpd.conf +++ b/tests/topotests/ldp_oc_topo1/r3/ldpd.conf @@ -1,13 +1,13 @@ hostname r3 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/ldp_oc_topo1/r3/show_ip_ospf_neighbor.json b/tests/topotests/ldp_oc_topo1/r3/show_ip_ospf_neighbor.json index 905774fc46..38794357ff 100644 --- a/tests/topotests/ldp_oc_topo1/r3/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_oc_topo1/r3/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "2.2.2.2":[ { "priority":1, - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.2.2", "ifaceName":"r3-eth0:10.0.2.3" } @@ -11,7 +11,7 @@ "4.4.4.4":[ { "priority":3, - "state":"Full\/DR", + "converged":"Full", "address":"10.0.2.4", "ifaceName":"r3-eth0:10.0.2.3" } diff --git a/tests/topotests/ldp_oc_topo1/r4/ldpd.conf b/tests/topotests/ldp_oc_topo1/r4/ldpd.conf index 6b7d28f983..9f66d7ba45 100644 --- a/tests/topotests/ldp_oc_topo1/r4/ldpd.conf +++ b/tests/topotests/ldp_oc_topo1/r4/ldpd.conf @@ -1,13 +1,13 @@ hostname r4 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 4.4.4.4 diff --git a/tests/topotests/ldp_oc_topo1/r4/show_ip_ospf_neighbor.json b/tests/topotests/ldp_oc_topo1/r4/show_ip_ospf_neighbor.json index 67593952ca..fccca693b9 100644 --- a/tests/topotests/ldp_oc_topo1/r4/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_oc_topo1/r4/show_ip_ospf_neighbor.json @@ -4,7 +4,7 @@ "2.2.2.2":[ { "priority":1, - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.2.2", "ifaceName":"r4-eth0:10.0.2.4" } @@ -12,7 +12,7 @@ "3.3.3.3":[ { "priority":2, - "state":"Full\/Backup", + "converged":"Full", "address":"10.0.2.3", "ifaceName":"r4-eth0:10.0.2.4" } diff --git a/tests/topotests/ldp_snmp/r1/isisd.conf b/tests/topotests/ldp_snmp/r1/isisd.conf index da2970d94e..d1abb497a6 100644 --- a/tests/topotests/ldp_snmp/r1/isisd.conf +++ b/tests/topotests/ldp_snmp/r1/isisd.conf @@ -1,9 +1,9 @@ hostname r1 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets -debug isis ldp-sync +! debug isis adj-packets +! debug isis events +! debug isis update-packets +! debug isis ldp-sync ! router isis 1 lsp-gen-interval 2 diff --git a/tests/topotests/ldp_snmp/r1/ldpd.conf b/tests/topotests/ldp_snmp/r1/ldpd.conf index 01fc039b09..c13135ff90 100644 --- a/tests/topotests/ldp_snmp/r1/ldpd.conf +++ b/tests/topotests/ldp_snmp/r1/ldpd.conf @@ -1,10 +1,10 @@ hostname r1 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/ldp_snmp/r1/zebra.conf b/tests/topotests/ldp_snmp/r1/zebra.conf index ea047355ad..bbb98d22fa 100644 --- a/tests/topotests/ldp_snmp/r1/zebra.conf +++ b/tests/topotests/ldp_snmp/r1/zebra.conf @@ -2,12 +2,12 @@ log file zebra.log ! hostname r1 ! -debug zebra kernel -debug zebra rib detailed -debug zebra dplane detailed -debug zebra nht -debug zebra pseudowires -debug zebra mpls +! debug zebra kernel +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra nht +! debug zebra pseudowires +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ldp_snmp/r2/isisd.conf b/tests/topotests/ldp_snmp/r2/isisd.conf index b29a2b93ee..213b65ee4c 100644 --- a/tests/topotests/ldp_snmp/r2/isisd.conf +++ b/tests/topotests/ldp_snmp/r2/isisd.conf @@ -1,9 +1,9 @@ hostname r2 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets -debug isis ldp-sync +! debug isis adj-packets +! debug isis events +! debug isis update-packets +! debug isis ldp-sync ! router isis 1 lsp-gen-interval 2 diff --git a/tests/topotests/ldp_snmp/r2/ldpd.conf b/tests/topotests/ldp_snmp/r2/ldpd.conf index c93e1a6ac5..fdb76ed3c0 100644 --- a/tests/topotests/ldp_snmp/r2/ldpd.conf +++ b/tests/topotests/ldp_snmp/r2/ldpd.conf @@ -1,10 +1,10 @@ hostname r2 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/ldp_snmp/r2/ospfd.conf b/tests/topotests/ldp_snmp/r2/ospfd.conf index f93f6aed56..50c593cb58 100644 --- a/tests/topotests/ldp_snmp/r2/ospfd.conf +++ b/tests/topotests/ldp_snmp/r2/ospfd.conf @@ -1,7 +1,7 @@ hostname r2 log file ospfd.log -debug ospf zebra interface -debug ospf ldp-sync +! debug ospf zebra interface +! debug ospf ldp-sync ! router ospf router-id 2.2.2.2 diff --git a/tests/topotests/ldp_snmp/r2/zebra.conf b/tests/topotests/ldp_snmp/r2/zebra.conf index c244442876..c79b210f11 100644 --- a/tests/topotests/ldp_snmp/r2/zebra.conf +++ b/tests/topotests/ldp_snmp/r2/zebra.conf @@ -2,11 +2,11 @@ log file zebra.log ! hostname r2 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht -debug zebra pseudowires +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht +! debug zebra pseudowires ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/ldp_snmp/r3/isisd.conf b/tests/topotests/ldp_snmp/r3/isisd.conf index 4c8499f23d..956d58239b 100644 --- a/tests/topotests/ldp_snmp/r3/isisd.conf +++ b/tests/topotests/ldp_snmp/r3/isisd.conf @@ -1,9 +1,9 @@ hostname r3 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets -debug isis ldp-sync +! debug isis adj-packets +! debug isis events +! debug isis update-packets +! debug isis ldp-sync ! router isis 1 lsp-gen-interval 2 diff --git a/tests/topotests/ldp_snmp/r3/ldpd.conf b/tests/topotests/ldp_snmp/r3/ldpd.conf index b7eeb258f1..d1a928bf45 100644 --- a/tests/topotests/ldp_snmp/r3/ldpd.conf +++ b/tests/topotests/ldp_snmp/r3/ldpd.conf @@ -1,10 +1,10 @@ hostname r3 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/ldp_snmp/r3/zebra.conf b/tests/topotests/ldp_snmp/r3/zebra.conf index b1919bd296..45929acb21 100644 --- a/tests/topotests/ldp_snmp/r3/zebra.conf +++ b/tests/topotests/ldp_snmp/r3/zebra.conf @@ -2,11 +2,11 @@ log file zebra.log ! hostname r3 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht -debug zebra pseudowires +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht +! debug zebra pseudowires ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/ldp_sync_isis_topo1/r1/isisd.conf b/tests/topotests/ldp_sync_isis_topo1/r1/isisd.conf index da2970d94e..d1abb497a6 100644 --- a/tests/topotests/ldp_sync_isis_topo1/r1/isisd.conf +++ b/tests/topotests/ldp_sync_isis_topo1/r1/isisd.conf @@ -1,9 +1,9 @@ hostname r1 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets -debug isis ldp-sync +! debug isis adj-packets +! debug isis events +! debug isis update-packets +! debug isis ldp-sync ! router isis 1 lsp-gen-interval 2 diff --git a/tests/topotests/ldp_sync_isis_topo1/r1/ldpd.conf b/tests/topotests/ldp_sync_isis_topo1/r1/ldpd.conf index b9c32d3000..973acf4356 100644 --- a/tests/topotests/ldp_sync_isis_topo1/r1/ldpd.conf +++ b/tests/topotests/ldp_sync_isis_topo1/r1/ldpd.conf @@ -1,10 +1,10 @@ hostname r1 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/ldp_sync_isis_topo1/r1/zebra.conf b/tests/topotests/ldp_sync_isis_topo1/r1/zebra.conf index ea047355ad..bbb98d22fa 100644 --- a/tests/topotests/ldp_sync_isis_topo1/r1/zebra.conf +++ b/tests/topotests/ldp_sync_isis_topo1/r1/zebra.conf @@ -2,12 +2,12 @@ log file zebra.log ! hostname r1 ! -debug zebra kernel -debug zebra rib detailed -debug zebra dplane detailed -debug zebra nht -debug zebra pseudowires -debug zebra mpls +! debug zebra kernel +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra nht +! debug zebra pseudowires +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ldp_sync_isis_topo1/r2/isisd.conf b/tests/topotests/ldp_sync_isis_topo1/r2/isisd.conf index b29a2b93ee..213b65ee4c 100644 --- a/tests/topotests/ldp_sync_isis_topo1/r2/isisd.conf +++ b/tests/topotests/ldp_sync_isis_topo1/r2/isisd.conf @@ -1,9 +1,9 @@ hostname r2 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets -debug isis ldp-sync +! debug isis adj-packets +! debug isis events +! debug isis update-packets +! debug isis ldp-sync ! router isis 1 lsp-gen-interval 2 diff --git a/tests/topotests/ldp_sync_isis_topo1/r2/ldpd.conf b/tests/topotests/ldp_sync_isis_topo1/r2/ldpd.conf index 52398b1b72..e738ff9917 100644 --- a/tests/topotests/ldp_sync_isis_topo1/r2/ldpd.conf +++ b/tests/topotests/ldp_sync_isis_topo1/r2/ldpd.conf @@ -1,10 +1,10 @@ hostname r2 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/ldp_sync_isis_topo1/r2/zebra.conf b/tests/topotests/ldp_sync_isis_topo1/r2/zebra.conf index c244442876..c79b210f11 100644 --- a/tests/topotests/ldp_sync_isis_topo1/r2/zebra.conf +++ b/tests/topotests/ldp_sync_isis_topo1/r2/zebra.conf @@ -2,11 +2,11 @@ log file zebra.log ! hostname r2 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht -debug zebra pseudowires +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht +! debug zebra pseudowires ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/ldp_sync_isis_topo1/r3/isisd.conf b/tests/topotests/ldp_sync_isis_topo1/r3/isisd.conf index 4c8499f23d..956d58239b 100644 --- a/tests/topotests/ldp_sync_isis_topo1/r3/isisd.conf +++ b/tests/topotests/ldp_sync_isis_topo1/r3/isisd.conf @@ -1,9 +1,9 @@ hostname r3 log file isisd.log -debug isis adj-packets -debug isis events -debug isis update-packets -debug isis ldp-sync +! debug isis adj-packets +! debug isis events +! debug isis update-packets +! debug isis ldp-sync ! router isis 1 lsp-gen-interval 2 diff --git a/tests/topotests/ldp_sync_isis_topo1/r3/ldpd.conf b/tests/topotests/ldp_sync_isis_topo1/r3/ldpd.conf index 2935caf13b..fae25e0710 100644 --- a/tests/topotests/ldp_sync_isis_topo1/r3/ldpd.conf +++ b/tests/topotests/ldp_sync_isis_topo1/r3/ldpd.conf @@ -1,10 +1,10 @@ hostname r3 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/ldp_sync_isis_topo1/r3/zebra.conf b/tests/topotests/ldp_sync_isis_topo1/r3/zebra.conf index b1919bd296..45929acb21 100644 --- a/tests/topotests/ldp_sync_isis_topo1/r3/zebra.conf +++ b/tests/topotests/ldp_sync_isis_topo1/r3/zebra.conf @@ -2,11 +2,11 @@ log file zebra.log ! hostname r3 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht -debug zebra pseudowires +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht +! debug zebra pseudowires ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r1/ldpd.conf b/tests/topotests/ldp_sync_ospf_topo1/r1/ldpd.conf index b9c32d3000..973acf4356 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r1/ldpd.conf +++ b/tests/topotests/ldp_sync_ospf_topo1/r1/ldpd.conf @@ -1,10 +1,10 @@ hostname r1 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r1/ospfd.conf b/tests/topotests/ldp_sync_ospf_topo1/r1/ospfd.conf index eefcd1e71c..dc201695f4 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r1/ospfd.conf +++ b/tests/topotests/ldp_sync_ospf_topo1/r1/ospfd.conf @@ -1,7 +1,7 @@ hostname r1 log file ospfd.log -debug ospf zebra interface -debug ospf ldp-sync +! debug ospf zebra interface +! debug ospf ldp-sync ! router ospf router-id 1.1.1.1 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r1/show_ip_ospf_neighbor.json b/tests/topotests/ldp_sync_ospf_topo1/r1/show_ip_ospf_neighbor.json index 3bfda39071..7efde22f3f 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r1/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_sync_ospf_topo1/r1/show_ip_ospf_neighbor.json @@ -5,7 +5,7 @@ "dbSummaryCounter": 0, "retransmitCounter": 0, "priority": 1, - "state": "Full/DROther", + "converged": "Full", "address": "10.0.1.2", "ifaceName": "r1-eth1:10.0.1.1", "requestCounter": 0 @@ -16,7 +16,7 @@ "dbSummaryCounter": 0, "retransmitCounter": 0, "priority": 1, - "state": "Full/DROther", + "converged": "Full", "address": "10.0.2.3", "ifaceName": "r1-eth2:10.0.2.1", "requestCounter": 0 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r1/zebra.conf b/tests/topotests/ldp_sync_ospf_topo1/r1/zebra.conf index ea047355ad..bbb98d22fa 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r1/zebra.conf +++ b/tests/topotests/ldp_sync_ospf_topo1/r1/zebra.conf @@ -2,12 +2,12 @@ log file zebra.log ! hostname r1 ! -debug zebra kernel -debug zebra rib detailed -debug zebra dplane detailed -debug zebra nht -debug zebra pseudowires -debug zebra mpls +! debug zebra kernel +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra nht +! debug zebra pseudowires +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/ldpd.conf b/tests/topotests/ldp_sync_ospf_topo1/r2/ldpd.conf index 52398b1b72..e738ff9917 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/ldpd.conf +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/ldpd.conf @@ -1,10 +1,10 @@ hostname r2 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/ospfd.conf b/tests/topotests/ldp_sync_ospf_topo1/r2/ospfd.conf index f93f6aed56..50c593cb58 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/ospfd.conf +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/ospfd.conf @@ -1,7 +1,7 @@ hostname r2 log file ospfd.log -debug ospf zebra interface -debug ospf ldp-sync +! debug ospf zebra interface +! debug ospf ldp-sync ! router ospf router-id 2.2.2.2 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ip_ospf_neighbor.json b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ip_ospf_neighbor.json index 5b7a5ebbb9..5bea193e01 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "1.1.1.1": [ { "priority":1, - "state":"Full/DROther", + "converged":"Full", "address":"10.0.1.1", "ifaceName":"r2-eth1:10.0.1.2", "retransmitCounter":0, @@ -14,7 +14,7 @@ "3.3.3.3": [ { "priority":1, - "state":"Full/DROther", + "converged":"Full", "address":"10.0.3.3", "ifaceName":"r2-eth2:10.0.3.2", "retransmitCounter":0, diff --git a/tests/topotests/ldp_sync_ospf_topo1/r2/zebra.conf b/tests/topotests/ldp_sync_ospf_topo1/r2/zebra.conf index c244442876..c79b210f11 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r2/zebra.conf +++ b/tests/topotests/ldp_sync_ospf_topo1/r2/zebra.conf @@ -2,11 +2,11 @@ log file zebra.log ! hostname r2 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht -debug zebra pseudowires +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht +! debug zebra pseudowires ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/ldpd.conf b/tests/topotests/ldp_sync_ospf_topo1/r3/ldpd.conf index 2935caf13b..fae25e0710 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/ldpd.conf +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/ldpd.conf @@ -1,10 +1,10 @@ hostname r3 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp sync +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp sync ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/ospfd.conf b/tests/topotests/ldp_sync_ospf_topo1/r3/ospfd.conf index 09eea759ad..b641fd8713 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/ospfd.conf +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/ospfd.conf @@ -1,7 +1,7 @@ hostname r3 log file ospfd.log -debug ospf zebra interface -debug ospf ldp-sync +! debug ospf zebra interface +! debug ospf ldp-sync ! router ospf router-id 3.3.3.3 diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ip_ospf_neighbor.json b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ip_ospf_neighbor.json index 1b29b9f947..9966297d8a 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "1.1.1.1": [ { "priority":1, - "state":"Full/DROther", + "converged":"Full", "address":"10.0.2.1", "ifaceName":"r3-eth1:10.0.2.3", "retransmitCounter":0, @@ -14,7 +14,7 @@ "2.2.2.2": [ { "priority":1, - "state":"Full/DROther", + "converged":"Full", "address":"10.0.3.2", "ifaceName":"r3-eth2:10.0.3.3", "retransmitCounter":0, diff --git a/tests/topotests/ldp_sync_ospf_topo1/r3/zebra.conf b/tests/topotests/ldp_sync_ospf_topo1/r3/zebra.conf index b1919bd296..45929acb21 100644 --- a/tests/topotests/ldp_sync_ospf_topo1/r3/zebra.conf +++ b/tests/topotests/ldp_sync_ospf_topo1/r3/zebra.conf @@ -2,11 +2,11 @@ log file zebra.log ! hostname r3 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht -debug zebra pseudowires +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht +! debug zebra pseudowires ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/ldp_topo1/r1/ldpd.conf b/tests/topotests/ldp_topo1/r1/ldpd.conf index 3c6cbddc2a..f7f2714dae 100644 --- a/tests/topotests/ldp_topo1/r1/ldpd.conf +++ b/tests/topotests/ldp_topo1/r1/ldpd.conf @@ -1,13 +1,13 @@ hostname r1 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/ldp_topo1/r2/ldpd.conf b/tests/topotests/ldp_topo1/r2/ldpd.conf index bfdef21b75..c4056e01a8 100644 --- a/tests/topotests/ldp_topo1/r2/ldpd.conf +++ b/tests/topotests/ldp_topo1/r2/ldpd.conf @@ -1,13 +1,13 @@ hostname r2 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/ldp_topo1/r3/ldpd.conf b/tests/topotests/ldp_topo1/r3/ldpd.conf index dbf1d72b5f..48956cb996 100644 --- a/tests/topotests/ldp_topo1/r3/ldpd.conf +++ b/tests/topotests/ldp_topo1/r3/ldpd.conf @@ -1,13 +1,13 @@ hostname r3 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/ldp_topo1/r4/ldpd.conf b/tests/topotests/ldp_topo1/r4/ldpd.conf index 8f3533527d..1d04aa07e7 100644 --- a/tests/topotests/ldp_topo1/r4/ldpd.conf +++ b/tests/topotests/ldp_topo1/r4/ldpd.conf @@ -1,13 +1,13 @@ hostname r4 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 4.4.4.4 diff --git a/tests/topotests/ldp_topo1/test_ldp_topo1.py b/tests/topotests/ldp_topo1/test_ldp_topo1.py index c21d6bf28e..4a33edb9d1 100644 --- a/tests/topotests/ldp_topo1/test_ldp_topo1.py +++ b/tests/topotests/ldp_topo1/test_ldp_topo1.py @@ -64,6 +64,7 @@ import re import sys import pytest from time import sleep +from lib.topolog import logger sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from lib import topotest @@ -126,7 +127,7 @@ def setup_module(module): tgen.gears["r%s" % i].start() # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) + # tgen.mininet_cli() def teardown_module(module): @@ -153,9 +154,6 @@ def test_router_running(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_mpls_interfaces(): global fatal_error @@ -219,9 +217,6 @@ def test_mpls_interfaces(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_mpls_ldp_neighbor_establish(): global fatal_error @@ -231,6 +226,13 @@ def test_mpls_ldp_neighbor_establish(): if fatal_error != "": pytest.skip(fatal_error) + neighbors_operational = { + 1: 1, + 2: 3, + 3: 2, + 4: 2, + } + # Wait for MPLS LDP neighbors to establish. print("\n\n** Verify MPLS LDP neighbors to establish") print("******************************************\n") @@ -260,9 +262,14 @@ def test_mpls_ldp_neighbor_establish(): established = "" # Empty string shows NOT established if re.search(operational, lines[j]): found_operational += 1 + + logger.info("Found operational %d" % found_operational) if found_operational < 1: # Need at least one operational neighbor established = "" # Empty string shows NOT established + else: + if found_operational != neighbors_operational[i]: + established = "" if not established: print("Waiting for r%s" % i) sys.stdout.flush() @@ -356,9 +363,6 @@ def test_mpls_ldp_discovery(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_mpls_ldp_neighbor(): global fatal_error @@ -426,9 +430,6 @@ def test_mpls_ldp_neighbor(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_mpls_ldp_binding(): global fatal_error @@ -518,9 +519,6 @@ def test_mpls_ldp_binding(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_zebra_ipv4_routingTable(): global fatal_error @@ -595,9 +593,6 @@ def test_zebra_ipv4_routingTable(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_mpls_table(): global fatal_error @@ -674,9 +669,6 @@ def test_mpls_table(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_linux_mpls_routes(): global fatal_error @@ -758,9 +750,6 @@ def test_linux_mpls_routes(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_shutdown_check_stderr(): global fatal_error diff --git a/tests/topotests/ldp_vpls_topo1/r1/ldpd.conf b/tests/topotests/ldp_vpls_topo1/r1/ldpd.conf index a1c0c822d6..594ec5a58f 100644 --- a/tests/topotests/ldp_vpls_topo1/r1/ldpd.conf +++ b/tests/topotests/ldp_vpls_topo1/r1/ldpd.conf @@ -1,13 +1,13 @@ hostname r1 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 1.1.1.1 diff --git a/tests/topotests/ldp_vpls_topo1/r1/show_ip_ospf_neighbor.json b/tests/topotests/ldp_vpls_topo1/r1/show_ip_ospf_neighbor.json index 7e281abb5f..90c8195416 100644 --- a/tests/topotests/ldp_vpls_topo1/r1/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_vpls_topo1/r1/show_ip_ospf_neighbor.json @@ -5,7 +5,7 @@ "dbSummaryCounter": 0, "retransmitCounter": 0, "priority": 2, - "state": "Full\/DR", + "converged": "Full", "address": "10.0.1.2", "ifaceName": "r1-eth1:10.0.1.1", "requestCounter": 0 @@ -16,7 +16,7 @@ "dbSummaryCounter": 0, "retransmitCounter": 0, "priority": 2, - "state": "Full\/DR", + "converged": "Full", "address": "10.0.2.3", "ifaceName": "r1-eth2:10.0.2.1", "requestCounter": 0 diff --git a/tests/topotests/ldp_vpls_topo1/r1/show_ip_route_after_link_down.ref b/tests/topotests/ldp_vpls_topo1/r1/show_ip_route_after_link_down.ref new file mode 100644 index 0000000000..84113a0383 --- /dev/null +++ b/tests/topotests/ldp_vpls_topo1/r1/show_ip_route_after_link_down.ref @@ -0,0 +1,20 @@ +{ + "2.2.2.2/32":[ + { + "prefix":"2.2.2.2/32", + "protocol":"ospf", + "selected":true, + "distance":110, + "metric":20, + "nexthops":[ + { + "fib":true, + "ip":"10.0.2.3", + "afi":"ipv4", + "interfaceName":"r1-eth2", + "active":true + } + ] + } + ] +} diff --git a/tests/topotests/ldp_vpls_topo1/r1/zebra.conf b/tests/topotests/ldp_vpls_topo1/r1/zebra.conf index ea047355ad..bbb98d22fa 100644 --- a/tests/topotests/ldp_vpls_topo1/r1/zebra.conf +++ b/tests/topotests/ldp_vpls_topo1/r1/zebra.conf @@ -2,12 +2,12 @@ log file zebra.log ! hostname r1 ! -debug zebra kernel -debug zebra rib detailed -debug zebra dplane detailed -debug zebra nht -debug zebra pseudowires -debug zebra mpls +! debug zebra kernel +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra nht +! debug zebra pseudowires +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ldp_vpls_topo1/r2/ldpd.conf b/tests/topotests/ldp_vpls_topo1/r2/ldpd.conf index 06e5973040..ffb4f0974a 100644 --- a/tests/topotests/ldp_vpls_topo1/r2/ldpd.conf +++ b/tests/topotests/ldp_vpls_topo1/r2/ldpd.conf @@ -1,13 +1,13 @@ hostname r2 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 2.2.2.2 diff --git a/tests/topotests/ldp_vpls_topo1/r2/show_ip_ospf_neighbor.json b/tests/topotests/ldp_vpls_topo1/r2/show_ip_ospf_neighbor.json index 22fd98f519..29dde53c6d 100644 --- a/tests/topotests/ldp_vpls_topo1/r2/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_vpls_topo1/r2/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "1.1.1.1": [ { "priority":1, - "state":"Full\/Backup", + "converged":"Full", "address":"10.0.1.1", "ifaceName":"r2-eth1:10.0.1.2", "retransmitCounter":0, @@ -14,7 +14,7 @@ "3.3.3.3": [ { "priority":2, - "state":"Full\/DR", + "converged":"Full", "address":"10.0.3.3", "ifaceName":"r2-eth2:10.0.3.2", "retransmitCounter":0, diff --git a/tests/topotests/ldp_vpls_topo1/r2/zebra.conf b/tests/topotests/ldp_vpls_topo1/r2/zebra.conf index c244442876..c79b210f11 100644 --- a/tests/topotests/ldp_vpls_topo1/r2/zebra.conf +++ b/tests/topotests/ldp_vpls_topo1/r2/zebra.conf @@ -2,11 +2,11 @@ log file zebra.log ! hostname r2 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht -debug zebra pseudowires +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht +! debug zebra pseudowires ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/ldp_vpls_topo1/r3/ldpd.conf b/tests/topotests/ldp_vpls_topo1/r3/ldpd.conf index 57a203bce3..c95471ffd8 100644 --- a/tests/topotests/ldp_vpls_topo1/r3/ldpd.conf +++ b/tests/topotests/ldp_vpls_topo1/r3/ldpd.conf @@ -1,13 +1,13 @@ hostname r3 log file ldpd.log ! -debug mpls ldp zebra -debug mpls ldp event -debug mpls ldp errors -debug mpls ldp messages recv -debug mpls ldp messages sent -debug mpls ldp discovery hello recv -debug mpls ldp discovery hello sent +! debug mpls ldp zebra +! debug mpls ldp event +! debug mpls ldp errors +! debug mpls ldp messages recv +! debug mpls ldp messages sent +! debug mpls ldp discovery hello recv +! debug mpls ldp discovery hello sent ! mpls ldp router-id 3.3.3.3 diff --git a/tests/topotests/ldp_vpls_topo1/r3/show_ip_ospf_neighbor.json b/tests/topotests/ldp_vpls_topo1/r3/show_ip_ospf_neighbor.json index 970eb2fc1d..9966297d8a 100644 --- a/tests/topotests/ldp_vpls_topo1/r3/show_ip_ospf_neighbor.json +++ b/tests/topotests/ldp_vpls_topo1/r3/show_ip_ospf_neighbor.json @@ -3,7 +3,7 @@ "1.1.1.1": [ { "priority":1, - "state":"Full\/Backup", + "converged":"Full", "address":"10.0.2.1", "ifaceName":"r3-eth1:10.0.2.3", "retransmitCounter":0, @@ -14,7 +14,7 @@ "2.2.2.2": [ { "priority":1, - "state":"Full\/Backup", + "converged":"Full", "address":"10.0.3.2", "ifaceName":"r3-eth2:10.0.3.3", "retransmitCounter":0, diff --git a/tests/topotests/ldp_vpls_topo1/r3/zebra.conf b/tests/topotests/ldp_vpls_topo1/r3/zebra.conf index 6b1eaa2ca0..bcc0d8d2be 100644 --- a/tests/topotests/ldp_vpls_topo1/r3/zebra.conf +++ b/tests/topotests/ldp_vpls_topo1/r3/zebra.conf @@ -2,11 +2,11 @@ log file zebra.log ! hostname r3 ! -debug zebra rib detailed -debug zebra dplane detailed -debug zebra kernel -debug zebra nht -debug zebra pseudowires +! debug zebra rib detailed +! debug zebra dplane detailed +! debug zebra kernel +! debug zebra nht +! debug zebra pseudowires ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py index 86128a629d..8a41ea510e 100644 --- a/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py +++ b/tests/topotests/ldp_vpls_topo1/test_ldp_vpls_topo1.py @@ -272,9 +272,15 @@ def test_ldp_pseudowires_after_link_down(): # Shut down r1-r2 link */ tgen = get_topogen() - tgen.gears["r1"].peer_link_enable("r1-eth1", False) - topotest.sleep(5, "Waiting for the network to reconverge") - + rname = "r1" + tgen.gears[rname].peer_link_enable("r1-eth1", False) + router_compare_json_output( + rname, + "show ip route json", + "show_ip_route_after_link_down.ref", + count=160, + wait=1, + ) # check if the pseudowire is still up (using an alternate path # for nexthop resolution). Give some extra wait time. for rname in ["r1", "r2", "r3"]: diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index 556240bfb5..551483d718 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -989,6 +989,14 @@ def __create_bgp_unicast_address_family( if "no_allowas_in" in peer: allow_as_in = peer["no_allowas_in"] config_data.append("no {} allowas-in {}".format(neigh_cxt, allow_as_in)) + + if "shutdown" in peer: + shut_val = peer["shutdown"] + if shut_val is True: + config_data.append("{} shutdown".format(neigh_cxt)) + elif shut_val is False: + config_data.append("no {} shutdown".format(neigh_cxt)) + if prefix_lists: for prefix_list in prefix_lists: name = prefix_list.setdefault("name", {}) @@ -2221,6 +2229,7 @@ def verify_bgp_attributes( rmap_name=None, input_dict=None, seq_id=None, + vrf=None, nexthop=None, expected=True, ): @@ -2275,7 +2284,10 @@ def verify_bgp_attributes( logger.info("Verifying BGP set attributes for dut {}:".format(router)) for static_route in static_routes: - cmd = "show bgp {} {} json".format(addr_type, static_route) + if vrf: + cmd = "show bgp vrf {} {} {} json".format(vrf, addr_type, static_route) + else: + cmd = "show bgp {} {} json".format(addr_type, static_route) show_bgp_json = run_frr_cmd(rnode, cmd, isjson=True) dict_to_test = [] @@ -2821,7 +2833,6 @@ def verify_bgp_rib( st_rt, dut, ) - return errormsg else: nh_found = True @@ -3050,7 +3061,12 @@ def verify_graceful_restart( if router != dut: continue - bgp_addr_type = topo["routers"][dut]["bgp"]["address_family"] + try: + bgp_addr_type = topo["routers"][dut]["bgp"]["address_family"] + except TypeError: + bgp_addr_type = topo["routers"][dut]["bgp"][0]["address_family"] + + # bgp_addr_type = topo["routers"][dut]["bgp"]["address_family"] if addr_type in bgp_addr_type: if not check_address_types(addr_type): @@ -4428,3 +4444,133 @@ def verify_evpn_routes( logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return False + + +@retry(retry_timeout=10) +def verify_bgp_bestpath(tgen, addr_type, input_dict): + """ + Verifies bgp next hop values in best-path output + + * `dut` : device under test + * `addr_type` : Address type ipv4/ipv6 + * `input_dict`: having details like multipath and bestpath + + Usage + ----- + input_dict_1 = { + "r1": { + "ipv4" : { + "bestpath": "50.0.0.1", + "multipath": ["50.0.0.1", "50.0.0.2"], + "network": "100.0.0.0/24" + } + "ipv6" : { + "bestpath": "1000::1", + "multipath": ["1000::1", "1000::2"] + "network": "2000::1/128" + } + } + } + + result = verify_bgp_bestpath(tgen, input_dict) + + """ + + result = False + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + for dut in input_dict.keys(): + rnode = tgen.routers()[dut] + + logger.info("[DUT: %s]: Verifying bgp bestpath and multipath " "routes:", dut) + result = False + for network_dict in input_dict[dut][addr_type]: + nw_addr = network_dict.setdefault("network", None) + vrf = network_dict.setdefault("vrf", None) + bestpath = network_dict.setdefault("bestpath", None) + + if vrf: + cmd = "show bgp vrf {} {} {} bestpath json".format( + vrf, addr_type, nw_addr + ) + else: + cmd = "show bgp {} {} bestpath json".format(addr_type, nw_addr) + + data = run_frr_cmd(rnode, cmd, isjson=True) + route = data["paths"][0] + + if "bestpath" in route: + if route["bestpath"]["overall"] is True: + _bestpath = route["nexthops"][0]["ip"] + + if _bestpath != bestpath: + return ( + "DUT:[{}] Bestpath do not match for" + " network: {}, Expected " + " {} as bgp bestpath found {}".format( + dut, nw_addr, bestpath, _bestpath + ) + ) + + logger.info( + "DUT:[{}] Found expected bestpath: " + " {} for network: {}".format(dut, _bestpath, nw_addr) + ) + result = True + + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return result + + +def verify_tcp_mss(tgen, dut, neighbour, configured_tcp_mss, vrf=None): + """ + This api is used to verify the tcp-mss value assigned to a neigbour of DUT + + Parameters + ---------- + * `tgen` : topogen object + * `dut`: device under test + * `neighbour`:neigbout IP address + * `configured_tcp_mss`:The TCP-MSS value to be verified + * `vrf`:vrf + + Usage + ----- + result = verify_tcp_mss(tgen, dut,neighbour,configured_tcp_mss) + Returns + ------- + errormsg(str) or True + """ + + logger.debug("Entering lib API: {}".format(sys._getframe().f_code.co_name)) + rnode = tgen.routers()[dut] + if vrf: + cmd = "show bgp vrf {} neighbors {} json".format(vrf, neighbour) + else: + cmd = "show bgp neighbors {} json".format(neighbour) + + # Execute the command + show_vrf_stats = run_frr_cmd(rnode, cmd, isjson=True) + + # Verify TCP-MSS on router + logger.info("Verify that no core is observed") + if tgen.routers_have_failure(): + errormsg = "Core observed while running CLI: %s" % (cmd) + return errormsg + else: + if configured_tcp_mss == show_vrf_stats.get(neighbour).get( + "bgpTcpMssConfigured" + ): + logger.debug( + "Configured TCP - MSS Found: {}".format(sys._getframe().f_code.co_name) + ) + return True + else: + logger.debug( + "TCP-MSS Mismatch ,configured {} expecting {}".format( + show_vrf_stats.get(neighbour).get("bgpTcpMssConfigured"), + configured_tcp_mss, + ) + ) + return "TCP-MSS Mismatch" + logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) + return False diff --git a/tests/topotests/lib/bgprib.py b/tests/topotests/lib/bgprib.py index a216e3588e..35a57d0a99 100644 --- a/tests/topotests/lib/bgprib.py +++ b/tests/topotests/lib/bgprib.py @@ -122,7 +122,7 @@ class BgpRib: luResult(target, True, title, logstr) def RequireUnicastRoutes(self, target, afi, vrf, title, wantroutes, debug=0): - logstr = "RequireVpnRoutes %s" % str(wantroutes) + logstr = "RequireUnicastRoutes %s" % str(wantroutes) vrfstr = "" if vrf != "": vrfstr = "vrf %s" % (vrf) diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index 1bce3c6bb2..c744e5bbbf 100644 --- a/tests/topotests/lib/common_config.py +++ b/tests/topotests/lib/common_config.py @@ -26,6 +26,7 @@ import socket import subprocess import sys import traceback +import functools from collections import OrderedDict from copy import deepcopy from datetime import datetime, timedelta @@ -2552,6 +2553,7 @@ def create_route_maps(tgen, input_dict, build=False): nexthop = set_data.setdefault("nexthop", None) origin = set_data.setdefault("origin", None) ext_comm_list = set_data.setdefault("extcommunity", {}) + metrictype = set_data.setdefault("metric-type", {}) # Local Preference if local_preference: @@ -2559,6 +2561,10 @@ def create_route_maps(tgen, input_dict, build=False): "set local-preference {}".format(local_preference) ) + # Metric-Type + if metrictype: + rmap_data.append("set metric-type {}\n".format(metrictype)) + # Metric if metric: rmap_data.append("set metric {} \n".format(metric)) @@ -2965,24 +2971,34 @@ def addKernelRoute( logger.info("[DUT: {}]: Running command: [{}]".format(router, cmd)) output = rnode.run(cmd) - # Verifying if ip route added to kernal - result = rnode.run(verify_cmd) - logger.debug("{}\n{}".format(verify_cmd, result)) - if "/" in grp_addr: - ip, mask = grp_addr.split("/") - if mask == "32" or mask == "128": - grp_addr = ip - else: - mask = "32" if addr_type == "ipv4" else "128" + def check_in_kernel(rnode, verify_cmd, grp_addr, router): + # Verifying if ip route added to kernal + errormsg = None + result = rnode.run(verify_cmd) + logger.debug("{}\n{}".format(verify_cmd, result)) + if "/" in grp_addr: + ip, mask = grp_addr.split("/") + if mask == "32" or mask == "128": + grp_addr = ip + else: + mask = "32" if addr_type == "ipv4" else "128" - if not re_search(r"{}".format(grp_addr), result) and mask != "0": - errormsg = ( - "[DUT: {}]: Kernal route is not added for group" - " address {} Config output: {}".format(router, grp_addr, output) - ) + if not re_search(r"{}".format(grp_addr), result) and mask != "0": + errormsg = ( + "[DUT: {}]: Kernal route is not added for group" + " address {} Config output: {}".format( + router, grp_addr, output + ) + ) return errormsg + test_func = functools.partial( + check_in_kernel, rnode, verify_cmd, grp_addr, router + ) + (result, out) = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result, out + logger.debug("Exiting lib API: addKernelRoute()") return True diff --git a/tests/topotests/lib/ltemplate.py b/tests/topotests/lib/ltemplate.py index c98bfac9ee..18882285ed 100644 --- a/tests/topotests/lib/ltemplate.py +++ b/tests/topotests/lib/ltemplate.py @@ -291,7 +291,7 @@ def ltemplateVersionCheck( # collect/log info on iproute2 cc = ltemplateRtrCmd() found = cc.doCmd( - tgen, rname, "apt-cache policy iproute2", "Installed: ([\d\.]*)" + tgen, rname, "apt-cache policy iproute2", r"Installed: ([\d\.]*)" ) if found != None: iproute2Ver = found.group(1) diff --git a/tests/topotests/lib/lutil.py b/tests/topotests/lib/lutil.py index c17c7f14e7..5c1fa24a7b 100644 --- a/tests/topotests/lib/lutil.py +++ b/tests/topotests/lib/lutil.py @@ -189,11 +189,8 @@ Total %-4d %-4d %d\n\ self.log("unable to read: " + tstFile) sys.exit(1) - def command(self, target, command, regexp, op, result, returnJson): + def command(self, target, command, regexp, op, result, returnJson, startt=None): global net - if op != "wait": - self.l_line += 1 - if op == "jsoncmp_pass" or op == "jsoncmp_fail": returnJson = True @@ -294,7 +291,11 @@ Total %-4d %-4d %d\n\ % (group_nl_converted, ret), 9, ) - if op == "pass" or op == "fail": + if startt != None: + if js != None or ret is not False: + delta = time.time() - startt + self.result(target, success, "%s +%4.2f secs" % (result, delta)) + elif op == "pass" or op == "fail": self.result(target, success, result) if js != None: return js @@ -326,7 +327,7 @@ Total %-4d %-4d %d\n\ while wait_count > 0: n += 1 - found = self.command(target, command, regexp, op, result, returnJson) + found = self.command(target, command, regexp, op, result, returnJson, startt) if found is not False: break @@ -336,14 +337,6 @@ Total %-4d %-4d %d\n\ delta = time.time() - startt self.log("Done after %d loops, time=%s, Found=%s" % (n, delta, found)) - found = self.command( - target, - command, - regexp, - "pass", - "%s +%4.2f secs" % (result, delta), - returnJson, - ) return found diff --git a/tests/topotests/lib/ospf.py b/tests/topotests/lib/ospf.py index c425e121af..92d29ad1ab 100644 --- a/tests/topotests/lib/ospf.py +++ b/tests/topotests/lib/ospf.py @@ -265,35 +265,6 @@ def __create_ospf_global(tgen, input_dict, router, build, load_config, ospf): cmd = "no {}".format(cmd) config_data.append(cmd) - # area interface information for ospf6d only - if ospf == "ospf6": - area_iface = ospf_data.setdefault("neighbors", {}) - if area_iface: - for neighbor in area_iface: - if "area" in area_iface[neighbor]: - iface = input_dict[router]["links"][neighbor]["interface"] - cmd = "interface {} area {}".format( - iface, area_iface[neighbor]["area"] - ) - if area_iface[neighbor].setdefault("delete", False): - cmd = "no {}".format(cmd) - config_data.append(cmd) - - try: - if "area" in input_dict[router]["links"][neighbor]["ospf6"]: - iface = input_dict[router]["links"][neighbor]["interface"] - cmd = "interface {} area {}".format( - iface, - input_dict[router]["links"][neighbor]["ospf6"]["area"], - ) - if input_dict[router]["links"][neighbor].setdefault( - "delete", False - ): - cmd = "no {}".format(cmd) - config_data.append(cmd) - except KeyError: - pass - # summary information summary_data = ospf_data.setdefault("summary-address", {}) if summary_data: @@ -363,69 +334,6 @@ def __create_ospf_global(tgen, input_dict, router, build, load_config, ospf): return config_data -def create_router_ospf6( - tgen, topo=None, input_dict=None, build=False, load_config=True -): - """ - API to configure ospf on router - - Parameters - ---------- - * `tgen` : Topogen object - * `topo` : json file data - * `input_dict` : Input dict data, required when configuring from testcase - * `build` : Only for initial setup phase this is set as True. - - Usage - ----- - input_dict = { - "r1": { - "ospf6": { - "router_id": "22.22.22.22", - } - } - - Returns - ------- - True or False - """ - logger.debug("Entering lib API: create_router_ospf6()") - result = False - - if topo is None: - topo = tgen.json_topo - - if not input_dict: - input_dict = deepcopy(topo) - else: - topo = topo["routers"] - input_dict = deepcopy(input_dict) - - config_data_dict = {} - - for router in input_dict.keys(): - if "ospf6" not in input_dict[router]: - logger.debug("Router %s: 'ospf6' not present in input_dict", router) - continue - - config_data = __create_ospf_global( - tgen, input_dict, router, build, load_config, "ospf6" - ) - if config_data: - config_data_dict[router] = config_data - - try: - result = create_common_configurations( - tgen, config_data_dict, "ospf6", build, load_config - ) - except InvalidCLIError: - logger.error("create_router_ospf6", exc_info=True) - result = False - - logger.debug("Exiting lib API: create_router_ospf6()") - return result - - def config_ospf_interface( tgen, topo=None, input_dict=None, build=False, load_config=True ): @@ -874,6 +782,16 @@ def verify_ospf6_neighbor(tgen, topo=None, dut=None, input_dict=None, lan=False) } result = verify_ospf6_neighbor(tgen, topo, dut, input_dict, lan=True) + 3. To check there are no neighbors. + input_dict = { + "r0": { + "ospf6": { + "neighbors": [] + } + } + } + result = verify_ospf6_neighbor(tgen, topo, dut, input_dict) + Returns ------- True or False (Error Message) @@ -904,6 +822,19 @@ def verify_ospf6_neighbor(tgen, topo=None, dut=None, input_dict=None, lan=False) ospf_data_list = input_dict[router]["ospf6"] ospf_nbr_list = ospf_data_list["neighbors"] + # Check if looking for no neighbors + if ospf_nbr_list == []: + if show_ospf_json["neighbors"] == []: + logger.info("[DUT: {}] OSPF6 no neighbors found".format(router)) + return True + else: + errormsg = ( + "[DUT: {}] OSPF6 active neighbors found, expected None".format( + router + ) + ) + return errormsg + for ospf_nbr, nbr_data in ospf_nbr_list.items(): try: diff --git a/tests/topotests/lib/pim.py b/tests/topotests/lib/pim.py index 944981add4..1f723eab93 100644 --- a/tests/topotests/lib/pim.py +++ b/tests/topotests/lib/pim.py @@ -21,8 +21,10 @@ import os import re import sys import traceback +import functools from copy import deepcopy from time import sleep +from lib import topotest # Import common_config to use commomnly used APIs @@ -1441,16 +1443,16 @@ def verify_pim_state( return True -def verify_pim_interface_traffic(tgen, input_dict): +def get_pim_interface_traffic(tgen, input_dict): """ - Verify ip pim interface traffice by running + get ip pim interface traffice by running "show ip pim interface traffic" cli Parameters ---------- * `tgen`: topogen object * `input_dict(dict)`: defines DUT, what and from which interfaces - traffic needs to be verified + traffic needs to be retrieved Usage ----- input_dict = { @@ -1464,7 +1466,7 @@ def verify_pim_interface_traffic(tgen, input_dict): } } - result = verify_pim_interface_traffic(tgen, input_dict) + result = get_pim_interface_traffic(tgen, input_dict) Returns ------- @@ -1481,24 +1483,34 @@ def verify_pim_interface_traffic(tgen, input_dict): rnode = tgen.routers()[dut] logger.info("[DUT: %s]: Verifying pim interface traffic", dut) - show_pim_intf_traffic_json = run_frr_cmd( - rnode, "show ip pim interface traffic json", isjson=True - ) - output_dict[dut] = {} - for intf, data in input_dict[dut].items(): - interface_json = show_pim_intf_traffic_json[intf] - for state in data: + def show_pim_intf_traffic(rnode, dut, input_dict, output_dict): + show_pim_intf_traffic_json = run_frr_cmd( + rnode, "show ip pim interface traffic json", isjson=True + ) - # Verify Tx/Rx - if state in interface_json: - output_dict[dut][state] = interface_json[state] - else: - errormsg = ( - "[DUT %s]: %s is not present" - "for interface %s [FAILED]!! " % (dut, state, intf) - ) - return errormsg + output_dict[dut] = {} + for intf, data in input_dict[dut].items(): + interface_json = show_pim_intf_traffic_json[intf] + for state in data: + + # Verify Tx/Rx + if state in interface_json: + output_dict[dut][state] = interface_json[state] + else: + errormsg = ( + "[DUT %s]: %s is not present" + "for interface %s [FAILED]!! " % (dut, state, intf) + ) + return errormsg + return None + + test_func = functools.partial( + show_pim_intf_traffic, rnode, dut, input_dict, output_dict + ) + (result, out) = topotest.run_and_expect(test_func, None, count=20, wait=1) + if not result: + return out logger.debug("Exiting lib API: {}".format(sys._getframe().f_code.co_name)) return output_dict diff --git a/tests/topotests/lib/topojson.py b/tests/topotests/lib/topojson.py index 4f23e1ace0..3ca3353ed3 100644 --- a/tests/topotests/lib/topojson.py +++ b/tests/topotests/lib/topojson.py @@ -40,7 +40,7 @@ from lib.common_config import ( topo_daemons, number_to_column, ) -from lib.ospf import create_router_ospf, create_router_ospf6 +from lib.ospf import create_router_ospf from lib.pim import create_igmp_config, create_pim_config from lib.topolog import logger @@ -334,7 +334,6 @@ def build_config_from_json(tgen, topo=None, save_bkup=True): ("igmp", create_igmp_config), ("bgp", create_router_bgp), ("ospf", create_router_ospf), - ("ospf6", create_router_ospf6), ] ) @@ -353,6 +352,18 @@ def build_config_from_json(tgen, topo=None, save_bkup=True): logger.info("build_config_from_json: failed to configure topology") pytest.exit(1) + logger.info("Built config now clearing ospf neighbors as that router-id might not be what is used") + for ospf in ["ospf", "ospf6"]: + for router in data: + if ospf not in data[router]: + continue + + r = tgen.gears[router] + if ospf == "ospf": + r.vtysh_cmd("clear ip ospf process") + else: + r.vtysh_cmd("clear ipv6 ospf6 process") + def create_tgen_from_json(testfile, json_file=None): """Create a topogen object given a testfile. diff --git a/tests/topotests/lib/topotest.py b/tests/topotests/lib/topotest.py index b98698185c..6be644ac00 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -1386,7 +1386,6 @@ class Router(Node): if params.get("routertype") is not None: self.routertype = params.get("routertype") - self.cmd("ulimit -c unlimited") # Set ownership of config files self.cmd("chown {0}:{0}vty /etc/{0}".format(self.routertype)) @@ -1445,7 +1444,7 @@ class Router(Node): running = self.listDaemons() if running: - for _ in range(0, 5): + for _ in range(0, 30): sleep( 0.5, "{}: waiting for daemons stopping: {}".format( @@ -1725,7 +1724,7 @@ class Router(Node): ) if valgrind_extra: cmdenv += ( - "--gen-suppressions=all --expensive-definedness-checks=yes" + " --gen-suppressions=all --expensive-definedness-checks=yes" ) elif daemon in strace_daemons or "all" in strace_daemons: cmdenv = "strace -f -D -o {1}/{2}.strace.{0} ".format( @@ -1860,7 +1859,7 @@ class Router(Node): self.cmd("kill -9 %s" % daemonpid) if pid_exists(int(daemonpid)): numRunning += 1 - if wait and numRunning > 0: + while wait and numRunning > 0: sleep( 2, "{}: waiting for {} daemon to be stopped".format( @@ -1884,7 +1883,11 @@ class Router(Node): ) ) self.cmd("kill -9 %s" % daemonpid) - self.cmd("rm -- {}".format(d.rstrip())) + if daemonpid.isdigit() and not pid_exists( + int(daemonpid) + ): + numRunning -= 1 + self.cmd("rm -- {}".format(d.rstrip())) if wait: errors = self.checkRouterCores(reportOnce=True) if self.checkRouterVersion("<", minErrorVersion): diff --git a/tests/topotests/msdp_topo1/r1/pimd.conf b/tests/topotests/msdp_topo1/r1/pimd.conf index 4274315271..5bb268ebef 100644 --- a/tests/topotests/msdp_topo1/r1/pimd.conf +++ b/tests/topotests/msdp_topo1/r1/pimd.conf @@ -1,5 +1,5 @@ -debug pim -debug pim zebra +! debug pim +! debug pim zebra ! interface lo ip pim diff --git a/tests/topotests/msdp_topo1/r2/pimd.conf b/tests/topotests/msdp_topo1/r2/pimd.conf index a4a69bf05c..733bd6f2f1 100644 --- a/tests/topotests/msdp_topo1/r2/pimd.conf +++ b/tests/topotests/msdp_topo1/r2/pimd.conf @@ -1,5 +1,5 @@ -debug pim -debug pim zebra +! debug pim +! debug pim zebra ! interface lo ip pim diff --git a/tests/topotests/msdp_topo1/r3/pimd.conf b/tests/topotests/msdp_topo1/r3/pimd.conf index db94447c76..47987c0aa8 100644 --- a/tests/topotests/msdp_topo1/r3/pimd.conf +++ b/tests/topotests/msdp_topo1/r3/pimd.conf @@ -1,5 +1,5 @@ -debug pim -debug pim zebra +! debug pim +! debug pim zebra ! interface lo ip pim diff --git a/tests/topotests/msdp_topo1/r4/pimd.conf b/tests/topotests/msdp_topo1/r4/pimd.conf index e9bb59054c..28085913fb 100644 --- a/tests/topotests/msdp_topo1/r4/pimd.conf +++ b/tests/topotests/msdp_topo1/r4/pimd.conf @@ -1,5 +1,5 @@ -debug pim -debug pim zebra +! debug pim +! debug pim zebra ! interface lo ip pim diff --git a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py index a94dcb505a..a8418d400d 100644 --- a/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py +++ b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py @@ -104,7 +104,7 @@ from lib.pim import ( enable_disable_pim_bsm, clear_ip_mroute, clear_ip_pim_interface_traffic, - verify_pim_interface_traffic, + get_pim_interface_traffic, McastTesterHelper, ) from lib.topolog import logger @@ -648,7 +648,7 @@ def test_BSR_CRP_with_blackhole_address_p1(request): step("Verify bsm transit count is not increamented" "show ip pim interface traffic") state_dict = {"f1": {intf_f1_i1: ["bsmTx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( @@ -673,7 +673,7 @@ def test_BSR_CRP_with_blackhole_address_p1(request): tc_name, result ) - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( @@ -848,6 +848,10 @@ def test_new_router_fwd_p0(request): assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) do_countdown(5) + step("Verify again if BSR is installed from bsm forwarded by i1") + result = verify_pim_bsr(tgen, topo, "l1", bsr_ip) + assert result is True, "Testcase {} :Failed \n Error {}".format(tc_name, result) + # Verify ip mroute populated again step("Verify mroute again on l1 (lhr)") result = verify_ip_mroutes(tgen, "l1", src_addr, GROUP_ADDRESS, iif, oil) 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 dc14bc6468..9929f4b3c7 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 @@ -84,7 +84,7 @@ from lib.pim import ( create_igmp_config, verify_igmp_groups, verify_ip_mroutes, - verify_pim_interface_traffic, + get_pim_interface_traffic, verify_upstream_iif, verify_ip_pim_join, clear_ip_mroute, @@ -280,7 +280,7 @@ def test_multicast_data_traffic_static_RP_send_join_then_traffic_p0(request): step("get joinRx value before join") intf_r2_l1 = topo["routers"]["r2"]["links"]["l1"]["interface"] state_dict = {"r2": {intf_r2_l1: ["joinRx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase {} : Failed \n state_before is not dictionary \n Error: {}".format( @@ -352,7 +352,7 @@ def test_multicast_data_traffic_static_RP_send_join_then_traffic_p0(request): assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) step("joinRx value after join sent") - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase {} : Failed \n state_before is not dictionary \n Error: {}".format( @@ -425,7 +425,7 @@ def test_multicast_data_traffic_static_RP_send_traffic_then_join_p0(request): step("Enable IGMP on FRR1 interface and send IGMP join (225.1.1.1)") step("joinRx value before join sent") state_dict = {"r2": {"r2-l1-eth2": ["joinRx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase {} : Failed \n state_before is not dictionary \n Error: {}".format( @@ -474,7 +474,7 @@ def test_multicast_data_traffic_static_RP_send_traffic_then_join_p0(request): assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) step("joinRx value after join sent") - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase {} : Failed \n state_before is not dictionary \n Error: {}".format( 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 c7d453ad81..57561c78eb 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 @@ -82,7 +82,7 @@ from lib.pim import ( create_igmp_config, verify_igmp_groups, verify_ip_mroutes, - verify_pim_interface_traffic, + get_pim_interface_traffic, verify_upstream_iif, verify_pim_neighbors, verify_pim_state, @@ -731,7 +731,7 @@ def test_verify_SPT_switchover_when_RPT_and_SPT_path_is_different_p0(request): step("registerRx and registerStopTx value before traffic sent") state_dict = {"c2": {"c2-f1-eth1": ["registerRx", "registerStopTx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase {} : Failed \n state_before is not dictionary \nError: {}".format( @@ -815,7 +815,7 @@ def test_verify_SPT_switchover_when_RPT_and_SPT_path_is_different_p0(request): assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) step("registerRx and registerStopTx value after traffic sent") - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase {} : Failed \n state_before is not dictionary \nError: {}".format( 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 5e29a1f1fd..1fc6fddefe 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 @@ -78,11 +78,13 @@ from lib.pim import ( verify_upstream_iif, clear_ip_mroute, verify_pim_rp_info, - verify_pim_interface_traffic, + get_pim_interface_traffic, McastTesterHelper, ) from lib.topolog import logger from lib.topojson import build_config_from_json +from time import sleep + TOPOLOGY = """ @@ -930,7 +932,7 @@ def test_PIM_hello_tx_rx_p1(request): } } - c1_state_before = verify_pim_interface_traffic(tgen, state_dict) + c1_state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( c1_state_before, dict ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( @@ -946,19 +948,30 @@ def test_PIM_hello_tx_rx_p1(request): ) shutdown_bringup_interface(tgen, "c1", intf_c1_l1, True) - step("verify stats after on c1") - c1_state_after = verify_pim_interface_traffic(tgen, state_dict) - assert isinstance( - c1_state_after, dict - ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( - tc_name, result - ) + step("verify stats after on c1 and that they are incremented") + + count = 0 + done = False + while not done and count <= 7: + c1_state_after = get_pim_interface_traffic(tgen, state_dict) + assert isinstance( + c1_state_after, dict + ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( + tc_name, result + ) + + result = verify_state_incremented(c1_state_before, c1_state_after) + if result is not True: + sleep(5) + count += 1 + else: + done = True - step("verify stats not increamented on c1") - result = verify_state_incremented(c1_state_before, c1_state_after) assert ( - result is not True - ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result) + result is True + ), "Testcase{} : Failed Error: {}" "stats is not incremented".format( + tc_name, result + ) step("verify before stats on l1") l1_state_dict = { @@ -967,7 +980,7 @@ def test_PIM_hello_tx_rx_p1(request): } } - l1_state_before = verify_pim_interface_traffic(tgen, l1_state_dict) + l1_state_before = get_pim_interface_traffic(tgen, l1_state_dict) assert isinstance( l1_state_before, dict ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( @@ -983,16 +996,24 @@ def test_PIM_hello_tx_rx_p1(request): ) shutdown_bringup_interface(tgen, "l1", intf_l1_c1, True) - step("verify stats after on l1") - l1_state_after = verify_pim_interface_traffic(tgen, l1_state_dict) - assert isinstance( - l1_state_after, dict - ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( - tc_name, result - ) + step("verify stats after on l1 are incremented") + count = 0 + done = False + while not done and count <= 7: + l1_state_after = get_pim_interface_traffic(tgen, l1_state_dict) + assert isinstance( + l1_state_after, dict + ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( + tc_name, result + ) + + result = verify_state_incremented(l1_state_before, l1_state_after) + if result is True: + sleep(5) + count += 1 + else: + done = True - step("verify stats not increamented on l1") - result = verify_state_incremented(l1_state_before, l1_state_after) assert ( result is not True ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result) @@ -1010,7 +1031,7 @@ def test_PIM_hello_tx_rx_p1(request): } } - c1_state_before = verify_pim_interface_traffic(tgen, state_dict) + c1_state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( c1_state_before, dict ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( @@ -1033,20 +1054,28 @@ def test_PIM_hello_tx_rx_p1(request): result = apply_raw_config(tgen, raw_config) assert result is True, "Testcase {} : Failed Error: {}".format(tc_name, result) - step("verify stats after on c1") - c1_state_after = verify_pim_interface_traffic(tgen, state_dict) - assert isinstance( - c1_state_after, dict - ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( + step("verify stats after on c1 are incremented") + count = 0 + done = False + while not done and count <= 7: + c1_state_after = get_pim_interface_traffic(tgen, state_dict) + assert isinstance( + c1_state_after, dict + ), "Testcase{} : Failed \n state_before is not dictionary \n Error: {}".format( + tc_name, result + ) + + result = verify_state_incremented(c1_state_before, c1_state_after) + if result is not True: + sleep(5) + count += 1 + else: + done = True + + assert result is True, "Testcase{} : Failed Error: {}" "stats incremented".format( tc_name, result ) - step("verify stats not increamented on c1") - result = verify_state_incremented(c1_state_before, c1_state_after) - assert ( - result is not True - ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result) - write_test_footer(tc_name) 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 9bbe3ca028..a5cec93813 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 @@ -137,7 +137,7 @@ from lib.pim import ( verify_join_state_and_timer, verify_ip_mroutes, verify_pim_neighbors, - verify_pim_interface_traffic, + get_pim_interface_traffic, verify_pim_rp_info, verify_pim_state, clear_ip_pim_interface_traffic, @@ -386,7 +386,7 @@ def test_add_delete_static_RP_p0(request): step("r1: Verify show ip pim interface traffic without any IGMP join") state_dict = {"r1": {"r1-r2-eth1": ["pruneTx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase {} : Failed \n state_before is not dictionary\n Error: {}".format( @@ -488,7 +488,7 @@ def test_add_delete_static_RP_p0(request): ) step("r1: Verify show ip pim interface traffic without any IGMP join") - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase {} : Failed \n state_before is not dictionary \n Error: {}".format( @@ -699,7 +699,7 @@ def test_not_reachable_static_RP_p0(request): "show ip pim interface traffic" ) state_dict = {"r1": {"r1-r2-eth1": ["pruneTx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( @@ -800,7 +800,7 @@ def test_not_reachable_static_RP_p0(request): "r1: (*,G) prune is sent towards the RP interface, verify using" "show ip pim interface traffic" ) - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( @@ -888,7 +888,7 @@ def test_add_RP_after_join_received_p1(request): step("joinTx value before join sent") state_dict = {"r1": {"r1-r2-eth1": ["joinTx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( @@ -979,7 +979,7 @@ def test_add_RP_after_join_received_p1(request): assert result is True, "Testcase {} :Failed \n Error: {}".format(tc_name, result) logger.info("Expected behavior: %s", result) - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( @@ -1024,7 +1024,7 @@ def test_reachable_static_RP_after_join_p0(request): step("r1 : Verify pim interface traffic") state_dict = {"r1": {"r1-r2-eth1": ["joinTx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( @@ -1123,7 +1123,7 @@ def test_reachable_static_RP_after_join_p0(request): logger.info("Expected behavior: %s", result) step("r1 : Verify pim interface traffic") - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( @@ -1211,7 +1211,7 @@ def test_send_join_on_higher_preffered_rp_p1(request): step("r1 : Verify joinTx count before sending join") state_dict = {"r1": {"r1-r4-eth3": ["joinTx"], "r1-r2-eth1": ["pruneTx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( @@ -1261,7 +1261,7 @@ def test_send_join_on_higher_preffered_rp_p1(request): step("r1 : Verify join is sent to higher preferred RP") step("r1 : Verify prune is sent to lower preferred RP") - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( @@ -1293,7 +1293,7 @@ def test_send_join_on_higher_preffered_rp_p1(request): step("r1 : Verify joinTx, pruneTx count before RP gets deleted") state_dict = {"r1": {"r1-r2-eth1": ["joinTx"], "r1-r4-eth3": ["pruneTx"]}} - state_before = verify_pim_interface_traffic(tgen, state_dict) + state_before = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_before, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( @@ -1375,7 +1375,7 @@ def test_send_join_on_higher_preffered_rp_p1(request): "r1 : Verify prune is sent to higher preferred RP when higher" " preferred RP gets deleted" ) - state_after = verify_pim_interface_traffic(tgen, state_dict) + state_after = get_pim_interface_traffic(tgen, state_dict) assert isinstance( state_after, dict ), "Testcase{} : Failed \n state_before is not dictionary \n " "Error: {}".format( diff --git a/tests/topotests/nhrp_topo/r1/nhrpd.conf b/tests/topotests/nhrp_topo/r1/nhrpd.conf index 04114bdbe6..e5224e4aab 100644 --- a/tests/topotests/nhrp_topo/r1/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r1/nhrpd.conf @@ -1,5 +1,5 @@ log stdout debugging -debug nhrp all +! debug nhrp all interface r1-gre0 ip nhrp holdtime 500 ip nhrp shortcut diff --git a/tests/topotests/nhrp_topo/r2/nhrpd.conf b/tests/topotests/nhrp_topo/r2/nhrpd.conf index e4f6fb7445..f9185f9a63 100644 --- a/tests/topotests/nhrp_topo/r2/nhrpd.conf +++ b/tests/topotests/nhrp_topo/r2/nhrpd.conf @@ -1,4 +1,4 @@ -debug nhrp all +! debug nhrp all log stdout debugging nhrp nflog-group 1 interface r2-gre0 diff --git a/tests/topotests/nhrp_topo/r3/zebra.conf b/tests/topotests/nhrp_topo/r3/zebra.conf index 6d3d267978..e77f955225 100644 --- a/tests/topotests/nhrp_topo/r3/zebra.conf +++ b/tests/topotests/nhrp_topo/r3/zebra.conf @@ -1,7 +1,7 @@ -debug zebra kernel -debug zebra rib -debug zebra events -debug zebra packet +! debug zebra kernel +! debug zebra rib +! debug zebra events +! debug zebra packet ip forwarding interface r3-eth0 ip address 10.1.1.3/24 diff --git a/tests/topotests/nhrp_topo/test_nhrp_topo.py b/tests/topotests/nhrp_topo/test_nhrp_topo.py index 2dd00c0184..e6e551906a 100644 --- a/tests/topotests/nhrp_topo/test_nhrp_topo.py +++ b/tests/topotests/nhrp_topo/test_nhrp_topo.py @@ -41,6 +41,7 @@ sys.path.append(os.path.join(CWD, "../")) 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 # Required to instantiate the topology builder class. @@ -86,19 +87,24 @@ def _populate_iface(): for cmd in cmds_tot_hub: input = cmd.format("r2", "2") - logger.info("input: " + cmd) - output = tgen.net["r2"].cmd(cmd.format("r2", "2")) + logger.info("input: " + input) + output = tgen.net["r2"].cmd(input) logger.info("output: " + output) for cmd in cmds_tot: input = cmd.format("r1", "1") - logger.info("input: " + cmd) - output = tgen.net["r1"].cmd(cmd.format("r1", "1")) + logger.info("input: " + input) + output = tgen.net["r1"].cmd(input) logger.info("output: " + output) def setup_module(mod): "Sets up the pytest environment" + + result = required_linux_kernel_version("5.0") + if result is not True: + pytest.skip("Kernel requirements are not met") + tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() diff --git a/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf index 9e2ad298a3..8a9b4eb124 100644 --- a/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf +++ b/tests/topotests/ospf6_gr_topo1/rt1/ospf6d.conf @@ -3,14 +3,14 @@ hostname rt1 log file ospf6d.log log commands ! -debug ospf6 lsa router originate -debug ospf6 lsa router flooding -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 graceful-restart -debug ospf6 spf process +! debug ospf6 lsa router originate +! debug ospf6 lsa router flooding +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 graceful-restart +! debug ospf6 spf process ! interface lo ipv6 ospf area 1 diff --git a/tests/topotests/ospf6_gr_topo1/rt1/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt1/zebra.conf index f29f5b73fb..01ecd647b5 100644 --- a/tests/topotests/ospf6_gr_topo1/rt1/zebra.conf +++ b/tests/topotests/ospf6_gr_topo1/rt1/zebra.conf @@ -3,10 +3,10 @@ hostname rt1 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ospf6_gr_topo1/rt2/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt2/ospf6d.conf index cfa8758344..bcce341f51 100644 --- a/tests/topotests/ospf6_gr_topo1/rt2/ospf6d.conf +++ b/tests/topotests/ospf6_gr_topo1/rt2/ospf6d.conf @@ -3,14 +3,14 @@ hostname rt2 log file ospf6d.log log commands ! -debug ospf6 lsa router originate -debug ospf6 lsa router flooding -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 graceful-restart -debug ospf6 spf process +! debug ospf6 lsa router originate +! debug ospf6 lsa router flooding +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 graceful-restart +! debug ospf6 spf process ! interface lo ipv6 ospf area 0 diff --git a/tests/topotests/ospf6_gr_topo1/rt2/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt2/zebra.conf index e4fe7620da..5e5731b7ab 100644 --- a/tests/topotests/ospf6_gr_topo1/rt2/zebra.conf +++ b/tests/topotests/ospf6_gr_topo1/rt2/zebra.conf @@ -3,10 +3,10 @@ hostname rt2 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/ospf6_gr_topo1/rt3/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt3/ospf6d.conf index f33f14f34f..8dba58e07c 100644 --- a/tests/topotests/ospf6_gr_topo1/rt3/ospf6d.conf +++ b/tests/topotests/ospf6_gr_topo1/rt3/ospf6d.conf @@ -3,14 +3,14 @@ hostname rt3 log file ospf6d.log log commands ! -debug ospf6 lsa router originate -debug ospf6 lsa router flooding -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 graceful-restart -debug ospf6 spf process +! debug ospf6 lsa router originate +! debug ospf6 lsa router flooding +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 graceful-restart +! debug ospf6 spf process ! interface lo ipv6 ospf area 0 diff --git a/tests/topotests/ospf6_gr_topo1/rt3/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt3/zebra.conf index 3a9de21d30..ca3eea410d 100644 --- a/tests/topotests/ospf6_gr_topo1/rt3/zebra.conf +++ b/tests/topotests/ospf6_gr_topo1/rt3/zebra.conf @@ -3,10 +3,10 @@ hostname rt3 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/ospf6_gr_topo1/rt4/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt4/ospf6d.conf index 301eb57e7d..9be5321e68 100644 --- a/tests/topotests/ospf6_gr_topo1/rt4/ospf6d.conf +++ b/tests/topotests/ospf6_gr_topo1/rt4/ospf6d.conf @@ -3,14 +3,14 @@ hostname rt4 log file ospf6d.log log commands ! -debug ospf6 lsa router originate -debug ospf6 lsa router flooding -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 graceful-restart -debug ospf6 spf process +! debug ospf6 lsa router originate +! debug ospf6 lsa router flooding +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 graceful-restart +! debug ospf6 spf process ! interface lo ipv6 ospf area 0 diff --git a/tests/topotests/ospf6_gr_topo1/rt4/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt4/zebra.conf index eeea417b70..c488b2a387 100644 --- a/tests/topotests/ospf6_gr_topo1/rt4/zebra.conf +++ b/tests/topotests/ospf6_gr_topo1/rt4/zebra.conf @@ -3,10 +3,10 @@ hostname rt4 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/ospf6_gr_topo1/rt5/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt5/ospf6d.conf index 254fea75fc..98ba8bc447 100644 --- a/tests/topotests/ospf6_gr_topo1/rt5/ospf6d.conf +++ b/tests/topotests/ospf6_gr_topo1/rt5/ospf6d.conf @@ -3,14 +3,14 @@ hostname rt5 log file ospf6d.log log commands ! -debug ospf6 lsa router originate -debug ospf6 lsa router flooding -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 graceful-restart -debug ospf6 spf process +! debug ospf6 lsa router originate +! debug ospf6 lsa router flooding +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 graceful-restart +! debug ospf6 spf process ! interface lo ipv6 ospf area 2 diff --git a/tests/topotests/ospf6_gr_topo1/rt5/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt5/zebra.conf index 0cdb90b129..43ed901266 100644 --- a/tests/topotests/ospf6_gr_topo1/rt5/zebra.conf +++ b/tests/topotests/ospf6_gr_topo1/rt5/zebra.conf @@ -3,10 +3,10 @@ hostname rt5 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/ospf6_gr_topo1/rt6/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt6/ospf6d.conf index b1feb1ac57..d6d6f0cf92 100644 --- a/tests/topotests/ospf6_gr_topo1/rt6/ospf6d.conf +++ b/tests/topotests/ospf6_gr_topo1/rt6/ospf6d.conf @@ -3,14 +3,14 @@ hostname rt6 log file ospf6d.log log commands ! -debug ospf6 lsa router originate -debug ospf6 lsa router flooding -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 graceful-restart -debug ospf6 spf process +! debug ospf6 lsa router originate +! debug ospf6 lsa router flooding +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 graceful-restart +! debug ospf6 spf process ! interface lo ipv6 ospf area 0 diff --git a/tests/topotests/ospf6_gr_topo1/rt6/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt6/zebra.conf index 3c2312da8a..5ec27de17a 100644 --- a/tests/topotests/ospf6_gr_topo1/rt6/zebra.conf +++ b/tests/topotests/ospf6_gr_topo1/rt6/zebra.conf @@ -3,10 +3,10 @@ hostname rt6 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 6.6.6.6/32 diff --git a/tests/topotests/ospf6_gr_topo1/rt7/ospf6d.conf b/tests/topotests/ospf6_gr_topo1/rt7/ospf6d.conf index d032741d1a..cee6ee577e 100644 --- a/tests/topotests/ospf6_gr_topo1/rt7/ospf6d.conf +++ b/tests/topotests/ospf6_gr_topo1/rt7/ospf6d.conf @@ -3,14 +3,14 @@ hostname rt7 log file ospf6d.log log commands ! -debug ospf6 lsa router originate -debug ospf6 lsa router flooding -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 graceful-restart -debug ospf6 spf process +! debug ospf6 lsa router originate +! debug ospf6 lsa router flooding +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 graceful-restart +! debug ospf6 spf process ! interface lo ipv6 ospf area 3 diff --git a/tests/topotests/ospf6_gr_topo1/rt7/zebra.conf b/tests/topotests/ospf6_gr_topo1/rt7/zebra.conf index 9cc8c29c1e..3939472b5e 100644 --- a/tests/topotests/ospf6_gr_topo1/rt7/zebra.conf +++ b/tests/topotests/ospf6_gr_topo1/rt7/zebra.conf @@ -3,10 +3,10 @@ hostname rt7 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 7.7.7.7/32 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 ccbcadb8b1..e59333ebd2 100755 --- a/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py +++ b/tests/topotests/ospf6_gr_topo1/test_ospf6_gr_topo1.py @@ -171,14 +171,60 @@ def router_compare_json_output(rname, command, reference, tries): assert diff is None, assertmsg +def expect_grace_lsa(restarting, helper): + """ + Check if the given helper neighbor has already received a Grace-LSA from + the router performing a graceful restart. + """ + tgen = get_topogen() + + logger.info( + "'{}': checking if a Grace-LSA was received from '{}'".format( + helper, restarting + ) + ) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[helper], + "show ipv6 ospf6 database json", + { + "interfaceScopedLinkStateDb": [ + { + "lsa": [ + { + "type": "GR", + "advRouter": restarting, + } + ] + } + ] + }, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = '"{}" didn\'t receive a Grace-LSA from "{}"'.format(helper, restarting) + + assert result is None, assertmsg + + def check_routers(initial_convergence=False, exiting=None, restarting=None): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: # Check the RIB first, which should be preserved across restarts in # all routers of the routing domain. + # If we are not on initial convergence *but* we are checking + # after a restart. Looking in the zebra rib for installed + # is a recipe for test failure. Why? because if we are restarting + # then ospf is in the process of establishing neighbors and passing + # new routes to zebra. Zebra will not mark the route as installed + # when it receives a replacement from ospf until it has finished + # processing it. Let's give it a few seconds to allow this to happen + # under load. if initial_convergence == True: tries = 240 else: - tries = 1 + if restarting != None: + tries = 40 + else: + tries = 1 router_compare_json_output( rname, "show ipv6 route ospf json", "show_ipv6_route.json", tries ) @@ -212,6 +258,26 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): ) +def ensure_gr_is_in_zebra(rname): + retry = True + retry_times = 10 + tgen = get_topogen() + + while retry and retry_times > 0: + out = tgen.net[rname].cmd( + 'vtysh -c "show zebra client" | grep "Client: ospf6$" -A 40 | grep "Capabilities "' + ) + + if "Graceful Restart" not in out: + sleep(2) + retry_times -= 1 + else: + retry = False + + assertmsg = "%s does not appear to have Graceful Restart setup" % rname + assert not retry and retry_times > 0, assertmsg + + # # Test initial network convergence # @@ -238,10 +304,10 @@ def test_gr_rt1(): pytest.skip(tgen.errors) tgen.net["rt1"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + expect_grace_lsa(restarting="1.1.1.1", helper="rt2") + ensure_gr_is_in_zebra("rt1") kill_router_daemons(tgen, "rt1", ["ospf6d"], save_config=False) check_routers(exiting="rt1") - start_router_daemons(tgen, "rt1", ["ospf6d"]) check_routers(restarting="rt1") @@ -258,7 +324,9 @@ def test_gr_rt2(): pytest.skip(tgen.errors) tgen.net["rt2"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + expect_grace_lsa(restarting="2.2.2.2", helper="rt1") + expect_grace_lsa(restarting="2.2.2.2", helper="rt3") + ensure_gr_is_in_zebra("rt2") kill_router_daemons(tgen, "rt2", ["ospf6d"], save_config=False) check_routers(exiting="rt2") @@ -278,7 +346,10 @@ def test_gr_rt3(): pytest.skip(tgen.errors) tgen.net["rt3"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + expect_grace_lsa(restarting="3.3.3.3", helper="rt2") + expect_grace_lsa(restarting="3.3.3.3", helper="rt4") + expect_grace_lsa(restarting="3.3.3.3", helper="rt6") + ensure_gr_is_in_zebra("rt3") kill_router_daemons(tgen, "rt3", ["ospf6d"], save_config=False) check_routers(exiting="rt3") @@ -298,7 +369,9 @@ def test_gr_rt4(): pytest.skip(tgen.errors) tgen.net["rt4"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + expect_grace_lsa(restarting="4.4.4.4", helper="rt3") + expect_grace_lsa(restarting="4.4.4.4", helper="rt5") + ensure_gr_is_in_zebra("rt4") kill_router_daemons(tgen, "rt4", ["ospf6d"], save_config=False) check_routers(exiting="rt4") @@ -318,7 +391,8 @@ def test_gr_rt5(): pytest.skip(tgen.errors) tgen.net["rt5"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + expect_grace_lsa(restarting="5.5.5.5", helper="rt4") + ensure_gr_is_in_zebra("rt5") kill_router_daemons(tgen, "rt5", ["ospf6d"], save_config=False) check_routers(exiting="rt5") @@ -338,7 +412,9 @@ def test_gr_rt6(): pytest.skip(tgen.errors) tgen.net["rt6"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + expect_grace_lsa(restarting="6.6.6.6", helper="rt3") + expect_grace_lsa(restarting="6.6.6.6", helper="rt7") + ensure_gr_is_in_zebra("rt6") kill_router_daemons(tgen, "rt6", ["ospf6d"], save_config=False) check_routers(exiting="rt6") @@ -358,7 +434,8 @@ def test_gr_rt7(): pytest.skip(tgen.errors) tgen.net["rt7"].cmd('vtysh -c "graceful-restart prepare ipv6 ospf"') - sleep(5) + expect_grace_lsa(restarting="6.6.6.6", helper="rt6") + ensure_gr_is_in_zebra("rt7") kill_router_daemons(tgen, "rt7", ["ospf6d"], save_config=False) check_routers(exiting="rt7") diff --git a/tests/topotests/ospf6_topo1/r1/ospf6d.conf b/tests/topotests/ospf6_topo1/r1/ospf6d.conf index 9f7e058931..5f1ceee964 100644 --- a/tests/topotests/ospf6_topo1/r1/ospf6d.conf +++ b/tests/topotests/ospf6_topo1/r1/ospf6d.conf @@ -1,13 +1,13 @@ hostname r1 log file ospf6d.log ! -debug ospf6 message all -debug ospf6 lsa unknown -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 route table -debug ospf6 flooding +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding ! interface r1-stubnet ipv6 ospf6 network broadcast diff --git a/tests/topotests/ospf6_topo1/r1/zebra.conf b/tests/topotests/ospf6_topo1/r1/zebra.conf index dfbcea8d21..3a7db9f25e 100644 --- a/tests/topotests/ospf6_topo1/r1/zebra.conf +++ b/tests/topotests/ospf6_topo1/r1/zebra.conf @@ -2,8 +2,8 @@ hostname r1 log file zebra.log ! -debug zebra events -debug zebra rib +! debug zebra events +! debug zebra rib ! interface r1-stubnet ipv6 address fc00:1:1:1::1/64 diff --git a/tests/topotests/ospf6_topo1/r2/ospf6d.conf b/tests/topotests/ospf6_topo1/r2/ospf6d.conf index 26ebc2c0ea..d51b41e1e5 100644 --- a/tests/topotests/ospf6_topo1/r2/ospf6d.conf +++ b/tests/topotests/ospf6_topo1/r2/ospf6d.conf @@ -1,13 +1,13 @@ hostname r2 log file ospf6d.log ! -debug ospf6 message all -debug ospf6 lsa unknown -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 route table -debug ospf6 flooding +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding ! interface r2-stubnet ipv6 ospf6 network broadcast diff --git a/tests/topotests/ospf6_topo1/r2/zebra.conf b/tests/topotests/ospf6_topo1/r2/zebra.conf index f05d1a60ff..5571dc979c 100644 --- a/tests/topotests/ospf6_topo1/r2/zebra.conf +++ b/tests/topotests/ospf6_topo1/r2/zebra.conf @@ -2,8 +2,8 @@ hostname r2 log file zebra.log ! -debug zebra events -debug zebra rib +! debug zebra events +! debug zebra rib ! interface r2-stubnet ipv6 address fc00:2:2:2::2/64 diff --git a/tests/topotests/ospf6_topo1/r3/ospf6d.conf b/tests/topotests/ospf6_topo1/r3/ospf6d.conf index e902496530..cad71ac067 100644 --- a/tests/topotests/ospf6_topo1/r3/ospf6d.conf +++ b/tests/topotests/ospf6_topo1/r3/ospf6d.conf @@ -1,13 +1,13 @@ hostname r3 log file ospf6d.log ! -debug ospf6 message all -debug ospf6 lsa unknown -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 route table -debug ospf6 flooding +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding ! interface r3-stubnet ipv6 ospf6 network broadcast diff --git a/tests/topotests/ospf6_topo1/r3/zebra.conf b/tests/topotests/ospf6_topo1/r3/zebra.conf index d8051c350d..3cc5626bd7 100644 --- a/tests/topotests/ospf6_topo1/r3/zebra.conf +++ b/tests/topotests/ospf6_topo1/r3/zebra.conf @@ -2,8 +2,8 @@ hostname r3 log file zebra.log ! -debug zebra events -debug zebra rib +! debug zebra events +! debug zebra rib ! interface r3-stubnet ipv6 address fc00:3:3:3::3/64 diff --git a/tests/topotests/ospf6_topo1/r4/ospf6d.conf b/tests/topotests/ospf6_topo1/r4/ospf6d.conf index 5607a789de..f0b166bc4b 100644 --- a/tests/topotests/ospf6_topo1/r4/ospf6d.conf +++ b/tests/topotests/ospf6_topo1/r4/ospf6d.conf @@ -1,13 +1,13 @@ hostname r4 log file ospf6d.log ! -debug ospf6 message all -debug ospf6 lsa unknown -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 route table -debug ospf6 flooding +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding ! interface r4-stubnet ipv6 ospf6 network broadcast diff --git a/tests/topotests/ospf6_topo1/r4/zebra.conf b/tests/topotests/ospf6_topo1/r4/zebra.conf index cada58bd01..20e27cea46 100644 --- a/tests/topotests/ospf6_topo1/r4/zebra.conf +++ b/tests/topotests/ospf6_topo1/r4/zebra.conf @@ -2,8 +2,8 @@ hostname r4 log file zebra.log ! -debug zebra events -debug zebra rib +! debug zebra events +! debug zebra rib ! interface r4-stubnet ipv6 address fc00:4:4:4::4/64 diff --git a/tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf b/tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf index 83bdfb7c81..e60c5991a4 100644 --- a/tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf +++ b/tests/topotests/ospf6_topo1_vrf/r1/ospf6d.conf @@ -1,13 +1,13 @@ hostname r1 log file ospf6d.log ! -debug ospf6 message all -debug ospf6 lsa unknown -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 route table -debug ospf6 flooding +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding ! interface r1-stubnet ipv6 ospf6 area 0.0.0.0 diff --git a/tests/topotests/ospf6_topo1_vrf/r1/zebra.conf b/tests/topotests/ospf6_topo1_vrf/r1/zebra.conf index abe8a9bc45..704912b52d 100644 --- a/tests/topotests/ospf6_topo1_vrf/r1/zebra.conf +++ b/tests/topotests/ospf6_topo1_vrf/r1/zebra.conf @@ -2,8 +2,8 @@ hostname r1 log file zebra.log ! -debug zebra events -debug zebra rib +! debug zebra events +! debug zebra rib ! interface r1-stubnet vrf r1-cust1 ipv6 address fc00:1:1:1::1/64 diff --git a/tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf b/tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf index 7fd01aa0cc..778c7781d8 100644 --- a/tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf +++ b/tests/topotests/ospf6_topo1_vrf/r2/ospf6d.conf @@ -1,13 +1,13 @@ hostname r2 log file ospf6d.log ! -debug ospf6 message all -debug ospf6 lsa unknown -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 route table -debug ospf6 flooding +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding ! interface r2-stubnet ipv6 ospf6 area 0.0.0.0 diff --git a/tests/topotests/ospf6_topo1_vrf/r2/zebra.conf b/tests/topotests/ospf6_topo1_vrf/r2/zebra.conf index e1011bd3b6..123d8c4a35 100644 --- a/tests/topotests/ospf6_topo1_vrf/r2/zebra.conf +++ b/tests/topotests/ospf6_topo1_vrf/r2/zebra.conf @@ -2,8 +2,8 @@ hostname r2 log file zebra.log ! -debug zebra events -debug zebra rib +! debug zebra events +! debug zebra rib ! interface r2-stubnet vrf r2-cust1 ipv6 address fc00:2:2:2::2/64 diff --git a/tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf b/tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf index df5aed3a6a..61d183f1d8 100644 --- a/tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf +++ b/tests/topotests/ospf6_topo1_vrf/r3/ospf6d.conf @@ -1,13 +1,13 @@ hostname r3 log file ospf6d.log ! -debug ospf6 message all -debug ospf6 lsa unknown -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 route table -debug ospf6 flooding +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding ! interface r3-stubnet ipv6 ospf6 area 0.0.0.0 diff --git a/tests/topotests/ospf6_topo1_vrf/r3/zebra.conf b/tests/topotests/ospf6_topo1_vrf/r3/zebra.conf index f489f3ac73..bd6873d2a8 100644 --- a/tests/topotests/ospf6_topo1_vrf/r3/zebra.conf +++ b/tests/topotests/ospf6_topo1_vrf/r3/zebra.conf @@ -2,8 +2,8 @@ hostname r3 log file zebra.log ! -debug zebra events -debug zebra rib +! debug zebra events +! debug zebra rib ! interface r3-stubnet vrf r3-cust1 ipv6 address fc00:3:3:3::3/64 diff --git a/tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf b/tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf index 465defb40f..12f6f52166 100644 --- a/tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf +++ b/tests/topotests/ospf6_topo1_vrf/r4/ospf6d.conf @@ -1,13 +1,13 @@ hostname r4 log file ospf6d.log ! -debug ospf6 message all -debug ospf6 lsa unknown -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 route table -debug ospf6 flooding +! debug ospf6 message all +! debug ospf6 lsa unknown +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 route table +! debug ospf6 flooding ! interface r4-stubnet ipv6 ospf6 area 0.0.0.1 diff --git a/tests/topotests/ospf6_topo1_vrf/r4/zebra.conf b/tests/topotests/ospf6_topo1_vrf/r4/zebra.conf index c59116df8c..0d9d011f6d 100644 --- a/tests/topotests/ospf6_topo1_vrf/r4/zebra.conf +++ b/tests/topotests/ospf6_topo1_vrf/r4/zebra.conf @@ -2,8 +2,8 @@ hostname r4 log file zebra.log ! -debug zebra events -debug zebra rib +! debug zebra events +! debug zebra rib ! interface r4-stubnet vrf r4-cust1 ipv6 address fc00:4:4:4::4/64 diff --git a/tests/topotests/ospf6_topo2/r1/ospf6d.conf b/tests/topotests/ospf6_topo2/r1/ospf6d.conf index 2e465e6d1f..a9d46be41a 100644 --- a/tests/topotests/ospf6_topo2/r1/ospf6d.conf +++ b/tests/topotests/ospf6_topo2/r1/ospf6d.conf @@ -1,34 +1,37 @@ -debug ospf6 lsa router -debug ospf6 lsa router originate -debug ospf6 lsa router examine -debug ospf6 lsa router flooding -debug ospf6 lsa as-external -debug ospf6 lsa as-external originate -debug ospf6 lsa as-external examine -debug ospf6 lsa as-external flooding -debug ospf6 lsa intra-prefix -debug ospf6 lsa intra-prefix originate -debug ospf6 lsa intra-prefix examine -debug ospf6 lsa intra-prefix flooding -debug ospf6 border-routers -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 gr helper -debug ospf6 spf process -debug ospf6 route intra-area -debug ospf6 route inter-area -debug ospf6 abr -debug ospf6 asbr -debug ospf6 nssa +! debug ospf6 lsa router +! debug ospf6 lsa router originate +! debug ospf6 lsa router examine +! debug ospf6 lsa router flooding +! debug ospf6 lsa nssa +! debug ospf6 lsa nssa originate +! debug ospf6 lsa nssa examine +! debug ospf6 lsa nssa flooding +! debug ospf6 lsa as-external +! debug ospf6 lsa as-external originate +! debug ospf6 lsa as-external examine +! debug ospf6 lsa as-external flooding +! debug ospf6 lsa intra-prefix +! debug ospf6 lsa intra-prefix originate +! debug ospf6 lsa intra-prefix examine +! debug ospf6 lsa intra-prefix flooding +! debug ospf6 border-routers +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 spf process +! debug ospf6 route intra-area +! debug ospf6 route inter-area +! debug ospf6 abr +! debug ospf6 asbr +! debug ospf6 nssa ! interface r1-eth0 + ipv6 ospf6 area 0.0.0.1 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! router ospf6 ospf6 router-id 10.254.254.1 area 0.0.0.1 stub - interface r1-eth0 area 0.0.0.1 ! diff --git a/tests/topotests/ospf6_topo2/r2/ospf6d.conf b/tests/topotests/ospf6_topo2/r2/ospf6d.conf index 4a1d10693d..8819a588f1 100644 --- a/tests/topotests/ospf6_topo2/r2/ospf6d.conf +++ b/tests/topotests/ospf6_topo2/r2/ospf6d.conf @@ -1,37 +1,43 @@ -debug ospf6 lsa router -debug ospf6 lsa router originate -debug ospf6 lsa router examine -debug ospf6 lsa router flooding -debug ospf6 lsa as-external -debug ospf6 lsa as-external originate -debug ospf6 lsa as-external examine -debug ospf6 lsa as-external flooding -debug ospf6 lsa intra-prefix -debug ospf6 lsa intra-prefix originate -debug ospf6 lsa intra-prefix examine -debug ospf6 lsa intra-prefix flooding -debug ospf6 border-routers -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 gr helper -debug ospf6 spf process -debug ospf6 route intra-area -debug ospf6 route inter-area -debug ospf6 abr -debug ospf6 asbr -debug ospf6 nssa +! debug ospf6 lsa router +! debug ospf6 lsa router originate +! debug ospf6 lsa router examine +! debug ospf6 lsa router flooding +! debug ospf6 lsa nssa +! debug ospf6 lsa nssa originate +! debug ospf6 lsa nssa examine +! debug ospf6 lsa nssa flooding +! debug ospf6 lsa as-external +! debug ospf6 lsa as-external originate +! debug ospf6 lsa as-external examine +! debug ospf6 lsa as-external flooding +! debug ospf6 lsa intra-prefix +! debug ospf6 lsa intra-prefix originate +! debug ospf6 lsa intra-prefix examine +! debug ospf6 lsa intra-prefix flooding +! debug ospf6 border-routers +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 spf process +! debug ospf6 route intra-area +! debug ospf6 route inter-area +! debug ospf6 abr +! debug ospf6 asbr +! debug ospf6 nssa ! interface r2-eth0 + ipv6 ospf6 area 0.0.0.1 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! interface r2-eth1 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! interface r2-eth2 + ipv6 ospf6 area 0.0.0.2 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! @@ -42,7 +48,4 @@ router ospf6 default-information originate always metric 123 area 0.0.0.1 stub area 0.0.0.2 nssa - interface r2-eth0 area 0.0.0.1 - interface r2-eth1 area 0.0.0.0 - interface r2-eth2 area 0.0.0.2 ! diff --git a/tests/topotests/ospf6_topo2/r3/ospf6d.conf b/tests/topotests/ospf6_topo2/r3/ospf6d.conf index 5faeb70e56..6e4f56ba7a 100644 --- a/tests/topotests/ospf6_topo2/r3/ospf6d.conf +++ b/tests/topotests/ospf6_topo2/r3/ospf6d.conf @@ -1,29 +1,33 @@ -debug ospf6 lsa router -debug ospf6 lsa router originate -debug ospf6 lsa router examine -debug ospf6 lsa router flooding -debug ospf6 lsa as-external -debug ospf6 lsa as-external originate -debug ospf6 lsa as-external examine -debug ospf6 lsa as-external flooding -debug ospf6 lsa intra-prefix -debug ospf6 lsa intra-prefix originate -debug ospf6 lsa intra-prefix examine -debug ospf6 lsa intra-prefix flooding -debug ospf6 border-routers -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 gr helper -debug ospf6 spf process -debug ospf6 route intra-area -debug ospf6 route inter-area -debug ospf6 abr -debug ospf6 asbr -debug ospf6 nssa +! debug ospf6 lsa router +! debug ospf6 lsa router originate +! debug ospf6 lsa router examine +! debug ospf6 lsa router flooding +! debug ospf6 lsa nssa +! debug ospf6 lsa nssa originate +! debug ospf6 lsa nssa examine +! debug ospf6 lsa nssa flooding +! debug ospf6 lsa as-external +! debug ospf6 lsa as-external originate +! debug ospf6 lsa as-external examine +! debug ospf6 lsa as-external flooding +! debug ospf6 lsa intra-prefix +! debug ospf6 lsa intra-prefix originate +! debug ospf6 lsa intra-prefix examine +! debug ospf6 lsa intra-prefix flooding +! debug ospf6 border-routers +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 spf process +! debug ospf6 route intra-area +! debug ospf6 route inter-area +! debug ospf6 abr +! debug ospf6 asbr +! debug ospf6 nssa ! interface r3-eth0 + ipv6 ospf6 area 0.0.0.0 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! @@ -31,5 +35,4 @@ router ospf6 ospf6 router-id 10.254.254.3 redistribute connected redistribute static - interface r3-eth0 area 0.0.0.0 ! diff --git a/tests/topotests/ospf6_topo2/r4/ospf6d.conf b/tests/topotests/ospf6_topo2/r4/ospf6d.conf index 04d763f6a8..59a2fd5cc9 100644 --- a/tests/topotests/ospf6_topo2/r4/ospf6d.conf +++ b/tests/topotests/ospf6_topo2/r4/ospf6d.conf @@ -1,34 +1,37 @@ -debug ospf6 lsa router -debug ospf6 lsa router originate -debug ospf6 lsa router examine -debug ospf6 lsa router flooding -debug ospf6 lsa as-external -debug ospf6 lsa as-external originate -debug ospf6 lsa as-external examine -debug ospf6 lsa as-external flooding -debug ospf6 lsa intra-prefix -debug ospf6 lsa intra-prefix originate -debug ospf6 lsa intra-prefix examine -debug ospf6 lsa intra-prefix flooding -debug ospf6 border-routers -debug ospf6 zebra -debug ospf6 interface -debug ospf6 neighbor -debug ospf6 flooding -debug ospf6 gr helper -debug ospf6 spf process -debug ospf6 route intra-area -debug ospf6 route inter-area -debug ospf6 abr -debug ospf6 asbr -debug ospf6 nssa +! debug ospf6 lsa router +! debug ospf6 lsa router originate +! debug ospf6 lsa router examine +! debug ospf6 lsa router flooding +! debug ospf6 lsa nssa +! debug ospf6 lsa nssa originate +! debug ospf6 lsa nssa examine +! debug ospf6 lsa nssa flooding +! debug ospf6 lsa as-external +! debug ospf6 lsa as-external originate +! debug ospf6 lsa as-external examine +! debug ospf6 lsa as-external flooding +! debug ospf6 lsa intra-prefix +! debug ospf6 lsa intra-prefix originate +! debug ospf6 lsa intra-prefix examine +! debug ospf6 lsa intra-prefix flooding +! debug ospf6 border-routers +! debug ospf6 zebra +! debug ospf6 interface +! debug ospf6 neighbor +! debug ospf6 flooding +! debug ospf6 spf process +! debug ospf6 route intra-area +! debug ospf6 route inter-area +! debug ospf6 abr +! debug ospf6 asbr +! debug ospf6 nssa ! interface r4-eth0 + ipv6 ospf6 area 0.0.0.2 ipv6 ospf6 hello-interval 2 ipv6 ospf6 dead-interval 10 ! router ospf6 ospf6 router-id 10.254.254.4 area 0.0.0.2 nssa - interface r4-eth0 area 0.0.0.2 ! diff --git a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py index 303bcd014d..eb8561c404 100644 --- a/tests/topotests/ospf6_topo2/test_ospf6_topo2.py +++ b/tests/topotests/ospf6_topo2/test_ospf6_topo2.py @@ -131,6 +131,8 @@ def build_topo(tgen): switch.add_link(tgen.gears["r2"]) switch.add_link(tgen.gears["r4"]) + switch = tgen.add_switch("s4") + switch.add_link(tgen.gears["r4"], nodeif="r4-stubnet") def setup_module(mod): "Sets up the pytest environment" @@ -484,7 +486,7 @@ def test_area_filters(): pytest.skip(tgen.errors) # - # Configure import/export filters on r2 (ABR for area 1). + # Configure import/export filters on r2 (ABR for area 2). # config = """ configure terminal @@ -544,6 +546,102 @@ def test_area_filters(): expect_ospfv3_routes("r1", routes, wait=30, type="inter-area") +def test_nssa_range(): + """ + Test NSSA ABR ranges. + """ + tgen = get_topogen() + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + # Configure new addresses on r4 and enable redistribution of connected + # routes. + config = """ + configure terminal + interface r4-stubnet + ipv6 address 2001:db8:1000::1/128 + ipv6 address 2001:db8:1000::2/128 + router ospf6 + redistribute connected + """ + tgen.gears["r4"].vtysh_cmd(config) + logger.info("Expecting NSSA-translated external routes to be added on r3") + routes = {"2001:db8:1000::1/128": {}, "2001:db8:1000::2/128": {}} + expect_ospfv3_routes("r3", routes, wait=30, type="external-2") + + # Configure an NSSA range on r2 (ABR for area 2). + config = """ + configure terminal + router ospf6 + area 2 nssa range 2001:db8:1000::/64 + """ + tgen.gears["r2"].vtysh_cmd(config) + logger.info("Expecting summarized routes to be removed from r3") + for route in ["2001:db8:1000::1/128", "2001:db8:1000::2/128"]: + test_func = partial(dont_expect_route, "r3", route, type="external-2") + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = "{}'s {} summarized route still exists".format("r3", route) + assert result is None, assertmsg + logger.info("Expecting NSSA range to be added on r3") + routes = { + "2001:db8:1000::/64": { + "metricType":2, + "metricCost":20, + "metricCostE2":10, + }} + expect_ospfv3_routes("r3", routes, wait=30, type="external-2", detail=True) + + # Change the NSSA range cost. + config = """ + configure terminal + router ospf6 + area 2 nssa range 2001:db8:1000::/64 cost 1000 + """ + tgen.gears["r2"].vtysh_cmd(config) + logger.info("Expecting NSSA range to be updated with new cost") + routes = { + "2001:db8:1000::/64": { + "metricType":2, + "metricCost":20, + "metricCostE2":1000, + }} + expect_ospfv3_routes("r3", routes, wait=30, type="external-2", detail=True) + + # Configure the NSSA range to not be advertised. + config = """ + configure terminal + router ospf6 + area 2 nssa range 2001:db8:1000::/64 not-advertise + """ + tgen.gears["r2"].vtysh_cmd(config) + logger.info("Expecting NSSA summary route to be removed") + route = "2001:db8:1000::/64" + test_func = partial(dont_expect_route, "r3", route, type="external-2") + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = "{}'s {} NSSA summary route still exists".format("r3", route) + assert result is None, assertmsg + + # Remove the NSSA range. + config = """ + configure terminal + router ospf6 + no area 2 nssa range 2001:db8:1000::/64 + """ + tgen.gears["r2"].vtysh_cmd(config) + logger.info("Expecting previously summarized routes to be re-added") + routes = { + "2001:db8:1000::1/128": { + "metricType":2, + "metricCost":20, + }, + "2001:db8:1000::2/128": { + "metricType":2, + "metricCost":20, + }, + } + expect_ospfv3_routes("r3", routes, wait=30, type="external-2", detail=True) + + def teardown_module(_mod): "Teardown the pytest environment" tgen = get_topogen() 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 64dfa0c69d..f9fa55e275 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 @@ -669,89 +669,6 @@ def test_ospf_type5_summary_tc48_p0(request): result is True ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name) - step("Configure metric type as 1 in route map.") - - routemaps = { - "r0": { - "route_maps": { - "rmap_ipv4": [{"action": "permit", "set": {"metric-type": "type-1"}}] - } - } - } - result = create_route_maps(tgen, routemaps) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - step( - "Verify that external routes(static / connected) are summarised" - " to configured summary address with metric type 2." - ) - input_dict = { - SUMMARY["ipv4"][0]: { - "Summary address": SUMMARY["ipv4"][0], - "Metric-type": "E2", - "Metric": 20, - "Tag": 0, - "External route count": 5, - } - } - dut = "r0" - result = verify_ospf_summary(tgen, topo, dut, input_dict) - assert ( - result is True - ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name) - - step("Un configure metric type from route map.") - - routemaps = { - "r0": { - "route_maps": { - "rmap_ipv4": [ - { - "action": "permit", - "set": {"metric-type": "type-1"}, - "delete": True, - } - ] - } - } - } - result = create_route_maps(tgen, routemaps) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - - step( - "Verify that external routes(static / connected) are summarised" - " to configured summary address with metric type 2." - ) - input_dict = { - SUMMARY["ipv4"][0]: { - "Summary address": SUMMARY["ipv4"][0], - "Metric-type": "E2", - "Metric": 20, - "Tag": 0, - "External route count": 5, - } - } - dut = "r0" - result = verify_ospf_summary(tgen, topo, dut, input_dict) - assert ( - result is True - ), "Testcase {} : Failed" "Error: Summary missing in OSPF DB".format(tc_name) - - step("Change rule from permit to deny in prefix list.") - pfx_list = { - "r0": { - "prefix_lists": { - "ipv4": { - "pf_list_1_ipv4": [ - {"seqid": 10, "network": "any", "action": "deny"} - ] - } - } - } - } - result = create_prefix_lists(tgen, pfx_list) - assert result is True, "Testcase {} : Failed \n Error: {}".format(tc_name, result) - write_test_footer(tc_name) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py index b80da41bec..b32483f7ad 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py @@ -408,11 +408,12 @@ def test_ospf_lan_tc1_p0(request): topo_modify_change_ip = deepcopy(topo) intf_ip = topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] topo_modify_change_ip["routers"]["r0"]["links"]["s1"]["ipv4"] = str( - IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 3 + IPv4Address(frr_unicode(intf_ip.split("/")[0])) + 4 ) + "/{}".format(intf_ip.split("/")[1]) build_config_from_json(tgen, topo_modify_change_ip, save_bkup=False) + clear_ospf(tgen, "r0") step( "Verify that OSPF is in FULL state with other routers with " "newly configured IP." diff --git a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.json b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.json index c8a3ce783b..cdb8813b3d 100644 --- a/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.json +++ b/tests/topotests/ospf_dual_stack/test_ospf_dual_stack.json @@ -23,7 +23,8 @@ }, "ospf6": { "hello_interval": 1, - "dead_interval": 4 + "dead_interval": 4, + "area": "1.1.1.1" } } }, @@ -36,9 +37,7 @@ "ospf6": { "router_id": "1.1.1.1", "neighbors": { - "r3": { - "area": "1.1.1.1" - } + "r3": {} } } }, @@ -56,7 +55,8 @@ "ospf6": { "hello_interval": 1, "dead_interval": 4, - "network": "point-to-point" + "network": "point-to-point", + "area": "1.1.1.1" } }, "r4": { @@ -71,7 +71,8 @@ "ospf6": { "hello_interval": 1, "dead_interval": 4, - "network": "point-to-point" + "network": "point-to-point", + "area": "0.0.0.0" } } }, @@ -85,8 +86,8 @@ "ospf6": { "router_id": "2.2.2.2", "neighbors": { - "r3": { "area": "1.1.1.1" }, - "r4": { "area": "0.0.0.0" } + "r3": {}, + "r4": {} } } }, @@ -104,7 +105,8 @@ "ospf6": { "hello_interval": 1, "dead_interval": 4, - "network": "point-to-point" + "network": "point-to-point", + "area": "1.1.1.1" } }, "r2": { @@ -119,7 +121,8 @@ "ospf6": { "hello_interval": 1, "dead_interval": 4, - "network": "point-to-point" + "network": "point-to-point", + "area": "1.1.1.1" } }, "r4": { @@ -134,7 +137,8 @@ "ospf6": { "hello_interval": 1, "dead_interval": 4, - "network": "point-to-point" + "network": "point-to-point", + "area": "0.0.0.0" } } }, @@ -149,9 +153,9 @@ "ospf6": { "router_id": "3.3.3.3", "neighbors": { - "r1": { "area": "1.1.1.1" }, - "r2": { "area": "1.1.1.1" }, - "r4": { "area": "0.0.0.0" } + "r1": {}, + "r2": {}, + "r4": {} } } }, @@ -169,7 +173,8 @@ "ospf6": { "hello_interval": 1, "dead_interval": 4, - "network": "point-to-point" + "network": "point-to-point", + "area": "0.0.0.0" } }, "r3": { @@ -184,7 +189,8 @@ "ospf6": { "hello_interval": 1, "dead_interval": 4, - "network": "point-to-point" + "network": "point-to-point", + "area": "0.0.0.0" } }, "r5": { @@ -199,7 +205,8 @@ "ospf6": { "hello_interval": 1, "dead_interval": 4, - "network": "point-to-point" + "network": "point-to-point", + "area": "2.2.2.2" } } }, @@ -214,9 +221,9 @@ "ospf6": { "router_id": "4.4.4.4", "neighbors": { - "r2": { "area": "0.0.0.0" }, - "r3": { "area": "0.0.0.0" }, - "r5": { "area": "2.2.2.2" } + "r2": {}, + "r3": {}, + "r5": {} } } }, @@ -234,7 +241,8 @@ "ospf6": { "hello_interval": 1, "dead_interval": 4, - "network": "point-to-point" + "network": "point-to-point", + "area": "2.2.2.2" } } }, @@ -247,7 +255,7 @@ "ospf6": { "router_id": "5.5.5.5", "neighbors": { - "r4": { "area": "2.2.2.2" } + "r4": {} } } } diff --git a/tests/topotests/ospf_gr_topo1/rt1/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt1/ospfd.conf index 9590a7cadf..27042e1a85 100644 --- a/tests/topotests/ospf_gr_topo1/rt1/ospfd.conf +++ b/tests/topotests/ospf_gr_topo1/rt1/ospfd.conf @@ -3,16 +3,16 @@ hostname rt1 log file ospfd.log log commands ! -debug ospf zebra -debug ospf event -debug ospf lsa -debug ospf te -debug ospf packet all -debug ospf packet ls-update detail -debug ospf ism -debug ospf nsm -debug ospf nssa -debug ospf graceful-restart +! debug ospf zebra +! debug ospf event +! debug ospf lsa +! debug ospf te +! debug ospf packet all +! debug ospf packet ls-update detail +! debug ospf ism +! debug ospf nsm +! debug ospf nssa +! debug ospf graceful-restart ! interface lo ip ospf area 1 diff --git a/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_neighbor.json index ed290323a4..f82758101c 100644 --- a/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_neighbor.json +++ b/tests/topotests/ospf_gr_topo1/rt1/show_ip_ospf_neighbor.json @@ -2,7 +2,7 @@ "neighbors":{ "2.2.2.2":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.1.2", "ifaceName":"eth-rt2:10.0.1.1" } diff --git a/tests/topotests/ospf_gr_topo1/rt1/zebra.conf b/tests/topotests/ospf_gr_topo1/rt1/zebra.conf index 183cd3df48..7b99b58548 100644 --- a/tests/topotests/ospf_gr_topo1/rt1/zebra.conf +++ b/tests/topotests/ospf_gr_topo1/rt1/zebra.conf @@ -3,10 +3,10 @@ hostname rt1 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ospf_gr_topo1/rt2/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt2/ospfd.conf index 4f60d37b18..591b242da7 100644 --- a/tests/topotests/ospf_gr_topo1/rt2/ospfd.conf +++ b/tests/topotests/ospf_gr_topo1/rt2/ospfd.conf @@ -3,16 +3,16 @@ hostname rt2 log file ospfd.log log commands ! -debug ospf zebra -debug ospf event -debug ospf lsa -debug ospf te -debug ospf packet all -debug ospf packet ls-update detail -debug ospf ism -debug ospf nsm -debug ospf nssa -debug ospf graceful-restart +! debug ospf zebra +! debug ospf event +! debug ospf lsa +! debug ospf te +! debug ospf packet all +! debug ospf packet ls-update detail +! debug ospf ism +! debug ospf nsm +! debug ospf nssa +! debug ospf graceful-restart ! interface lo ip ospf area 0 diff --git a/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_neighbor.json index 4fe92b0b98..5a0b092702 100644 --- a/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_neighbor.json +++ b/tests/topotests/ospf_gr_topo1/rt2/show_ip_ospf_neighbor.json @@ -2,14 +2,14 @@ "neighbors":{ "1.1.1.1":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.1.1", "ifaceName":"eth-rt1:10.0.1.2" } ], "3.3.3.3":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.2.3", "ifaceName":"eth-rt3:10.0.2.2" } diff --git a/tests/topotests/ospf_gr_topo1/rt2/zebra.conf b/tests/topotests/ospf_gr_topo1/rt2/zebra.conf index 8bde98ad44..73571aadbf 100644 --- a/tests/topotests/ospf_gr_topo1/rt2/zebra.conf +++ b/tests/topotests/ospf_gr_topo1/rt2/zebra.conf @@ -3,10 +3,10 @@ hostname rt2 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/ospf_gr_topo1/rt3/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt3/ospfd.conf index 870878287d..5e7477120a 100644 --- a/tests/topotests/ospf_gr_topo1/rt3/ospfd.conf +++ b/tests/topotests/ospf_gr_topo1/rt3/ospfd.conf @@ -3,16 +3,16 @@ hostname rt3 log file ospfd.log log commands ! -debug ospf zebra -debug ospf event -debug ospf lsa -debug ospf te -debug ospf packet all -debug ospf packet ls-update detail -debug ospf ism -debug ospf nsm -debug ospf nssa -debug ospf graceful-restart +! debug ospf zebra +! debug ospf event +! debug ospf lsa +! debug ospf te +! debug ospf packet all +! debug ospf packet ls-update detail +! debug ospf ism +! debug ospf nsm +! debug ospf nssa +! debug ospf graceful-restart ! interface lo ip ospf area 0 diff --git a/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_neighbor.json index e3c36ab9a3..ab5e78414d 100644 --- a/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_neighbor.json +++ b/tests/topotests/ospf_gr_topo1/rt3/show_ip_ospf_neighbor.json @@ -2,21 +2,21 @@ "neighbors":{ "2.2.2.2":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.2.2", "ifaceName":"eth-rt2:10.0.2.3" } ], "4.4.4.4":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.3.4", "ifaceName":"eth-rt4:10.0.3.3" } ], "6.6.6.6":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.4.6", "ifaceName":"eth-rt6:10.0.4.3" } diff --git a/tests/topotests/ospf_gr_topo1/rt3/zebra.conf b/tests/topotests/ospf_gr_topo1/rt3/zebra.conf index dfd89cbe5b..c09bafef2e 100644 --- a/tests/topotests/ospf_gr_topo1/rt3/zebra.conf +++ b/tests/topotests/ospf_gr_topo1/rt3/zebra.conf @@ -3,10 +3,10 @@ hostname rt3 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/ospf_gr_topo1/rt4/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt4/ospfd.conf index 0aff1faf2c..7aa722cb8a 100644 --- a/tests/topotests/ospf_gr_topo1/rt4/ospfd.conf +++ b/tests/topotests/ospf_gr_topo1/rt4/ospfd.conf @@ -3,16 +3,16 @@ hostname rt4 log file ospfd.log log commands ! -debug ospf zebra -debug ospf event -debug ospf lsa -debug ospf te -debug ospf packet all -debug ospf packet ls-update detail -debug ospf ism -debug ospf nsm -debug ospf nssa -debug ospf graceful-restart +! debug ospf zebra +! debug ospf event +! debug ospf lsa +! debug ospf te +! debug ospf packet all +! debug ospf packet ls-update detail +! debug ospf ism +! debug ospf nsm +! debug ospf nssa +! debug ospf graceful-restart ! interface lo ip ospf area 0 diff --git a/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_neighbor.json index 2123ecb8da..405679c10e 100644 --- a/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_neighbor.json +++ b/tests/topotests/ospf_gr_topo1/rt4/show_ip_ospf_neighbor.json @@ -2,14 +2,14 @@ "neighbors":{ "3.3.3.3":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.3.3", "ifaceName":"eth-rt3:10.0.3.4" } ], "5.5.5.5":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.5.5", "ifaceName":"eth-rt5:10.0.5.4" } diff --git a/tests/topotests/ospf_gr_topo1/rt4/zebra.conf b/tests/topotests/ospf_gr_topo1/rt4/zebra.conf index f399b29f3f..e21b23e4d3 100644 --- a/tests/topotests/ospf_gr_topo1/rt4/zebra.conf +++ b/tests/topotests/ospf_gr_topo1/rt4/zebra.conf @@ -3,10 +3,10 @@ hostname rt4 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/ospf_gr_topo1/rt5/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt5/ospfd.conf index 4af89389a5..0e25f1a138 100644 --- a/tests/topotests/ospf_gr_topo1/rt5/ospfd.conf +++ b/tests/topotests/ospf_gr_topo1/rt5/ospfd.conf @@ -3,16 +3,16 @@ hostname rt5 log file ospfd.log log commands ! -debug ospf zebra -debug ospf event -debug ospf lsa -debug ospf te -debug ospf packet all -debug ospf packet ls-update detail -debug ospf ism -debug ospf nsm -debug ospf nssa -debug ospf graceful-restart +! debug ospf zebra +! debug ospf event +! debug ospf lsa +! debug ospf te +! debug ospf packet all +! debug ospf packet ls-update detail +! debug ospf ism +! debug ospf nsm +! debug ospf nssa +! debug ospf graceful-restart ! interface lo ip ospf area 2 diff --git a/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_neighbor.json index 6440b67698..893d454368 100644 --- a/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_neighbor.json +++ b/tests/topotests/ospf_gr_topo1/rt5/show_ip_ospf_neighbor.json @@ -2,7 +2,7 @@ "neighbors":{ "4.4.4.4":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.5.4", "ifaceName":"eth-rt4:10.0.5.5" } diff --git a/tests/topotests/ospf_gr_topo1/rt5/zebra.conf b/tests/topotests/ospf_gr_topo1/rt5/zebra.conf index 49a1c05a6d..83f12c6635 100644 --- a/tests/topotests/ospf_gr_topo1/rt5/zebra.conf +++ b/tests/topotests/ospf_gr_topo1/rt5/zebra.conf @@ -3,10 +3,10 @@ hostname rt5 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/ospf_gr_topo1/rt6/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt6/ospfd.conf index 2295a75fe7..3960e6b40c 100644 --- a/tests/topotests/ospf_gr_topo1/rt6/ospfd.conf +++ b/tests/topotests/ospf_gr_topo1/rt6/ospfd.conf @@ -3,16 +3,16 @@ hostname rt6 log file ospfd.log log commands ! -debug ospf zebra -debug ospf event -debug ospf lsa -debug ospf te -debug ospf packet all -debug ospf packet ls-update detail -debug ospf ism -debug ospf nsm -debug ospf nssa -debug ospf graceful-restart +! debug ospf zebra +! debug ospf event +! debug ospf lsa +! debug ospf te +! debug ospf packet all +! debug ospf packet ls-update detail +! debug ospf ism +! debug ospf nsm +! debug ospf nssa +! debug ospf graceful-restart ! interface lo ip ospf area 0 diff --git a/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_neighbor.json index d815c23927..564a513ac6 100644 --- a/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_neighbor.json +++ b/tests/topotests/ospf_gr_topo1/rt6/show_ip_ospf_neighbor.json @@ -2,14 +2,14 @@ "neighbors":{ "3.3.3.3":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.4.3", "ifaceName":"eth-rt3:10.0.4.6" } ], "7.7.7.7":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.6.7", "ifaceName":"eth-rt7:10.0.6.6" } diff --git a/tests/topotests/ospf_gr_topo1/rt6/zebra.conf b/tests/topotests/ospf_gr_topo1/rt6/zebra.conf index d6a8f52b3a..67ebf14575 100644 --- a/tests/topotests/ospf_gr_topo1/rt6/zebra.conf +++ b/tests/topotests/ospf_gr_topo1/rt6/zebra.conf @@ -3,10 +3,10 @@ hostname rt6 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 6.6.6.6/32 diff --git a/tests/topotests/ospf_gr_topo1/rt7/ospfd.conf b/tests/topotests/ospf_gr_topo1/rt7/ospfd.conf index 8534eda5a7..e52424e1db 100644 --- a/tests/topotests/ospf_gr_topo1/rt7/ospfd.conf +++ b/tests/topotests/ospf_gr_topo1/rt7/ospfd.conf @@ -3,16 +3,16 @@ hostname rt7 log file ospfd.log log commands ! -debug ospf zebra -debug ospf event -debug ospf lsa -debug ospf te -debug ospf packet all -debug ospf packet ls-update detail -debug ospf ism -debug ospf nsm -debug ospf nssa -debug ospf graceful-restart +! debug ospf zebra +! debug ospf event +! debug ospf lsa +! debug ospf te +! debug ospf packet all +! debug ospf packet ls-update detail +! debug ospf ism +! debug ospf nsm +! debug ospf nssa +! debug ospf graceful-restart ! interface lo ip ospf area 3 diff --git a/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_neighbor.json b/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_neighbor.json index 2254aea9a6..bc6b60697c 100644 --- a/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_neighbor.json +++ b/tests/topotests/ospf_gr_topo1/rt7/show_ip_ospf_neighbor.json @@ -2,7 +2,7 @@ "neighbors":{ "6.6.6.6":[ { - "state":"Full\/DROther", + "converged":"Full", "address":"10.0.6.6", "ifaceName":"eth-rt6:10.0.6.7" } diff --git a/tests/topotests/ospf_gr_topo1/rt7/zebra.conf b/tests/topotests/ospf_gr_topo1/rt7/zebra.conf index c481e4532b..7037e6fc5f 100644 --- a/tests/topotests/ospf_gr_topo1/rt7/zebra.conf +++ b/tests/topotests/ospf_gr_topo1/rt7/zebra.conf @@ -3,10 +3,10 @@ hostname rt7 log file zebra.log log commands ! -debug zebra event -debug zebra packet -debug zebra rib -debug zebra kernel +! debug zebra event +! debug zebra packet +! debug zebra rib +! debug zebra kernel ! interface lo ip address 7.7.7.7/32 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 7d9cc68412..debf7ad766 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -180,14 +180,60 @@ def router_compare_json_output(rname, command, reference, tries): assert diff is None, assertmsg +def expect_grace_lsa(restarting, area, helper): + """ + Check if the given helper neighbor has already received a Grace-LSA from + the router performing a graceful restart. + """ + tgen = get_topogen() + + logger.info( + "'{}': checking if a Grace-LSA was received from '{}'".format( + helper, restarting + ) + ) + test_func = partial( + topotest.router_json_cmp, + tgen.gears[helper], + "show ip ospf database opaque-link json", + { + "linkLocalOpaqueLsa": { + "areas": { + area: [ + { + "advertisingRouter": restarting, + "opaqueType": "Grace-LSA", + } + ] + } + } + }, + ) + _, result = topotest.run_and_expect(test_func, None, count=60, wait=1) + assertmsg = '"{}" didn\'t receive a Grace-LSA from "{}"'.format(helper, restarting) + + assert result is None, assertmsg + + def check_routers(initial_convergence=False, exiting=None, restarting=None): for rname in ["rt1", "rt2", "rt3", "rt4", "rt5", "rt6", "rt7"]: # Check the RIB first, which should be preserved across restarts in # all routers of the routing domain. + # If we are not on initial convergence *but* we are checking + # after a restart. Looking in the zebra rib for installed + # is a recipe for test failure. Why? because if we are restarting + # then ospf is in the process of establishing neighbors and passing + # new routes to zebra. Zebra will not mark the route as installed + # when it receives a replacement from ospf until it has finished + # processing it. Let's give it a few seconds to allow this to happen + # under load. if initial_convergence == True: tries = 240 else: - tries = 1 + if restarting != None: + tries = 60 + else: + tries = 1 router_compare_json_output( rname, "show ip route ospf json", "show_ip_route.json", tries ) @@ -215,6 +261,26 @@ def check_routers(initial_convergence=False, exiting=None, restarting=None): ) +def ensure_gr_is_in_zebra(rname): + retry = True + retry_times = 10 + tgen = get_topogen() + + while retry and retry_times > 0: + out = tgen.net[rname].cmd( + 'vtysh -c "show zebra client" | grep "Client: ospf$" -A 40 | grep "Capabilities "' + ) + + if "Graceful Restart" not in out: + sleep(2) + retry_times -= 1 + else: + retry = False + + assertmsg = "%s does not appear to have Graceful Restart setup" % rname + assert not retry and retry_times > 0, assertmsg + + # # Test initial network convergence # @@ -241,7 +307,8 @@ def test_gr_rt1(): pytest.skip(tgen.errors) tgen.net["rt1"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + expect_grace_lsa(restarting="1.1.1.1", area="0.0.0.1", helper="rt2") + ensure_gr_is_in_zebra("rt1") kill_router_daemons(tgen, "rt1", ["ospfd"], save_config=False) check_routers(exiting="rt1") @@ -261,7 +328,9 @@ def test_gr_rt2(): pytest.skip(tgen.errors) tgen.net["rt2"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + expect_grace_lsa(restarting="2.2.2.2", area="0.0.0.1", helper="rt1") + expect_grace_lsa(restarting="2.2.2.2", area="0.0.0.0", helper="rt3") + ensure_gr_is_in_zebra("rt2") kill_router_daemons(tgen, "rt2", ["ospfd"], save_config=False) check_routers(exiting="rt2") @@ -281,7 +350,10 @@ def test_gr_rt3(): pytest.skip(tgen.errors) tgen.net["rt3"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + expect_grace_lsa(restarting="3.3.3.3", area="0.0.0.0", helper="rt2") + expect_grace_lsa(restarting="3.3.3.3", area="0.0.0.0", helper="rt4") + expect_grace_lsa(restarting="3.3.3.3", area="0.0.0.0", helper="rt6") + ensure_gr_is_in_zebra("rt3") kill_router_daemons(tgen, "rt3", ["ospfd"], save_config=False) check_routers(exiting="rt3") @@ -301,7 +373,9 @@ def test_gr_rt4(): pytest.skip(tgen.errors) tgen.net["rt4"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + expect_grace_lsa(restarting="4.4.4.4", area="0.0.0.0", helper="rt3") + expect_grace_lsa(restarting="4.4.4.4", area="0.0.0.2", helper="rt5") + ensure_gr_is_in_zebra("rt4") kill_router_daemons(tgen, "rt4", ["ospfd"], save_config=False) check_routers(exiting="rt4") @@ -321,7 +395,8 @@ def test_gr_rt5(): pytest.skip(tgen.errors) tgen.net["rt5"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + expect_grace_lsa(restarting="5.5.5.5", area="0.0.0.2", helper="rt4") + ensure_gr_is_in_zebra("rt5") kill_router_daemons(tgen, "rt5", ["ospfd"], save_config=False) check_routers(exiting="rt5") @@ -341,7 +416,9 @@ def test_gr_rt6(): pytest.skip(tgen.errors) tgen.net["rt6"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + expect_grace_lsa(restarting="6.6.6.6", area="0.0.0.0", helper="rt3") + expect_grace_lsa(restarting="6.6.6.6", area="0.0.0.3", helper="rt7") + ensure_gr_is_in_zebra("rt6") kill_router_daemons(tgen, "rt6", ["ospfd"], save_config=False) check_routers(exiting="rt6") @@ -361,7 +438,8 @@ def test_gr_rt7(): pytest.skip(tgen.errors) tgen.net["rt7"].cmd('vtysh -c "graceful-restart prepare ip ospf"') - sleep(3) + expect_grace_lsa(restarting="7.7.7.7", area="0.0.0.3", helper="rt6") + ensure_gr_is_in_zebra("rt7") kill_router_daemons(tgen, "rt7", ["ospfd"], save_config=False) check_routers(exiting="rt7") diff --git a/tests/topotests/ospf_sr_te_topo1/dst/zebra.conf b/tests/topotests/ospf_sr_te_topo1/dst/zebra.conf index 4cb50fdb27..fbe55e53a4 100644 --- a/tests/topotests/ospf_sr_te_topo1/dst/zebra.conf +++ b/tests/topotests/ospf_sr_te_topo1/dst/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname dst ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 9.9.9.2/32 diff --git a/tests/topotests/ospf_sr_te_topo1/rt1/ospfd.conf b/tests/topotests/ospf_sr_te_topo1/rt1/ospfd.conf index 225ac93528..a440fa6fdf 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt1/ospfd.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt1/ospfd.conf @@ -2,11 +2,11 @@ password 1 hostname rt1 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/ospf_sr_te_topo1/rt1/zebra.conf b/tests/topotests/ospf_sr_te_topo1/rt1/zebra.conf index dd686ea3da..6b282b110b 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt1/zebra.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt1/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ospf_sr_te_topo1/rt2/ospfd.conf b/tests/topotests/ospf_sr_te_topo1/rt2/ospfd.conf index f6a7bbb621..7bec98cd76 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt2/ospfd.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt2/ospfd.conf @@ -1,11 +1,11 @@ hostname rt2 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/ospf_sr_te_topo1/rt2/zebra.conf b/tests/topotests/ospf_sr_te_topo1/rt2/zebra.conf index ddd50ba520..24795c2618 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt2/zebra.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt2/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/ospf_sr_te_topo1/rt3/ospfd.conf b/tests/topotests/ospf_sr_te_topo1/rt3/ospfd.conf index 5f71cd8484..40b85c4601 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt3/ospfd.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt3/ospfd.conf @@ -1,11 +1,11 @@ hostname rt3 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/ospf_sr_te_topo1/rt3/zebra.conf b/tests/topotests/ospf_sr_te_topo1/rt3/zebra.conf index 0825b5c8bf..353c710bdb 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt3/zebra.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt3/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/ospf_sr_te_topo1/rt4/ospfd.conf b/tests/topotests/ospf_sr_te_topo1/rt4/ospfd.conf index d4862cd233..4d3380d107 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt4/ospfd.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt4/ospfd.conf @@ -1,11 +1,11 @@ hostname rt4 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/ospf_sr_te_topo1/rt4/zebra.conf b/tests/topotests/ospf_sr_te_topo1/rt4/zebra.conf index c6d1f4f40e..966eb725a1 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt4/zebra.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt4/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/ospf_sr_te_topo1/rt5/ospfd.conf b/tests/topotests/ospf_sr_te_topo1/rt5/ospfd.conf index fdc0dcfdb7..b111ce588a 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt5/ospfd.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt5/ospfd.conf @@ -1,11 +1,11 @@ hostname rt5 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/ospf_sr_te_topo1/rt5/zebra.conf b/tests/topotests/ospf_sr_te_topo1/rt5/zebra.conf index 96b732d398..3184f1d778 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt5/zebra.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt5/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/ospf_sr_te_topo1/rt6/ospfd.conf b/tests/topotests/ospf_sr_te_topo1/rt6/ospfd.conf index c06565be0b..f0c5a9c0ba 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt6/ospfd.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt6/ospfd.conf @@ -1,11 +1,11 @@ hostname rt6 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ip ospf area 0.0.0.0 diff --git a/tests/topotests/ospf_sr_te_topo1/rt6/zebra.conf b/tests/topotests/ospf_sr_te_topo1/rt6/zebra.conf index 360837c4ca..c556aa3681 100644 --- a/tests/topotests/ospf_sr_te_topo1/rt6/zebra.conf +++ b/tests/topotests/ospf_sr_te_topo1/rt6/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt6 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 6.6.6.6/32 diff --git a/tests/topotests/ospf_sr_topo1/rt1/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt1/ospfd.conf index 6a12ae5011..be9abf6238 100644 --- a/tests/topotests/ospf_sr_topo1/rt1/ospfd.conf +++ b/tests/topotests/ospf_sr_topo1/rt1/ospfd.conf @@ -2,11 +2,11 @@ password 1 hostname rt1 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ! diff --git a/tests/topotests/ospf_sr_topo1/rt1/zebra.conf b/tests/topotests/ospf_sr_topo1/rt1/zebra.conf index 7d3139a80e..520f2e4994 100644 --- a/tests/topotests/ospf_sr_topo1/rt1/zebra.conf +++ b/tests/topotests/ospf_sr_topo1/rt1/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt1 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 1.1.1.1/32 diff --git a/tests/topotests/ospf_sr_topo1/rt2/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt2/ospfd.conf index adf4d09235..30ef12a79e 100644 --- a/tests/topotests/ospf_sr_topo1/rt2/ospfd.conf +++ b/tests/topotests/ospf_sr_topo1/rt2/ospfd.conf @@ -2,11 +2,11 @@ password 1 hostname rt2 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ! diff --git a/tests/topotests/ospf_sr_topo1/rt2/zebra.conf b/tests/topotests/ospf_sr_topo1/rt2/zebra.conf index c4ed4276d9..fbf805cdac 100644 --- a/tests/topotests/ospf_sr_topo1/rt2/zebra.conf +++ b/tests/topotests/ospf_sr_topo1/rt2/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt2 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 2.2.2.2/32 diff --git a/tests/topotests/ospf_sr_topo1/rt3/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt3/ospfd.conf index c45c1069fb..e315679765 100644 --- a/tests/topotests/ospf_sr_topo1/rt3/ospfd.conf +++ b/tests/topotests/ospf_sr_topo1/rt3/ospfd.conf @@ -2,11 +2,11 @@ password 1 hostname rt3 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ! diff --git a/tests/topotests/ospf_sr_topo1/rt3/zebra.conf b/tests/topotests/ospf_sr_topo1/rt3/zebra.conf index 89a781fe3c..fc9db060e9 100644 --- a/tests/topotests/ospf_sr_topo1/rt3/zebra.conf +++ b/tests/topotests/ospf_sr_topo1/rt3/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt3 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 3.3.3.3/32 diff --git a/tests/topotests/ospf_sr_topo1/rt4/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt4/ospfd.conf index 9853ce64cf..681aaa3a8c 100644 --- a/tests/topotests/ospf_sr_topo1/rt4/ospfd.conf +++ b/tests/topotests/ospf_sr_topo1/rt4/ospfd.conf @@ -2,11 +2,11 @@ password 1 hostname rt4 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ! diff --git a/tests/topotests/ospf_sr_topo1/rt4/zebra.conf b/tests/topotests/ospf_sr_topo1/rt4/zebra.conf index 13c621eb31..d794837eb7 100644 --- a/tests/topotests/ospf_sr_topo1/rt4/zebra.conf +++ b/tests/topotests/ospf_sr_topo1/rt4/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt4 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 4.4.4.4/32 diff --git a/tests/topotests/ospf_sr_topo1/rt5/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt5/ospfd.conf index e6a755c430..0b441c70de 100644 --- a/tests/topotests/ospf_sr_topo1/rt5/ospfd.conf +++ b/tests/topotests/ospf_sr_topo1/rt5/ospfd.conf @@ -2,11 +2,11 @@ password 1 hostname rt5 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ! diff --git a/tests/topotests/ospf_sr_topo1/rt5/zebra.conf b/tests/topotests/ospf_sr_topo1/rt5/zebra.conf index ca2d6df665..09923f28e9 100644 --- a/tests/topotests/ospf_sr_topo1/rt5/zebra.conf +++ b/tests/topotests/ospf_sr_topo1/rt5/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt5 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 5.5.5.5/32 diff --git a/tests/topotests/ospf_sr_topo1/rt6/ospfd.conf b/tests/topotests/ospf_sr_topo1/rt6/ospfd.conf index 1ec71e4454..7bb5de9440 100644 --- a/tests/topotests/ospf_sr_topo1/rt6/ospfd.conf +++ b/tests/topotests/ospf_sr_topo1/rt6/ospfd.conf @@ -2,11 +2,11 @@ password 1 hostname rt6 log file ospfd.log ! -debug ospf sr -debug ospf te -debug ospf event -debug ospf lsa -debug ospf zebra +! debug ospf sr +! debug ospf te +! debug ospf event +! debug ospf lsa +! debug ospf zebra ! interface lo ! diff --git a/tests/topotests/ospf_sr_topo1/rt6/zebra.conf b/tests/topotests/ospf_sr_topo1/rt6/zebra.conf index 4b739d0bca..1452560065 100644 --- a/tests/topotests/ospf_sr_topo1/rt6/zebra.conf +++ b/tests/topotests/ospf_sr_topo1/rt6/zebra.conf @@ -2,9 +2,9 @@ log file zebra.log ! hostname rt6 ! -debug zebra kernel -debug zebra packet -debug zebra mpls +! debug zebra kernel +! debug zebra packet +! debug zebra mpls ! interface lo ip address 6.6.6.6/32 diff --git a/tests/topotests/ospf_tilfa_topo1/rt1/ospfd.conf b/tests/topotests/ospf_tilfa_topo1/rt1/ospfd.conf index eaef49225f..04b2c381e2 100644 --- a/tests/topotests/ospf_tilfa_topo1/rt1/ospfd.conf +++ b/tests/topotests/ospf_tilfa_topo1/rt1/ospfd.conf @@ -1,5 +1,5 @@ -debug ospf sr -debug ospf ti-lfa +! debug ospf sr +! debug ospf ti-lfa ! interface lo ! diff --git a/tests/topotests/ospf_tilfa_topo1/rt2/ospfd.conf b/tests/topotests/ospf_tilfa_topo1/rt2/ospfd.conf index 7548aad7f8..e6e4847ba7 100644 --- a/tests/topotests/ospf_tilfa_topo1/rt2/ospfd.conf +++ b/tests/topotests/ospf_tilfa_topo1/rt2/ospfd.conf @@ -1,5 +1,5 @@ -debug ospf sr -debug ospf ti-lfa +! debug ospf sr +! debug ospf ti-lfa ! interface lo ! diff --git a/tests/topotests/ospf_tilfa_topo1/rt3/ospfd.conf b/tests/topotests/ospf_tilfa_topo1/rt3/ospfd.conf index 6258295b6f..472cdc6bcb 100644 --- a/tests/topotests/ospf_tilfa_topo1/rt3/ospfd.conf +++ b/tests/topotests/ospf_tilfa_topo1/rt3/ospfd.conf @@ -1,5 +1,5 @@ -debug ospf sr -debug ospf ti-lfa +! debug ospf sr +! debug ospf ti-lfa ! interface lo ! diff --git a/tests/topotests/ospf_tilfa_topo1/rt4/ospfd.conf b/tests/topotests/ospf_tilfa_topo1/rt4/ospfd.conf index ad02214017..75770dc5dd 100644 --- a/tests/topotests/ospf_tilfa_topo1/rt4/ospfd.conf +++ b/tests/topotests/ospf_tilfa_topo1/rt4/ospfd.conf @@ -1,5 +1,5 @@ -debug ospf sr -debug ospf ti-lfa +! debug ospf sr +! debug ospf ti-lfa ! interface lo ! diff --git a/tests/topotests/ospf_tilfa_topo1/rt5/ospfd.conf b/tests/topotests/ospf_tilfa_topo1/rt5/ospfd.conf index 1b95858f53..ef9d583ae9 100644 --- a/tests/topotests/ospf_tilfa_topo1/rt5/ospfd.conf +++ b/tests/topotests/ospf_tilfa_topo1/rt5/ospfd.conf @@ -1,5 +1,5 @@ -debug ospf sr -debug ospf ti-lfa +! debug ospf sr +! debug ospf ti-lfa ! interface lo ! diff --git a/tests/topotests/ospf_topo1/test_ospf_topo1.py b/tests/topotests/ospf_topo1/test_ospf_topo1.py index d84c41bea3..e2a6ff64a4 100644 --- a/tests/topotests/ospf_topo1/test_ospf_topo1.py +++ b/tests/topotests/ospf_topo1/test_ospf_topo1.py @@ -30,6 +30,7 @@ import os import re import sys from functools import partial +from time import sleep import pytest # Save the Current Working Directory to find configuration files. @@ -135,7 +136,7 @@ def test_wait_protocol_convergence(): ) if ( topotest.json_cmp( - result, {"neighbors": {neighbor: [{"state": "Full/DR"}]}} + result, {"neighbors": {neighbor: [{"converged": "Full"}]}} ) is None ): @@ -143,14 +144,14 @@ def test_wait_protocol_convergence(): if ( topotest.json_cmp( - result, {"neighbors": {neighbor: [{"state": "Full/DROther"}]}} + result, {"neighbors": {neighbor: [{"converged": "Full"}]}} ) is None ): return None return topotest.json_cmp( - result, {"neighbors": {neighbor: [{"state": "Full/Backup"}]}} + result, {"neighbors": {neighbor: [{"converged": "Full"}]}} ) _, result = topotest.run_and_expect( @@ -475,7 +476,18 @@ def test_ospf_link_down_kernel_route(): assertmsg = 'OSPF IPv4 route mismatch in router "{}" after link down'.format( router.name ) - assert topotest.json_cmp(routes, expected) is None, assertmsg + count = 0 + not_found = True + while not_found and count < 10: + not_found = topotest.json_cmp(routes, expected) + if not_found: + sleep(1) + routes = topotest.ip4_route(router) + count += 1 + else: + not_found = False + break + assert not_found is False, assertmsg def test_ospf6_link_down(): @@ -547,7 +559,19 @@ def test_ospf6_link_down_kernel_route(): assertmsg = 'OSPF IPv6 route mismatch in router "{}" after link down'.format( router.name ) - assert topotest.json_cmp(routes, expected) is None, assertmsg + count = 0 + not_found = True + while not_found and count < 10: + not_found = topotest.json_cmp(routes, expected) + if not_found: + sleep(1) + routes = topotest.ip6_route(router) + count += 1 + else: + not_found = False + break + + assert not_found is False, assertmsg def test_memory_leak(): diff --git a/tests/topotests/ospf_topo1_vrf/r1/zebra.conf b/tests/topotests/ospf_topo1_vrf/r1/zebra.conf index e100d3b121..56d7a9764e 100644 --- a/tests/topotests/ospf_topo1_vrf/r1/zebra.conf +++ b/tests/topotests/ospf_topo1_vrf/r1/zebra.conf @@ -1,7 +1,7 @@ -debug zebra kernel -debug zebra dplane detail -debug zebra rib -debug zebra event +! debug zebra kernel +! debug zebra dplane detail +! debug zebra rib +! debug zebra event ! hostname r1 password zebra diff --git a/tests/topotests/ospfv3_basic_functionality/ospfv3_nssa.json b/tests/topotests/ospfv3_basic_functionality/ospfv3_nssa.json new file mode 100644 index 0000000000..2b91abc9e3 --- /dev/null +++ b/tests/topotests/ospfv3_basic_functionality/ospfv3_nssa.json @@ -0,0 +1,86 @@ +{ + "address_types": [ + "ipv6" + ], + "lo_prefix": { + "ipv6": "2001::", + "v6mask": 128 + }, + "routers": { + "r1": { + "links": { + "lo": { + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv6": "12::1/64", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "1.1.1.1", + "neighbors": { + "r2": {} + } + } + }, + "r2": { + "links": { + "lo": { + "ipv6": "auto", + "type": "loopback" + }, + "r1": { + "ipv6": "12::2/64", + "ospf6": { + "area": "0.0.0.0", + "hello_interval": 1, + "dead_interval": 4 + } + }, + "r3": { + "ipv6": "23::2/64", + "ospf6": { + "area": "1.1.1.1", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "2.2.2.2", + "neighbors": { + "r1": {}, + "r3": {} + } + } + }, + "r3": { + "links": { + "lo": { + "ipv6": "auto", + "type": "loopback" + }, + "r2": { + "ipv6": "23::3/64", + "ospf6": { + "area": "1.1.1.1", + "hello_interval": 1, + "dead_interval": 4 + } + } + }, + "ospf6": { + "router_id": "3.3.3.3", + "neighbors": { + "r2": {} + } + } + } + } +} diff --git a/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py new file mode 100644 index 0000000000..64a067cd1a --- /dev/null +++ b/tests/topotests/ospfv3_basic_functionality/test_ospfv3_nssa.py @@ -0,0 +1,162 @@ +#!/usr/bin/python + +from lib.topogen import Topogen, get_topogen +from lib.common_config import ( + start_topology, + write_test_header, + write_test_footer, + reset_config_on_routers, + step, + topo_daemons, +) +from lib.topolog import logger +from lib.topojson import build_config_from_json +from lib.ospf import create_router_ospf, verify_ospf6_neighbor +import os +import sys +import time +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, "../")) +sys.path.append(os.path.join(CWD, "../lib/")) + +# pylint: disable=C0413 + +pytestmark = [pytest.mark.ospfd] + + +# Global variables +topo = None + +""" +TOPOOLOGY + + +---+ 0.0.0.0 +---+ 1.1.1.1 +---+ + +R1 +------------+R2 |------------+R3 | + +-+-+ +--++ +--++ + +TESTCASES = +1. OSPF Verify E-bit mismatch between R2 and R3 +2. OSPF Verify N-bit mismatch between R2 and R3 +""" + + +def setup_module(mod): + """ + Sets up the pytest environment + + * `mod`: module name + """ + testsuite_run_time = time.asctime(time.localtime(time.time())) + logger.info("Testsuite start time: {}".format(testsuite_run_time)) + logger.info("=" * 40) + + logger.info("Running setup_module to create topology") + + # This function initiates the topology build with Topogen... + json_file = "{}/ospfv3_nssa.json".format(CWD) + tgen = Topogen(json_file, mod.__name__) + global topo + topo = tgen.json_topo + # ... and here it calls Mininet initialization functions. + + # get list of daemons needs to be started for this suite. + daemons = topo_daemons(tgen, topo) + + # Starting topology, create tmp files which are loaded to routers + # to start deamons and then start routers + start_topology(tgen, daemons) + + # Creating configuration from JSON + build_config_from_json(tgen, topo) + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + result = verify_ospf6_neighbor(tgen, topo) + assert result is True, "setup_module: Failed \n Error:" " {}".format(result) + + logger.info("Running setup_module() done") + + +def teardown_module(mod): + """ + Teardown the pytest environment. + + * `mod`: module name + """ + + logger.info("Running teardown_module to delete topology") + + tgen = get_topogen() + + # Stop toplogy and Remove tmp files + tgen.stop_topology() + + logger.info( + "Testsuite end time: {}".format(time.asctime(time.localtime(time.time()))) + ) + logger.info("=" * 40) + + +# ################################## +# Test cases start here. +# ################################## + + +def test_ospfv3_bit_mismatch(request): + """OSPF verify E-bit and N-bit mismatch.""" + + tc_name = request.node.name + write_test_header(tc_name) + tgen = get_topogen() + + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + global topo + step("Bring up the base config as per the topology") + reset_config_on_routers(tgen) + + input_dict = {"r3": {"ospf6": {"neighbors": []}}} + + step("Configure r3 as stub router") + stub = {"r3": {"ospf6": {"area": [{"id": "1.1.1.1", "type": "stub"}]}}} + result = create_router_ospf(tgen, topo, stub) + assert result is True, "Testcase {}: Failed \n Error: {}".format(tc_name, result) + # Verify r3 lost its adjacency with r2 due to E-bit mismatch + result = verify_ospf6_neighbor(tgen, topo, dut="r3", input_dict=input_dict) + assert result is True, "Testcase {}: Failed \n Error: {}".format(tc_name, result) + + step("Configure r2 as stub router") + stub = {"r2": {"ospf6": {"area": [{"id": "1.1.1.1", "type": "stub"}]}}} + result = create_router_ospf(tgen, topo, stub) + assert result is True, "Testcase {}: Failed \n Error: {}".format(tc_name, result) + # Verify r3 has an adjacency up with r2 again + result = verify_ospf6_neighbor(tgen, topo, dut="r3") + assert result is True, "Testcase {}: Failed \n Error: {}".format(tc_name, result) + + step("Configure r3 as NSSA router") + nssa = {"r3": {"ospf6": {"area": [{"id": "1.1.1.1", "type": "nssa"}]}}} + result = create_router_ospf(tgen, topo, nssa) + # Verify r3 lost its adjacency with r2 due to N-bit mismatch + result = verify_ospf6_neighbor(tgen, topo, dut="r3", input_dict=input_dict) + assert result is True, "Testcase {}: Failed \n Error: {}".format(tc_name, result) + + step("Configure r2 as NSSA router") + nssa = {"r2": {"ospf6": {"area": [{"id": "1.1.1.1", "type": "nssa"}]}}} + result = create_router_ospf(tgen, topo, nssa) + # Verify r3 has an adjacency up with r2 again + result = verify_ospf6_neighbor(tgen, topo, dut="r3") + assert result is True, "Testcase {}: Failed \n Error: {}".format(tc_name, result) + + write_test_footer(tc_name) + + +if __name__ == "__main__": + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/pbr_topo1/r1/pbrd.conf b/tests/topotests/pbr_topo1/r1/pbrd.conf index 45cb7656ab..2a5f464780 100644 --- a/tests/topotests/pbr_topo1/r1/pbrd.conf +++ b/tests/topotests/pbr_topo1/r1/pbrd.conf @@ -1,7 +1,7 @@ -debug pbr -debug pbr events -debug pbr nht -debug pbr zebra +! debug pbr +! debug pbr events +! debug pbr nht +! debug pbr zebra # Valid table range pbr table range 10000 50000 # Try to set invalid bounds diff --git a/tests/topotests/pim_acl/r1/ospf_neighbor.json b/tests/topotests/pim_acl/r1/ospf_neighbor.json index a8fc093e90..af83d6bea3 100644 --- a/tests/topotests/pim_acl/r1/ospf_neighbor.json +++ b/tests/topotests/pim_acl/r1/ospf_neighbor.json @@ -3,7 +3,7 @@ "192.168.0.11":[ { "priority":10, - "state":"Full\/Backup", + "converged":"Full", "address":"192.168.101.11", "ifaceName":"r1-eth1:192.168.101.1", "retransmitCounter":0, @@ -14,7 +14,7 @@ "192.168.0.12":[ { "priority":0, - "state":"Full\/DROther", + "converged":"Full", "address":"192.168.101.12", "ifaceName":"r1-eth1:192.168.101.1", "retransmitCounter":0, @@ -25,7 +25,7 @@ "192.168.0.13":[ { "priority":0, - "state":"Full\/DROther", + "converged":"Full", "address":"192.168.101.13", "ifaceName":"r1-eth1:192.168.101.1", "retransmitCounter":0, @@ -36,7 +36,7 @@ "192.168.0.14":[ { "priority":0, - "state":"Full\/DROther", + "converged":"Full", "address":"192.168.101.14", "ifaceName":"r1-eth1:192.168.101.1", "retransmitCounter":0, @@ -47,7 +47,7 @@ "192.168.0.15":[ { "priority":0, - "state":"Full\/DROther", + "converged":"Full", "address":"192.168.101.15", "ifaceName":"r1-eth1:192.168.101.1", "retransmitCounter":0, diff --git a/tests/topotests/pim_acl/r1/ospfd.conf b/tests/topotests/pim_acl/r1/ospfd.conf index e1f47fb3b1..c453dec96c 100644 --- a/tests/topotests/pim_acl/r1/ospfd.conf +++ b/tests/topotests/pim_acl/r1/ospfd.conf @@ -1,6 +1,6 @@ hostname r1 ! -debug ospf event +! debug ospf event ! interface r1-eth1 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_acl/r1/pimd.conf b/tests/topotests/pim_acl/r1/pimd.conf index a148c73146..5bdfbea72a 100644 --- a/tests/topotests/pim_acl/r1/pimd.conf +++ b/tests/topotests/pim_acl/r1/pimd.conf @@ -1,12 +1,12 @@ hostname r1 ! -debug igmp events -debug igmp packets -debug pim events -debug pim packets -debug pim trace -debug pim zebra -debug pim bsm +! debug igmp events +! debug igmp packets +! debug pim events +! debug pim packets +! debug pim trace +! debug pim zebra +! debug pim bsm ! ip pim rp 192.168.0.11 prefix-list rp-pl-1 ip pim rp 192.168.0.12 prefix-list rp-pl-2 diff --git a/tests/topotests/pim_acl/r11/ospfd.conf b/tests/topotests/pim_acl/r11/ospfd.conf index e107220a4e..86fb66db61 100644 --- a/tests/topotests/pim_acl/r11/ospfd.conf +++ b/tests/topotests/pim_acl/r11/ospfd.conf @@ -1,6 +1,6 @@ hostname r11 ! -debug ospf event +! debug ospf event ! interface r11-eth0 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_acl/r11/pimd.conf b/tests/topotests/pim_acl/r11/pimd.conf index b1d45205da..3e409ddd31 100644 --- a/tests/topotests/pim_acl/r11/pimd.conf +++ b/tests/topotests/pim_acl/r11/pimd.conf @@ -1,10 +1,10 @@ hostname r11 ! -debug pim events -debug pim packets -debug pim trace -debug pim zebra -debug pim bsm +! debug pim events +! debug pim packets +! debug pim trace +! debug pim zebra +! debug pim bsm ! ip pim rp 192.168.0.11 239.100.0.0/28 ip pim join-prune-interval 5 diff --git a/tests/topotests/pim_acl/r12/ospfd.conf b/tests/topotests/pim_acl/r12/ospfd.conf index f9203c78e4..1110df18b4 100644 --- a/tests/topotests/pim_acl/r12/ospfd.conf +++ b/tests/topotests/pim_acl/r12/ospfd.conf @@ -1,6 +1,6 @@ hostname r12 ! -debug ospf event +! debug ospf event ! interface r12-eth0 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_acl/r12/pimd.conf b/tests/topotests/pim_acl/r12/pimd.conf index ba9e7d902f..2fc853bc04 100644 --- a/tests/topotests/pim_acl/r12/pimd.conf +++ b/tests/topotests/pim_acl/r12/pimd.conf @@ -1,10 +1,10 @@ hostname r12 ! -debug pim events -debug pim packets -debug pim trace -debug pim zebra -debug pim bsm +! debug pim events +! debug pim packets +! debug pim trace +! debug pim zebra +! debug pim bsm ! ip pim rp 192.168.0.12 239.100.0.17/32 ip pim join-prune-interval 5 diff --git a/tests/topotests/pim_acl/r13/ospfd.conf b/tests/topotests/pim_acl/r13/ospfd.conf index 830c5a14b6..aff24c7038 100644 --- a/tests/topotests/pim_acl/r13/ospfd.conf +++ b/tests/topotests/pim_acl/r13/ospfd.conf @@ -1,6 +1,6 @@ hostname r13 ! -debug ospf event +! debug ospf event ! interface r13-eth0 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_acl/r13/pimd.conf b/tests/topotests/pim_acl/r13/pimd.conf index 2ff1743574..5e44879306 100644 --- a/tests/topotests/pim_acl/r13/pimd.conf +++ b/tests/topotests/pim_acl/r13/pimd.conf @@ -1,10 +1,10 @@ hostname r13 ! -debug pim events -debug pim packets -debug pim trace -debug pim zebra -debug pim bsm +! debug pim events +! debug pim packets +! debug pim trace +! debug pim zebra +! debug pim bsm ! ip pim rp 192.168.0.13 239.100.0.32/27 ip pim join-prune-interval 5 diff --git a/tests/topotests/pim_acl/r14/ospfd.conf b/tests/topotests/pim_acl/r14/ospfd.conf index 422e4c08b0..e5cf8e2567 100644 --- a/tests/topotests/pim_acl/r14/ospfd.conf +++ b/tests/topotests/pim_acl/r14/ospfd.conf @@ -1,6 +1,6 @@ hostname r14 ! -debug ospf event +! debug ospf event ! interface r14-eth0 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_acl/r14/pimd.conf b/tests/topotests/pim_acl/r14/pimd.conf index 1324a9e40b..42beb2ab08 100644 --- a/tests/topotests/pim_acl/r14/pimd.conf +++ b/tests/topotests/pim_acl/r14/pimd.conf @@ -1,10 +1,10 @@ hostname r14 ! -debug pim events -debug pim packets -debug pim trace -debug pim zebra -debug pim bsm +! debug pim events +! debug pim packets +! debug pim trace +! debug pim zebra +! debug pim bsm ! ip pim rp 192.168.0.14 239.100.0.96/28 ip pim rp 192.168.0.14 239.100.0.128/25 diff --git a/tests/topotests/pim_acl/r15/ospfd.conf b/tests/topotests/pim_acl/r15/ospfd.conf index cd4d7b3875..cc58325e2b 100644 --- a/tests/topotests/pim_acl/r15/ospfd.conf +++ b/tests/topotests/pim_acl/r15/ospfd.conf @@ -1,6 +1,6 @@ hostname r15 ! -debug ospf event +! debug ospf event ! interface r15-eth0 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_acl/r15/pimd.conf b/tests/topotests/pim_acl/r15/pimd.conf index f47e78c221..d5a0450067 100644 --- a/tests/topotests/pim_acl/r15/pimd.conf +++ b/tests/topotests/pim_acl/r15/pimd.conf @@ -1,10 +1,10 @@ hostname r15 ! -debug pim events -debug pim packets -debug pim trace -debug pim zebra -debug pim bsm +! debug pim events +! debug pim packets +! debug pim trace +! debug pim zebra +! debug pim bsm ! ip pim rp 192.168.0.15 239.100.0.64/28 ip pim join-prune-interval 5 diff --git a/tests/topotests/pim_basic/mcast-rx.py b/tests/topotests/pim_basic/mcast-rx.py index 862ad46af4..885337666a 100755 --- a/tests/topotests/pim_basic/mcast-rx.py +++ b/tests/topotests/pim_basic/mcast-rx.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # mcast-rx.py # diff --git a/tests/topotests/pim_basic/mcast-tx.py b/tests/topotests/pim_basic/mcast-tx.py index 87038ad5cf..88c234573f 100755 --- a/tests/topotests/pim_basic/mcast-tx.py +++ b/tests/topotests/pim_basic/mcast-tx.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # # mcast-tx.py # diff --git a/tests/topotests/pim_basic/test_pim.py b/tests/topotests/pim_basic/test_pim.py index 03b4368e42..6cea521aa9 100644 --- a/tests/topotests/pim_basic/test_pim.py +++ b/tests/topotests/pim_basic/test_pim.py @@ -172,7 +172,11 @@ def test_pim_send_mcast_stream(): } } - assert topotest.json_cmp(out, expected) is None, "failed to converge pim" + test_func = partial( + topotest.router_json_cmp, r1, "show ip pim upstream json", expected + ) + _, result = topotest.run_and_expect(test_func, None, count=20, wait=1) + assert result is None, "failed to converge pim" # tgen.mininet_cli() diff --git a/tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json index 604d25fac1..1e70fcc36e 100644 --- a/tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json +++ b/tests/topotests/pim_igmp_vrf/r1/ospf_blue_neighbor.json @@ -5,7 +5,7 @@ "192.168.0.11":[ { "priority":10, - "state":"Full\/Backup", + "converged":"Full", "address":"192.168.101.11", "ifaceName":"r1-eth1:192.168.101.1" } diff --git a/tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json b/tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json index 456bb87520..7f2ab248cc 100644 --- a/tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json +++ b/tests/topotests/pim_igmp_vrf/r1/ospf_red_neighbor.json @@ -5,7 +5,7 @@ "192.168.0.12":[ { "priority":10, - "state":"Full\/Backup", + "converged":"Full", "address":"192.168.101.12", "ifaceName":"r1-eth3:192.168.101.1" } diff --git a/tests/topotests/pim_igmp_vrf/r1/ospfd.conf b/tests/topotests/pim_igmp_vrf/r1/ospfd.conf index 263b5867cc..88eb5a8a05 100644 --- a/tests/topotests/pim_igmp_vrf/r1/ospfd.conf +++ b/tests/topotests/pim_igmp_vrf/r1/ospfd.conf @@ -1,6 +1,6 @@ hostname r1 ! -debug ospf event +! debug ospf event ! ! interface r1-eth1 diff --git a/tests/topotests/pim_igmp_vrf/r1/pimd.conf b/tests/topotests/pim_igmp_vrf/r1/pimd.conf index f04c255de9..040c3d01b1 100644 --- a/tests/topotests/pim_igmp_vrf/r1/pimd.conf +++ b/tests/topotests/pim_igmp_vrf/r1/pimd.conf @@ -1,12 +1,12 @@ hostname r1 ! -debug igmp events -debug igmp packets -debug pim events -debug pim packets -debug pim trace -debug pim zebra -debug pim bsm +! debug igmp events +! debug igmp packets +! debug pim events +! debug pim packets +! debug pim trace +! debug pim zebra +! debug pim bsm ! interface r1-eth0 ip igmp diff --git a/tests/topotests/pim_igmp_vrf/r11/ospfd.conf b/tests/topotests/pim_igmp_vrf/r11/ospfd.conf index e107220a4e..86fb66db61 100644 --- a/tests/topotests/pim_igmp_vrf/r11/ospfd.conf +++ b/tests/topotests/pim_igmp_vrf/r11/ospfd.conf @@ -1,6 +1,6 @@ hostname r11 ! -debug ospf event +! debug ospf event ! interface r11-eth0 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_igmp_vrf/r11/pimd.conf b/tests/topotests/pim_igmp_vrf/r11/pimd.conf index b1d45205da..3e409ddd31 100644 --- a/tests/topotests/pim_igmp_vrf/r11/pimd.conf +++ b/tests/topotests/pim_igmp_vrf/r11/pimd.conf @@ -1,10 +1,10 @@ hostname r11 ! -debug pim events -debug pim packets -debug pim trace -debug pim zebra -debug pim bsm +! debug pim events +! debug pim packets +! debug pim trace +! debug pim zebra +! debug pim bsm ! ip pim rp 192.168.0.11 239.100.0.0/28 ip pim join-prune-interval 5 diff --git a/tests/topotests/pim_igmp_vrf/r12/ospfd.conf b/tests/topotests/pim_igmp_vrf/r12/ospfd.conf index 03acc82c1d..f0dcabece2 100644 --- a/tests/topotests/pim_igmp_vrf/r12/ospfd.conf +++ b/tests/topotests/pim_igmp_vrf/r12/ospfd.conf @@ -1,6 +1,6 @@ hostname r12 ! -debug ospf event +! debug ospf event ! interface r12-eth0 ip ospf hello-interval 2 diff --git a/tests/topotests/pim_igmp_vrf/r12/pimd.conf b/tests/topotests/pim_igmp_vrf/r12/pimd.conf index 5cb76efa22..2c308f7818 100644 --- a/tests/topotests/pim_igmp_vrf/r12/pimd.conf +++ b/tests/topotests/pim_igmp_vrf/r12/pimd.conf @@ -1,10 +1,10 @@ hostname r12 ! -debug pim events -debug pim packets -debug pim trace -debug pim zebra -debug pim bsm +! debug pim events +! debug pim packets +! debug pim trace +! debug pim zebra +! debug pim bsm ! ip pim rp 192.168.0.12 239.100.0.0/28 ip pim join-prune-interval 5 diff --git a/tests/topotests/pytest.ini b/tests/topotests/pytest.ini index 33c5635eb2..7dd13935b1 100644 --- a/tests/topotests/pytest.ini +++ b/tests/topotests/pytest.ini @@ -81,4 +81,3 @@ markers = # memleak_path = /tmp/memleak_ # Output files will be named after the testname: # /tmp/memleak_test_ospf_topo1.txt -memleak_path = /tmp/memleak_ diff --git a/tests/topotests/rip_topo1/test_rip_topo1.py b/tests/topotests/rip_topo1/test_rip_topo1.py index c5812f28cf..7d59e8422f 100644 --- a/tests/topotests/rip_topo1/test_rip_topo1.py +++ b/tests/topotests/rip_topo1/test_rip_topo1.py @@ -108,7 +108,7 @@ def setup_module(module): tgen.gears["r%s" % i].start() # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) + # tgen.mininet_cli() def teardown_module(module): @@ -134,9 +134,6 @@ def test_router_running(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_converge_protocols(): global fatal_error @@ -159,9 +156,6 @@ def test_converge_protocols(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_rip_status(): global fatal_error @@ -220,9 +214,6 @@ def test_rip_status(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_rip_routes(): global fatal_error @@ -275,9 +266,6 @@ def test_rip_routes(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_zebra_ipv4_routingTable(): global fatal_error @@ -341,9 +329,6 @@ def test_zebra_ipv4_routingTable(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_shutdown_check_stderr(): global fatal_error diff --git a/tests/topotests/ripng_topo1/r1/ripng_status.ref b/tests/topotests/ripng_topo1/r1/ripng_status.ref index b02cc69d0e..d92ae054cf 100644 --- a/tests/topotests/ripng_topo1/r1/ripng_status.ref +++ b/tests/topotests/ripng_topo1/r1/ripng_status.ref @@ -1,5 +1,5 @@ Routing Protocol is "RIPng" - Sending updates every 5 seconds with +/-50%, next due in XX seconds + Sending updates every 1 seconds with +/-50%, next due in XX seconds Timeout after 180 seconds, garbage collect after 5 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set diff --git a/tests/topotests/ripng_topo1/r1/ripngd.conf b/tests/topotests/ripng_topo1/r1/ripngd.conf index 07ed7296d9..f96297b927 100644 --- a/tests/topotests/ripng_topo1/r1/ripngd.conf +++ b/tests/topotests/ripng_topo1/r1/ripngd.conf @@ -1,11 +1,11 @@ log file ripngd.log ! -debug ripng events -debug ripng packet -debug ripng zebra +! debug ripng events +! debug ripng packet +! debug ripng zebra ! router ripng - timers basic 5 180 5 + timers basic 1 180 5 network fc00:5::/64 network r1-eth2 network r1-eth3 diff --git a/tests/topotests/ripng_topo1/r2/ripng_status.ref b/tests/topotests/ripng_topo1/r2/ripng_status.ref index 640df9a4a0..de14b12ca4 100644 --- a/tests/topotests/ripng_topo1/r2/ripng_status.ref +++ b/tests/topotests/ripng_topo1/r2/ripng_status.ref @@ -1,5 +1,5 @@ Routing Protocol is "RIPng" - Sending updates every 5 seconds with +/-50%, next due in XX seconds + Sending updates every 1 seconds with +/-50%, next due in XX seconds Timeout after 180 seconds, garbage collect after 5 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set diff --git a/tests/topotests/ripng_topo1/r2/ripngd.conf b/tests/topotests/ripng_topo1/r2/ripngd.conf index ef2c42195d..7a6450eab5 100644 --- a/tests/topotests/ripng_topo1/r2/ripngd.conf +++ b/tests/topotests/ripng_topo1/r2/ripngd.conf @@ -1,11 +1,11 @@ log file ripngd.log ! -debug ripng events -debug ripng packet -debug ripng zebra +! debug ripng events +! debug ripng packet +! debug ripng zebra ! router ripng - timers basic 5 180 5 + timers basic 1 180 5 network fc00:5::/64 network fc00:6::/62 ! diff --git a/tests/topotests/ripng_topo1/r3/ripng_status.ref b/tests/topotests/ripng_topo1/r3/ripng_status.ref index f4bfff0c59..bef2361fcd 100644 --- a/tests/topotests/ripng_topo1/r3/ripng_status.ref +++ b/tests/topotests/ripng_topo1/r3/ripng_status.ref @@ -1,5 +1,5 @@ Routing Protocol is "RIPng" - Sending updates every 5 seconds with +/-50%, next due in XX seconds + Sending updates every 1 seconds with +/-50%, next due in XX seconds Timeout after 180 seconds, garbage collect after 5 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set diff --git a/tests/topotests/ripng_topo1/r3/ripngd.conf b/tests/topotests/ripng_topo1/r3/ripngd.conf index 506eaac442..7a07080f7a 100644 --- a/tests/topotests/ripng_topo1/r3/ripngd.conf +++ b/tests/topotests/ripng_topo1/r3/ripngd.conf @@ -1,11 +1,11 @@ log file ripngd.log ! -debug ripng events -debug ripng packet -debug ripng zebra +! debug ripng events +! debug ripng packet +! debug ripng zebra ! router ripng - timers basic 5 180 5 + timers basic 1 180 5 network fc00:6::/62 redistribute connected redistribute static diff --git a/tests/topotests/ripng_topo1/test_ripng_topo1.py b/tests/topotests/ripng_topo1/test_ripng_topo1.py index df81ac08c4..563c4f7497 100644 --- a/tests/topotests/ripng_topo1/test_ripng_topo1.py +++ b/tests/topotests/ripng_topo1/test_ripng_topo1.py @@ -104,7 +104,7 @@ def setup_module(module): tgen.gears["r%s" % i].start() # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) + # tgen.mininet_cli() def teardown_module(module): @@ -130,9 +130,6 @@ def test_router_running(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_converge_protocols(): global fatal_error @@ -155,9 +152,6 @@ def test_converge_protocols(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_ripng_status(): global fatal_error @@ -223,9 +217,6 @@ def test_ripng_status(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_ripng_routes(): global fatal_error @@ -290,9 +281,6 @@ def test_ripng_routes(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_zebra_ipv6_routingTable(): global fatal_error @@ -358,9 +346,6 @@ def test_zebra_ipv6_routingTable(): fatal_error = net["r%s" % i].checkRouterRunning() assert fatal_error == "", fatal_error - # For debugging after starting FRR daemons, uncomment the next line - # CLI(net) - def test_shutdown_check_stderr(): global fatal_error diff --git a/tests/topotests/simple_snmp_test/r1/isisd.conf b/tests/topotests/simple_snmp_test/r1/isisd.conf index b5ca993da3..1a148f0628 100644 --- a/tests/topotests/simple_snmp_test/r1/isisd.conf +++ b/tests/topotests/simple_snmp_test/r1/isisd.conf @@ -1,7 +1,7 @@ log stdout debugging ! -debug isis route-events -debug isis events +! debug isis route-events +! debug isis events ! interface r1-eth0 ip router isis ISIS1 diff --git a/tests/topotests/srv6_locator/r1/zebra.conf b/tests/topotests/srv6_locator/r1/zebra.conf index d0c0232073..85001d710e 100644 --- a/tests/topotests/srv6_locator/r1/zebra.conf +++ b/tests/topotests/srv6_locator/r1/zebra.conf @@ -1,7 +1,7 @@ hostname r1 ! -debug zebra events -debug zebra rib detailed +! debug zebra events +! debug zebra rib detailed ! log stdout notifications log monitor notifications diff --git a/tests/topotests/zebra_seg6_route/r1/routes.json b/tests/topotests/zebra_seg6_route/r1/routes.json index a0c15b8fe4..50ac4f7174 100644 --- a/tests/topotests/zebra_seg6_route/r1/routes.json +++ b/tests/topotests/zebra_seg6_route/r1/routes.json @@ -2,7 +2,7 @@ { "in": { "dest": "1::1", - "nh": "2001::1", + "nh": "2001::2", "sid": "a::" }, "out":[{ diff --git a/tests/topotests/zebra_seg6_route/r1/zebra.conf b/tests/topotests/zebra_seg6_route/r1/zebra.conf index ad661e116b..e5e360ffa5 100644 --- a/tests/topotests/zebra_seg6_route/r1/zebra.conf +++ b/tests/topotests/zebra_seg6_route/r1/zebra.conf @@ -4,9 +4,9 @@ log stdout notifications log monitor notifications log commands ! -debug zebra packet -debug zebra dplane -debug zebra kernel msgdump +! debug zebra packet +! debug zebra dplane +! debug zebra kernel msgdump ! interface dum0 ipv6 address 2001::1/64 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 cdad988b81..399af748a1 100755 --- a/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py +++ b/tests/topotests/zebra_seg6_route/test_zebra_seg6_route.py @@ -79,11 +79,7 @@ def test_zebra_seg6local_routes(): logger.info("Test for seg6local route install via ZAPI was start.") r1 = tgen.gears["r1"] - def check(router, dest, nh, sid, expected): - router.vtysh_cmd( - "sharp install seg6-routes {} " - "nexthop-seg6 {} encap {} 1".format(dest, nh, sid) - ) + def check(router, dest, expected): output = json.loads(router.vtysh_cmd("show ipv6 route {} json".format(dest))) output = output.get("{}/128".format(dest)) if output is None: @@ -92,19 +88,17 @@ def test_zebra_seg6local_routes(): manifests = open_json_file(os.path.join(CWD, "{}/routes.json".format("r1"))) for manifest in manifests: - logger.info( - "CHECK {} {} {}".format( - manifest["in"]["dest"], manifest["in"]["nh"], manifest["in"]["sid"] + dest = manifest["in"]["dest"] + nh = manifest["in"]["nh"] + sid = manifest["in"]["sid"] + + r1.vtysh_cmd( + "sharp install seg6-routes {} nexthop-seg6 {} encap {} 1".format( + dest, nh, sid ) ) - test_func = partial( - check, - r1, - manifest["in"]["dest"], - manifest["in"]["nh"], - manifest["in"]["sid"], - manifest["out"], - ) + 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=5, wait=1) assert result is None, "Failed" diff --git a/tests/topotests/zebra_seg6local_route/r1/zebra.conf b/tests/topotests/zebra_seg6local_route/r1/zebra.conf index 22eb88098b..dee7a9171a 100644 --- a/tests/topotests/zebra_seg6local_route/r1/zebra.conf +++ b/tests/topotests/zebra_seg6local_route/r1/zebra.conf @@ -4,6 +4,6 @@ log stdout notifications log monitor notifications log commands ! -debug zebra packet -debug zebra dplane -debug zebra kernel msgdump +! debug zebra packet +! debug zebra dplane +! debug zebra kernel msgdump 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 1062c306a0..0da51cc8b2 100755 --- a/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py +++ b/tests/topotests/zebra_seg6local_route/test_zebra_seg6local_route.py @@ -79,11 +79,7 @@ def test_zebra_seg6local_routes(): logger.info("Test for seg6local route install via ZAPI was start.") r1 = tgen.gears["r1"] - def check(router, dest, context, expected): - router.vtysh_cmd( - "sharp install seg6local-routes {} " - "nexthop-seg6local dum0 {} 1".format(dest, context) - ) + def check(router, dest, expected): output = json.loads(router.vtysh_cmd("show ipv6 route {} json".format(dest))) output = output.get("{}/128".format(dest)) if output is None: @@ -92,14 +88,20 @@ def test_zebra_seg6local_routes(): manifests = open_json_file(os.path.join(CWD, "{}/routes.json".format("r1"))) for manifest in manifests: - logger.info( - "CHECK {} {}".format(manifest["in"]["dest"], manifest["in"]["context"]) + dest = manifest["in"]["dest"] + context = manifest["in"]["context"] + + logger.info("CHECK {} {}".format(dest, context)) + + r1.vtysh_cmd( + "sharp install seg6local-routes {} nexthop-seg6local dum0 {} 1".format( + dest, context + ) ) test_func = partial( check, r1, - manifest["in"]["dest"], - manifest["in"]["context"], + dest, manifest["out"], ) success, result = topotest.run_and_expect(test_func, None, count=5, wait=1) diff --git a/tests/zebra/subdir.am b/tests/zebra/subdir.am new file mode 100644 index 0000000000..d9fcde80a9 --- /dev/null +++ b/tests/zebra/subdir.am @@ -0,0 +1,17 @@ +if !ZEBRA +PYTEST_IGNORE += --ignore=zebra/ +endif +ZEBRA_TEST_LDADD = zebra/label_manager.o $(ALL_TESTS_LDADD) + + +if ZEBRA +check_PROGRAMS += tests/zebra/test_lm_plugin +endif +tests_zebra_test_lm_plugin_CFLAGS = $(TESTS_CFLAGS) +tests_zebra_test_lm_plugin_CPPFLAGS = $(TESTS_CPPFLAGS) +tests_zebra_test_lm_plugin_LDADD = $(ZEBRA_TEST_LDADD) +tests_zebra_test_lm_plugin_SOURCES = tests/zebra/test_lm_plugin.c +EXTRA_DIST += \ + tests/zebra/test_lm_plugin.py \ + tests/zebra/test_lm_plugin.refout \ + # end diff --git a/tools/checkpatch.pl b/tools/checkpatch.pl index cf15d00796..d2eb20ce5b 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -409,6 +409,25 @@ our $Operators = qr{ }x; our $c90_Keywords = qr{do|for|while|if|else|return|goto|continue|switch|default|case|break}x; +our $Iterators = qr{ + frr_each|frr_each_safe|frr_each_from| + frr_with_mutex|frr_with_privs| + LIST_FOREACH|LIST_FOREACH_SAFE| + SLIST_FOREACH|SLIST_FOREACH_SAFE|SLIST_FOREACH_PREVPTR| + STAILQ_FOREACH|STAILQ_FOREACH_SAFE| + TAILQ_FOREACH|TAILQ_FOREACH_SAFE|TAILQ_FOREACH_REVERSE|TAILQ_FOREACH_REVERSE_SAFE| + RB_FOREACH|RB_FOREACH_SAFE|RB_FOREACH_REVERSE|RB_FOREACH_REVERSE_SAFE| + SPLAY_FOREACH| + FOR_ALL_INTERFACES|FOR_ALL_INTERFACES_ADDRESSES|JSON_FOREACH| + LY_FOR_KEYS|LY_LIST_FOR|LY_TREE_FOR|LY_TREE_DFS_BEGIN|LYD_TREE_DFS_BEGIN| + RE_DEST_FOREACH_ROUTE|RE_DEST_FOREACH_ROUTE_SAFE| + RNODE_FOREACH_RE|RNODE_FOREACH_RE_SAFE| + UPDGRP_FOREACH_SUBGRP|UPDGRP_FOREACH_SUBGRP_SAFE| + SUBGRP_FOREACH_PEER|SUBGRP_FOREACH_PEER_SAFE| + SUBGRP_FOREACH_ADJ|SUBGRP_FOREACH_ADJ_SAFE| + AF_FOREACH|FOREACH_AFI_SAFI|FOREACH_SAFI| + LSDB_LOOP + }x; our $BasicType; our $NonptrType; @@ -1009,9 +1028,9 @@ sub top_of_kernel_tree { my ($root) = @_; my @tree_check = ( - "COPYING", "CREDITS", "Kbuild", "MAINTAINERS", "Makefile", - "README", "Documentation", "arch", "include", "drivers", - "fs", "init", "ipc", "kernel", "lib", "scripts", + "COPYING", "configure.ac", "Makefile.am", + "README.md", "doc", "lib", "vtysh", "watchfrr", "tests", + "zebra", "bgpd", "ospfd", "ospf6d", "isisd", "staticd", ); foreach my $check (@tree_check) { @@ -2655,8 +2674,8 @@ sub process { (defined($1) || defined($2))))) { $is_patch = 1; $reported_maintainer_file = 1; - WARN("FILE_PATH_CHANGES", - "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); + #WARN("FILE_PATH_CHANGES", + # "added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr); } # Check for wrappage within a valid hunk of the file @@ -4028,7 +4047,8 @@ sub process { if|for|while|switch|return|case| volatile|__volatile__| __attribute__|format|__extension__| - asm|__asm__)$/x) + asm|__asm__| + $Iterators)$/x) { # cpp #define statements have non-optional spaces, ie # if there is a space between the name and the open diff --git a/tools/coccinelle/json_object_string_addf_inet_ntop.cocci b/tools/coccinelle/json_object_string_addf_inet_ntop.cocci new file mode 100644 index 0000000000..d9f92e564c --- /dev/null +++ b/tools/coccinelle/json_object_string_addf_inet_ntop.cocci @@ -0,0 +1,19 @@ +@@ +identifier json; +expression family, buf, value; +constant key, buflen; +@@ + +( +-json_object_string_add(json, key, inet_ntop(AF_INET, &value, buf, sizeof(buf))); ++json_object_string_addf(json, key, "%pI4", &value); +| +-json_object_string_add(json, key, inet_ntop(AF_INET, &value, buf, buflen)); ++json_object_string_addf(json, key, "%pI4", &value); +| +-json_object_string_add(json, key, inet_ntop(AF_INET6, &value, buf, sizeof(buf))); ++json_object_string_addf(json, key, "%pI6", &value); +| +-json_object_string_add(json, key, inet_ntop(AF_INET6, &value, buf, buflen)); ++json_object_string_addf(json, key, "%pI6", &value); +) diff --git a/tools/coccinelle/json_object_string_addf_prefix2str.cocci b/tools/coccinelle/json_object_string_addf_prefix2str.cocci new file mode 100644 index 0000000000..ae012b91be --- /dev/null +++ b/tools/coccinelle/json_object_string_addf_prefix2str.cocci @@ -0,0 +1,16 @@ +@@ +identifier json; +expression family, value; +expression prefix; +constant key; +@@ + +( +-prefix2str(prefix, value, ...); +... +-json_object_string_add(json, key, value); ++json_object_string_addf(json, key, "%pFX", prefix); +| +-json_object_string_add(json, key, prefix2str(prefix, value, ...)); ++json_object_string_addf(json, key, "%pFX", prefix); +) diff --git a/tools/coccinelle/struct_thread_double_pointer.cocci b/tools/coccinelle/struct_thread_double_pointer.cocci new file mode 100644 index 0000000000..a08e6727cf --- /dev/null +++ b/tools/coccinelle/struct_thread_double_pointer.cocci @@ -0,0 +1,35 @@ +@r1@ +identifier fn, m, f, a, v, t; +identifier func =~ "thread_add_"; +type T1, T2; +position p; +@@ + +?static +T1 fn(T2 *t) +{ +... +func(m,f,a,v,&t)@p +... +} + +@r2@ +identifier m, f, a, v, t; +identifier func =~ "thread_add_"; +type T1; +position p; +@@ + +T1 *t; +... +func(m,f,a,v,&t)@p + +@script:python@ +p << r1.p; +@@ +coccilib.report.print_report(p[0],"Passed double 'struct thread' pointer") + +@script:python@ +p << r2.p; +@@ +coccilib.report.print_report(p[0],"Passed double 'struct thread' pointer") diff --git a/tools/coccinelle/vty_json.cocci b/tools/coccinelle/vty_json.cocci new file mode 100644 index 0000000000..481dac5406 --- /dev/null +++ b/tools/coccinelle/vty_json.cocci @@ -0,0 +1,9 @@ +@@ +identifier vty; +identifier json; +@@ + +-vty_out(vty, "%s\n", json_object_to_json_string_ext(json, ...)); +... +-json_object_free(json); ++vty_json(vty, json); diff --git a/tools/frr-reload.py b/tools/frr-reload.py index a1320cad1a..c33c1f72a0 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -172,7 +172,6 @@ class Vtysh(object): class Context(object): - """ A Context object represents a section of frr configuration such as: ! @@ -237,7 +236,6 @@ def get_normalized_mac_ip_line(line): class Config(object): - """ A frr configuration is stored in a Config object. A Config object contains a dictionary of Context objects where the Context keys @@ -268,22 +266,20 @@ class Config(object): if ":" in line: line = get_normalized_mac_ip_line(line) - """ - vrf static routes can be added in two ways. The old way is: - - "ip route x.x.x.x/x y.y.y.y vrf <vrfname>" - - but it's rendered in the configuration as the new way:: - - vrf <vrf-name> - ip route x.x.x.x/x y.y.y.y - exit-vrf - - this difference causes frr-reload to not consider them a - match and delete vrf static routes incorrectly. - fix the old way to match new "show running" output so a - proper match is found. - """ + # vrf static routes can be added in two ways. The old way is: + # + # "ip route x.x.x.x/x y.y.y.y vrf <vrfname>" + # + # but it's rendered in the configuration as the new way:: + # + # vrf <vrf-name> + # ip route x.x.x.x/x y.y.y.y + # exit-vrf + # + # this difference causes frr-reload to not consider them a + # match and delete vrf static routes incorrectly. + # fix the old way to match new "show running" output so a + # proper match is found. if ( line.startswith("ip route ") or line.startswith("ipv6 route ") ) and " vrf " in line: @@ -329,14 +325,12 @@ class Config(object): """ Return the lines read in from the configuration """ - return "\n".join(self.lines) def get_contexts(self): """ Return the parsed context as strings for display, log etc. """ - for (_, ctx) in sorted(iteritems(self.contexts)): print(str(ctx)) @@ -344,18 +338,15 @@ class Config(object): """ Save the provided key and lines as a context """ - if not key: return - """ - IP addresses specified in "network" statements, "ip prefix-lists" - etc. can differ in the host part of the specification the user - provides and what the running config displays. For example, user - can specify 11.1.1.1/24, and the running config displays this as - 11.1.1.0/24. Ensure we don't do a needless operation for such - lines. IS-IS & OSPFv3 have no "network" support. - """ + # IP addresses specified in "network" statements, "ip prefix-lists" + # etc. can differ in the host part of the specification the user + # provides and what the running config displays. For example, user can + # specify 11.1.1.1/24, and the running config displays this as + # 11.1.1.0/24. Ensure we don't do a needless operation for such lines. + # IS-IS & OSPFv3 have no "network" support. re_key_rt = re.match(r"(ip|ipv6)\s+route\s+([A-Fa-f:.0-9/]+)(.*)$", key[0]) if re_key_rt: addr = re_key_rt.group(2) @@ -433,10 +424,8 @@ class Config(object): newlines.append(line) lines = newlines - """ - More fixups in user specification and what running config shows. - "null0" in routes must be replaced by Null0. - """ + # More fixups in user specification and what running config shows. + # "null0" in routes must be replaced by Null0. if ( key[0].startswith("ip route") or key[0].startswith("ipv6 route") @@ -444,10 +433,8 @@ class Config(object): ): key[0] = re.sub(r"\s+null0(\s*$)", " Null0", key[0]) - """ - Similar to above, but when the static is in a vrf, it turns into a - blackhole nexthop for both null0 and Null0. Fix it accordingly - """ + # Similar to above, but when the static is in a vrf, it turns into a + # blackhole nexthop for both null0 and Null0. Fix it accordingly if lines and key[0].startswith("vrf "): newlines = [] for line in lines: @@ -477,71 +464,58 @@ class Config(object): def load_contexts(self): """ Parse the configuration and create contexts for each appropriate block - """ - """ The end of a context is flagged via the 'end' keyword: -! -interface swp52 - ipv6 nd suppress-ra - link-detect -! -end -router bgp 10 - bgp router-id 10.0.0.1 - bgp log-neighbor-changes - no bgp default ipv4-unicast - neighbor EBGP peer-group - neighbor EBGP advertisement-interval 1 - neighbor EBGP timers connect 10 - neighbor 2001:40:1:4::6 remote-as 40 - neighbor 2001:40:1:8::a remote-as 40 -! -end - address-family ipv6 - neighbor IBGPv6 activate - neighbor 2001:10::2 peer-group IBGPv6 - neighbor 2001:10::3 peer-group IBGPv6 - exit-address-family -! -end - address-family evpn - neighbor LEAF activate - advertise-all-vni - vni 10100 - rd 65000:10100 - route-target import 10.1.1.1:10100 - route-target export 10.1.1.1:10100 - exit-vni - exit-address-family -! -end -router ospf - ospf router-id 10.0.0.1 - log-adjacency-changes detail - timers throttle spf 0 50 5000 -! -end + ! + interface swp52 + ipv6 nd suppress-ra + link-detect + ! + end + router bgp 10 + bgp router-id 10.0.0.1 + bgp log-neighbor-changes + no bgp default ipv4-unicast + neighbor EBGP peer-group + neighbor EBGP advertisement-interval 1 + neighbor EBGP timers connect 10 + neighbor 2001:40:1:4::6 remote-as 40 + neighbor 2001:40:1:8::a remote-as 40 + ! + end + address-family ipv6 + neighbor IBGPv6 activate + neighbor 2001:10::2 peer-group IBGPv6 + neighbor 2001:10::3 peer-group IBGPv6 + exit-address-family + ! + end + router ospf + ospf router-id 10.0.0.1 + log-adjacency-changes detail + timers throttle spf 0 50 5000 + ! + end + + The code assumes that its working on the output from the "vtysh -m" + command. That provides the appropriate markers to signify end of + a context. This routine uses that to build the contexts for the + config. + + There are single line contexts such as "log file /media/node/zebra.log" + and multi-line contexts such as "router ospf" and subcontexts + within a context such as "address-family" within "router bgp" + In each of these cases, the first line of the context becomes the + key of the context. So "router bgp 10" is the key for the non-address + family part of bgp, "router bgp 10, address-family ipv6 unicast" is + the key for the subcontext and so on. + + This dictionary contains a tree of all commands that we know start a + new multi-line context. All other commands are treated either as + commands inside a multi-line context or as single-line contexts. This + dictionary should be updated whenever a new node is added to FRR. """ - - # The code assumes that its working on the output from the "vtysh -m" - # command. That provides the appropriate markers to signify end of - # a context. This routine uses that to build the contexts for the - # config. - # - # There are single line contexts such as "log file /media/node/zebra.log" - # and multi-line contexts such as "router ospf" and subcontexts - # within a context such as "address-family" within "router bgp" - # In each of these cases, the first line of the context becomes the - # key of the context. So "router bgp 10" is the key for the non-address - # family part of bgp, "router bgp 10, address-family ipv6 unicast" is - # the key for the subcontext and so on. - - # This dictionary contains a tree of all commands that we know start a - # new multi-line context. All other commands are treated either as - # commands inside a multi-line context or as single-line contexts. This - # dictionary should be updated whenever a new node is added to FRR. ctx_keywords = { "router bgp ": { "address-family ": { @@ -791,6 +765,84 @@ def check_for_exit_vrf(lines_to_add, lines_to_del): return (lines_to_add, lines_to_del) +def bgp_delete_nbr_remote_as_line(lines_to_add): + # Handle deletion of neighbor <nbr> remote-as line from + # lines_to_add if the nbr is configured with peer-group and + # peer-group has remote-as config present. + # 'neighbor <nbr> remote-as change on peer is not allowed + # if the peer is part of peer-group and peer-group has + # remote-as config. + + pg_dict = dict() + # Find all peer-group commands; create dict of each peer-group + # to store assoicated neighbor as value + for ctx_keys, line in lines_to_add: + if ( + ctx_keys[0].startswith("router bgp") + and line + and line.startswith("neighbor ") + ): + # {'router bgp 65001': {'PG': [], 'PG1': []}, + # 'router bgp 65001 vrf vrf1': {'PG': [], 'PG1': []}} + if ctx_keys[0] not in pg_dict: + pg_dict[ctx_keys[0]] = dict() + # find 'neighbor <pg_name> peer-group' + re_pg = re.match("neighbor (\S+) peer-group$", line) + if re_pg and re_pg.group(1) not in pg_dict[ctx_keys[0]]: + pg_dict[ctx_keys[0]][re_pg.group(1)] = { + "nbr": list(), + "remoteas": False, + } + found_pg_cmd = True + + # Find peer-group with remote-as command, also search neighbor + # associated to peer-group and store into peer-group dict + for ctx_keys, line in lines_to_add: + if ( + ctx_keys[0].startswith("router bgp") + and line + and line.startswith("neighbor ") + ): + if ctx_keys[0] in pg_dict: + for pg_key in pg_dict[ctx_keys[0]]: + # Find 'neighbor <pg_name> remote-as' + pg_rmtas = "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 <peer> [interface] peer-group <pg_name>' + nb_pg = "neighbor (\S+) peer-group %s$" % pg_key + re_nbr_pg = re.search(nb_pg, line) + if ( + re_nbr_pg + and re_nbr_pg.group(1) not in pg_dict[ctx_keys[0]][pg_key] + ): + pg_dict[ctx_keys[0]][pg_key]["nbr"].append(re_nbr_pg.group(1)) + + # Find any neighbor <nbr> remote-as config line check if the nbr + # is in the peer group's list of nbrs. Remove 'neighbor <nbr> remote-as <>' + # from lines_to_add. + lines_to_del_from_add = [] + for ctx_keys, line in lines_to_add: + if ( + ctx_keys[0].startswith("router bgp") + and line + and line.startswith("neighbor ") + ): + nbr_rmtas = "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]]: + if pg_dict[ctx_keys[0]][pg]["remoteas"] == True: + for nbr in pg_dict[ctx_keys[0]][pg]["nbr"]: + if re_nbr_rmtas.group(1) in nbr: + lines_to_del_from_add.append((ctx_keys, line)) + + for ctx_keys, line in lines_to_del_from_add: + lines_to_add.remove((ctx_keys, line)) + + """ This method handles deletion of bgp peer group config. The objective is to delete config lines related to peers @@ -801,6 +853,8 @@ config line to the end of the lines_to_del list. def delete_move_lines(lines_to_add, lines_to_del): + bgp_delete_nbr_remote_as_line(lines_to_add) + del_dict = dict() # Stores the lines to move to the end of the pending list. lines_to_del_to_del = [] @@ -808,54 +862,51 @@ def delete_move_lines(lines_to_add, lines_to_del): lines_to_del_to_app = [] found_pg_del_cmd = False - """ - When "neighbor <pg_name> peer-group" under a bgp instance is removed, - it also deletes the associated peer config. Any config line below no form of - peer-group related to a peer are errored out as the peer no longer exists. - To cleanup peer-group and associated peer(s) configs: - - Remove all the peers config lines from the pending list (lines_to_del list). - - Move peer-group deletion line to the end of the pending list, to allow - removal of any of the peer-group specific configs. - - Create a dictionary of config context (i.e. router bgp vrf x). - Under each context node, create a dictionary of a peer-group name. - Append a peer associated to the peer-group into a list under a peer-group node. - Remove all of the peer associated config lines from the pending list. - Append peer-group deletion line to end of the pending list. - - Example: - neighbor underlay peer-group - neighbor underlay remote-as external - neighbor underlay advertisement-interval 0 - neighbor underlay timers 3 9 - neighbor underlay timers connect 10 - neighbor swp1 interface peer-group underlay - neighbor swp1 advertisement-interval 0 - neighbor swp1 timers 3 9 - neighbor swp1 timers connect 10 - neighbor swp2 interface peer-group underlay - neighbor swp2 advertisement-interval 0 - neighbor swp2 timers 3 9 - neighbor swp2 timers connect 10 - neighbor swp3 interface peer-group underlay - neighbor uplink1 interface remote-as internal - neighbor uplink1 advertisement-interval 0 - neighbor uplink1 timers 3 9 - neighbor uplink1 timers connect 10 - - New order: - "router bgp 200 no bgp bestpath as-path multipath-relax" - "router bgp 200 no neighbor underlay advertisement-interval 0" - "router bgp 200 no neighbor underlay timers 3 9" - "router bgp 200 no neighbor underlay timers connect 10" - "router bgp 200 no neighbor uplink1 advertisement-interval 0" - "router bgp 200 no neighbor uplink1 timers 3 9" - "router bgp 200 no neighbor uplink1 timers connect 10" - "router bgp 200 no neighbor underlay remote-as external" - "router bgp 200 no neighbor uplink1 interface remote-as internal" - "router bgp 200 no neighbor underlay peer-group" - - """ + # When "neighbor <pg_name> peer-group" under a bgp instance is removed, + # it also deletes the associated peer config. Any config line below no form of + # peer-group related to a peer are errored out as the peer no longer exists. + # To cleanup peer-group and associated peer(s) configs: + # - Remove all the peers config lines from the pending list (lines_to_del list). + # - Move peer-group deletion line to the end of the pending list, to allow + # removal of any of the peer-group specific configs. + # + # Create a dictionary of config context (i.e. router bgp vrf x). + # Under each context node, create a dictionary of a peer-group name. + # Append a peer associated to the peer-group into a list under a peer-group node. + # Remove all of the peer associated config lines from the pending list. + # Append peer-group deletion line to end of the pending list. + # + # Example: + # neighbor underlay peer-group + # neighbor underlay remote-as external + # neighbor underlay advertisement-interval 0 + # neighbor underlay timers 3 9 + # neighbor underlay timers connect 10 + # neighbor swp1 interface peer-group underlay + # neighbor swp1 advertisement-interval 0 + # neighbor swp1 timers 3 9 + # neighbor swp1 timers connect 10 + # neighbor swp2 interface peer-group underlay + # neighbor swp2 advertisement-interval 0 + # neighbor swp2 timers 3 9 + # neighbor swp2 timers connect 10 + # neighbor swp3 interface peer-group underlay + # neighbor uplink1 interface remote-as internal + # neighbor uplink1 advertisement-interval 0 + # neighbor uplink1 timers 3 9 + # neighbor uplink1 timers connect 10 + + # New order: + # "router bgp 200 no bgp bestpath as-path multipath-relax" + # "router bgp 200 no neighbor underlay advertisement-interval 0" + # "router bgp 200 no neighbor underlay timers 3 9" + # "router bgp 200 no neighbor underlay timers connect 10" + # "router bgp 200 no neighbor uplink1 advertisement-interval 0" + # "router bgp 200 no neighbor uplink1 timers 3 9" + # "router bgp 200 no neighbor uplink1 timers connect 10" + # "router bgp 200 no neighbor underlay remote-as external" + # "router bgp 200 no neighbor uplink1 interface remote-as internal" + # "router bgp 200 no neighbor underlay peer-group" for (ctx_keys, line) in lines_to_del: if ( @@ -863,55 +914,50 @@ def delete_move_lines(lines_to_add, lines_to_del): and line and line.startswith("neighbor ") ): - """ - When 'neighbor <peer> remote-as <>' is removed it deletes the peer, - there might be a peer associated config which also needs to be removed - prior to peer. - Append the 'neighbor <peer> remote-as <>' to the lines_to_del. - Example: - - neighbor uplink1 interface remote-as internal - neighbor uplink1 advertisement-interval 0 - neighbor uplink1 timers 3 9 - neighbor uplink1 timers connect 10 - - Move to end: - neighbor uplink1 advertisement-interval 0 - neighbor uplink1 timers 3 9 - neighbor uplink1 timers connect 10 - ... - - neighbor uplink1 interface remote-as internal - - """ + # When 'neighbor <peer> remote-as <>' is removed it deletes the peer, + # there might be a peer associated config which also needs to be removed + # prior to peer. + # Append the 'neighbor <peer> remote-as <>' to the lines_to_del. + # Example: + # + # neighbor uplink1 interface remote-as internal + # neighbor uplink1 advertisement-interval 0 + # neighbor uplink1 timers 3 9 + # neighbor uplink1 timers connect 10 + + # Move to end: + # neighbor uplink1 advertisement-interval 0 + # neighbor uplink1 timers 3 9 + # neighbor uplink1 timers connect 10 + # ... + # + # neighbor uplink1 interface remote-as internal + # # 'no neighbor peer [interface] remote-as <>' nb_remoteas = "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)) - """ - {'router bgp 65001': {'PG': [], 'PG1': []}, - 'router bgp 65001 vrf vrf1': {'PG': [], 'PG1': []}} - """ + # {'router bgp 65001': {'PG': [], 'PG1': []}, + # 'router bgp 65001 vrf vrf1': {'PG': [], 'PG1': []}} if ctx_keys[0] not in del_dict: del_dict[ctx_keys[0]] = dict() # find 'no neighbor <pg_name> peer-group' re_pg = re.match("neighbor (\S+) peer-group$", line) if re_pg and re_pg.group(1) not in del_dict[ctx_keys[0]]: del_dict[ctx_keys[0]][re_pg.group(1)] = list() + found_pg_del_cmd = True + + if found_pg_del_cmd == False: + return (lines_to_add, lines_to_del) for (ctx_keys, line) in lines_to_del_to_app: lines_to_del.remove((ctx_keys, line)) lines_to_del.append((ctx_keys, line)) - if found_pg_del_cmd == False: - return (lines_to_add, lines_to_del) - - """ - {'router bgp 65001': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']}, - 'router bgp 65001 vrf vrf1': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']}} - """ + # {'router bgp 65001': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']}, + # 'router bgp 65001 vrf vrf1': {'PG': ['10.1.1.2'], 'PG1': ['10.1.1.21']}} for (ctx_keys, line) in lines_to_del: if ( ctx_keys[0].startswith("router bgp") @@ -985,25 +1031,22 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): if ctx_keys[0].startswith("router bgp") and line: if line.startswith("neighbor "): - """ - BGP changed how it displays swpX peers that are part of peer-group. Older - versions of frr would display these on separate lines: - neighbor swp1 interface - neighbor swp1 peer-group FOO - - but today we display via a single line - neighbor swp1 interface peer-group FOO - - This change confuses frr-reload.py so check to see if we are deleting - neighbor swp1 interface peer-group FOO - - and adding - neighbor swp1 interface - neighbor swp1 peer-group FOO - - If so then chop the del line and the corresponding add lines - """ - + # BGP changed how it displays swpX peers that are part of peer-group. Older + # versions of frr would display these on separate lines: + # neighbor swp1 interface + # neighbor swp1 peer-group FOO + # + # but today we display via a single line + # neighbor swp1 interface peer-group FOO + # + # This change confuses frr-reload.py so check to see if we are deleting + # neighbor swp1 interface peer-group FOO + # + # and adding + # neighbor swp1 interface + # neighbor swp1 peer-group FOO + # + # 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 ) @@ -1055,12 +1098,10 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_add_to_del.append((ctx_keys, swpx_interface)) lines_to_add_to_del.append((tmp_ctx_keys, swpx_peergroup)) - """ - Changing the bfd timers on neighbors is allowed without doing - a delete/add process. Since doing a "no neighbor blah bfd ..." - will cause the peer to bounce unnecessarily, just skip the delete - and just do the add. - """ + # Changing the bfd timers on neighbors is allowed without doing + # a delete/add process. Since doing a "no neighbor blah bfd + # ..." will cause the peer to bounce unnecessarily, just skip + # the delete and just do the add. re_nbr_bfd_timers = re.search( r"neighbor (\S+) bfd (\S+) (\S+) (\S+)", line ) @@ -1084,16 +1125,14 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): if found_add_bfd_nbr: lines_to_del_to_del.append((ctx_keys, line)) - """ - Neighbor changes of route-maps need to be accounted for in that we - do not want to do a `no route-map...` `route-map ....` when changing - a route-map. This is bad mojo as that we will send/receive - data we don't want. - Additionally we need to ensure that if we have different afi/safi - variants that 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 - """ + # Neighbor changes of route-maps need to be accounted for in + # that we do not want to do a `no route-map...` `route-map + # ....` when changing a route-map. This is bad mojo as that we + # will send/receive data we don't want. Additionally we need + # to ensure that if we have different afi/safi variants that + # 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) if re_nbr_rm: adjust_for_bgp_node = 0 @@ -1131,29 +1170,27 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): if save_line == dl_line: lines_to_del_to_del.append((ctx_keys_dl, save_line)) - """ - We changed how we display the neighbor interface command. Older - versions of frr would display the following: - neighbor swp1 interface - neighbor swp1 remote-as external - neighbor swp1 capability extended-nexthop - - but today we display via a single line - neighbor swp1 interface remote-as external - - and capability extended-nexthop is no longer needed because we - automatically enable it when the neighbor is of type interface. - - This change confuses frr-reload.py so check to see if we are deleting - neighbor swp1 interface remote-as (external|internal|ASNUM) - - and adding - neighbor swp1 interface - neighbor swp1 remote-as (external|internal|ASNUM) - neighbor swp1 capability extended-nexthop - - If so then chop the del line and the corresponding add lines - """ + # We changed how we display the neighbor interface command. Older + # versions of frr would display the following: + # neighbor swp1 interface + # neighbor swp1 remote-as external + # neighbor swp1 capability extended-nexthop + # + # but today we display via a single line + # neighbor swp1 interface remote-as external + # + # and capability extended-nexthop is no longer needed because we + # automatically enable it when the neighbor is of type interface. + # + # This change confuses frr-reload.py so check to see if we are deleting + # neighbor swp1 interface remote-as (external|internal|ASNUM) + # + # and adding + # neighbor swp1 interface + # neighbor swp1 remote-as (external|internal|ASNUM) + # neighbor swp1 capability extended-nexthop + # + # 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 ) @@ -1189,15 +1226,13 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_add_to_del.append((ctx_keys, swpx_interface)) lines_to_add_to_del.append((tmp_ctx_keys, swpx_remoteas)) - """ - We made the 'bgp bestpath as-path multipath-relax' command - automatically assume 'no-as-set' since the lack of this option caused - weird routing problems. When the running config is shown in - releases with this change, the no-as-set keyword is not shown as it - is the default. This causes frr-reload to unnecessarily unapply - this option only to apply it back again, causing unnecessary session - resets. - """ + # We made the 'bgp bestpath as-path multipath-relax' command + # automatically assume 'no-as-set' since the lack of this option + # caused weird routing problems. When the running config is shown + # in releases with this change, the no-as-set keyword is not shown + # as it is the default. This causes frr-reload to unnecessarily + # unapply this option only to apply it back again, causing + # unnecessary session resets. if "multipath-relax" in line: re_asrelax_new = re.search( "^bgp\s+bestpath\s+as-path\s+multipath-relax$", line @@ -1210,25 +1245,21 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_del_to_del.append((ctx_keys, line)) lines_to_add_to_del.append((ctx_keys, old_asrelax_cmd)) - """ - If we are modifying the BGP table-map we need to avoid a del/add and - instead modify the table-map in place via an add. This is needed to - avoid installing all routes in the RIB the second the 'no table-map' - is issued. - """ + # If we are modifying the BGP table-map we need to avoid a del/add + # and instead modify the table-map in place via an add. This is + # needed to avoid installing all routes in the RIB the second the + # 'no table-map' is issued. if line.startswith("table-map"): found_table_map = line_exist(lines_to_add, ctx_keys, "table-map", False) if found_table_map: lines_to_del_to_del.append((ctx_keys, line)) - """ - More old-to-new config handling. ip import-table no longer accepts - distance, but we honor the old syntax. But 'show running' shows only - 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. - """ + # More old-to-new config handling. ip import-table no longer accepts + # distance, but we honor the old syntax. But 'show running' shows only + # 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]) if re_importtbl: table_num = re_importtbl.group(1) @@ -1239,17 +1270,16 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): ) lines_to_add_to_del.append((ctx[0], None)) - """ - ip/ipv6 prefix-lists and access-lists can be specified without a seq number. - However, the running config always adds 'seq x', where x is a number - incremented by 5 for every element of the prefix/access list. - So, ignore such lines as well. Sample prefix-list and acces-list lines: - ip prefix-list PR-TABLE-2 seq 5 permit 20.8.2.0/24 le 32 - ip prefix-list PR-TABLE-2 seq 10 permit 20.8.2.0/24 le 32 - ipv6 prefix-list vrfdev6-12 permit 2000:9:2::/64 gt 64 - access-list FOO seq 5 permit 2.2.2.2/32 - ipv6 access-list BAR seq 5 permit 2:2:2::2/128 - """ + # ip/ipv6 prefix-lists and access-lists can be specified without a seq + # number. However, the running config always adds 'seq x', where x is + # a number incremented by 5 for every element of the prefix/access + # list. So, ignore such lines as well. Sample prefix-list and + # acces-list lines: + # ip prefix-list PR-TABLE-2 seq 5 permit 20.8.2.0/24 le 32 + # ip prefix-list PR-TABLE-2 seq 10 permit 20.8.2.0/24 le 32 + # ipv6 prefix-list vrfdev6-12 permit 2000:9:2::/64 gt 64 + # 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)(.*)$", ctx_keys[0], @@ -1268,12 +1298,9 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_del_to_del.append((ctx_keys, None)) lines_to_add_to_del.append(((tmpline,), None)) found = True - """ - If prefix-lists or access-lists are being deleted and - not added (see comment above), add command with 'no' to - lines_to_add and remove from lines_to_del to improve - scaling performance. - """ + # If prefix-lists or access-lists are being deleted and not added + # (see comment above), add command with 'no' to lines_to_add and + # remove from lines_to_del to improve scaling performance. if found is False: add_cmd = ("no " + ctx_keys[0],) lines_to_add.append((add_cmd, None)) @@ -1305,16 +1332,12 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_add, ctx_keys, route_target_both_line ) - """ - If the running configs has - route-target import 1:1 - route-target export 1:1 - - and the config we are reloading against has - route-target both 1:1 - - then we can ignore deleting the import/export and ignore adding the 'both' - """ + # If the running configs has + # route-target import 1:1 + # route-target export 1:1 + # and the config we are reloading against has + # route-target both 1:1 + # then we can ignore deleting the import/export and ignore adding the 'both' if found_route_target_export_line and found_route_target_both_line: lines_to_del_to_del.append((ctx_keys, route_target_import_line)) lines_to_del_to_del.append((ctx_keys, route_target_export_line)) @@ -1336,23 +1359,21 @@ def ignore_delete_re_add_lines(lines_to_add, lines_to_del): lines_to_del_to_del.append((ctx_keys, line)) lines_to_add_to_del.append((ctx_keys, line)) else: - """ - We have commands that used to be displayed in the global part - of 'router bgp' that are now displayed under 'address-family ipv4 unicast' - - # old way - router bgp 64900 - neighbor ISL advertisement-interval 0 - - vs. - - # new way - router bgp 64900 - address-family ipv4 unicast - neighbor ISL advertisement-interval 0 - - Look to see if we are deleting it in one format just to add it back in the other - """ + # We have commands that used to be displayed in the global part + # of 'router bgp' that are now displayed under 'address-family ipv4 unicast' + # + # # old way + # router bgp 64900 + # neighbor ISL advertisement-interval 0 + # + # vs. + # + # # new way + # router bgp 64900 + # address-family ipv4 unicast + # neighbor ISL advertisement-interval 0 + # + # Look to see if we are deleting it in one format just to add it back in the other if ( ctx_keys[0].startswith("router bgp") and len(ctx_keys) > 1 @@ -1385,19 +1406,22 @@ def ignore_unconfigurable_lines(lines_to_add, lines_to_del): for (ctx_keys, line) in lines_to_del: - if ( - ctx_keys[0].startswith("frr version") - or ctx_keys[0].startswith("frr defaults") - or ctx_keys[0].startswith("username") - or ctx_keys[0].startswith("password") - or ctx_keys[0].startswith("line vty") - or - # This is technically "no"able but if we did so frr-reload would - # stop working so do not let the user shoot themselves in the foot - # by removing this. - ctx_keys[0].startswith("service integrated-vtysh-config") + # The integrated-vtysh-config one is technically "no"able but if we did + # so frr-reload would stop working so do not let the user shoot + # themselves in the foot by removing this. + if any( + [ + ctx_keys[0].startswith(x) + for x in [ + "frr version", + "frr defaults", + "username", + "password", + "line vty", + "service integrated-vtysh-config", + ] + ] ): - log.info('"%s" cannot be removed' % (ctx_keys[-1],)) lines_to_del_to_del.append((ctx_keys, line)) @@ -1906,7 +1930,7 @@ if __name__ == "__main__": lines_to_configure = [] # We will not be able to do anything, go ahead and exit(1) - if not vtysh.is_config_available(): + if not vtysh.is_config_available() or not reload_ok: sys.exit(1) log.debug("New Frr Config\n%s", newconf.get_lines()) diff --git a/tools/frr.service.in b/tools/frr.service.in index f67bc41b09..df1e4f3b08 100644 --- a/tools/frr.service.in +++ b/tools/frr.service.in @@ -12,7 +12,7 @@ Type=forking NotifyAccess=all StartLimitInterval=3m StartLimitBurst=3 -TimeoutSec=2m +TimeoutSec=@TIMEOUT_MIN@m WatchdogSec=60s RestartSec=5 Restart=on-abnormal diff --git a/tools/frr@.service.in b/tools/frr@.service.in index 7b94a11f5b..1cbef1b18c 100644 --- a/tools/frr@.service.in +++ b/tools/frr@.service.in @@ -12,7 +12,7 @@ Type=forking NotifyAccess=all StartLimitInterval=3m StartLimitBurst=3 -TimeoutSec=2m +TimeoutSec=@TIMEOUT_MIN@m WatchdogSec=60s RestartSec=5 Restart=on-abnormal diff --git a/tools/frr_babeltrace.py b/tools/frr_babeltrace.py index 3058395758..27d830a119 100755 --- a/tools/frr_babeltrace.py +++ b/tools/frr_babeltrace.py @@ -1,5 +1,5 @@ #!/usr/bin/env python3 -''' +""" Usage: frr_babeltrace.py trace_path FRR pushes data into lttng tracepoints in the least overhead way possible @@ -23,7 +23,7 @@ more details. You should have received a copy of the GNU General Public License along with this program; see the file COPYING; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA -''' +""" import ipaddress import socket @@ -33,56 +33,56 @@ import babeltrace ########################### common parsers - start ############################ def print_ip_addr(field_val): - ''' + """ pretty print "struct ipaddr" - ''' + """ if field_val[0] == socket.AF_INET: addr = [str(fv) for fv in field_val[4:8]] - return str(ipaddress.IPv4Address('.'.join(addr))) + return str(ipaddress.IPv4Address(".".join(addr))) if field_val[0] == socket.AF_INET6: - tmp = ''.join('%02x' % fb for fb in field_val[4:]) + tmp = "".join("%02x" % fb for fb in field_val[4:]) addr = [] while tmp: addr.append(tmp[:4]) tmp = tmp[4:] - addr = ':'.join(addr) + addr = ":".join(addr) return str(ipaddress.IPv6Address(addr)) if not field_val[0]: - return '' + return "" return field_val def print_mac(field_val): - ''' + """ pretty print "u8 mac[6]" - ''' - return ':'.join('%02x' % fb for fb in field_val) + """ + return ":".join("%02x" % fb for fb in field_val) def print_net_ipv4_addr(field_val): - ''' + """ pretty print ctf_integer_network ipv4 - ''' + """ return str(ipaddress.IPv4Address(field_val)) def print_esi(field_val): - ''' + """ pretty print ethernet segment id, esi_t - ''' - return ':'.join('%02x' % fb for fb in field_val) + """ + return ":".join("%02x" % fb for fb in field_val) def get_field_list(event): - ''' + """ only fetch fields added via the TP, skip metadata etc. - ''' + """ return event.field_list_with_scope(babeltrace.CTFScope.EVENT_FIELDS) def parse_event(event, field_parsers): - ''' + """ Wild card event parser; doesn't make things any prettier - ''' + """ field_list = get_field_list(event) field_info = {} for field in field_list: @@ -96,7 +96,7 @@ def parse_event(event, field_parsers): ############################ evpn parsers - start ############################# def parse_frr_bgp_evpn_mac_ip_zsend(event): - ''' + """ bgp evpn mac-ip parser; raw format - ctf_array(unsigned char, mac, &pfx->prefix.macip_addr.mac, sizeof(struct ethaddr)) @@ -104,53 +104,156 @@ def parse_frr_bgp_evpn_mac_ip_zsend(event): sizeof(struct ipaddr)) ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) ctf_array(unsigned char, esi, esi, sizeof(esi_t)) - ''' - field_parsers = {'ip': print_ip_addr, - 'mac': print_mac, - 'esi': print_esi, - 'vtep': print_net_ipv4_addr} + """ + field_parsers = {"ip": print_ip_addr, + "mac": print_mac, + "esi": print_esi, + "vtep": print_net_ipv4_addr} parse_event(event, field_parsers) def parse_frr_bgp_evpn_bum_vtep_zsend(event): - ''' + """ bgp evpn bum-vtep parser; raw format - ctf_integer_network_hex(unsigned int, vtep, pfx->prefix.imet_addr.ip.ipaddr_v4.s_addr) - ''' - field_parsers = {'vtep': print_net_ipv4_addr} + """ + field_parsers = {"vtep": print_net_ipv4_addr} parse_event(event, field_parsers) def parse_frr_bgp_evpn_mh_nh_rmac_send(event): - ''' + """ bgp evpn nh-rmac parser; raw format - ctf_array(unsigned char, rmac, &nh->rmac, sizeof(struct ethaddr)) - ''' - field_parsers = {'rmac': print_mac} + """ + field_parsers = {"rmac": print_mac} parse_event(event, field_parsers) -############################ evpn parsers - end ############################# +def parse_frr_bgp_evpn_mh_local_es_add_zrecv(event): + """ + bgp evpn local-es parser; raw format - + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + """ + field_parsers = {"esi": print_esi, + "vtep": print_net_ipv4_addr} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_mh_local_es_del_zrecv(event): + """ + bgp evpn local-es parser; raw format - + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + """ + field_parsers = {"esi": print_esi} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_mh_local_es_evi_add_zrecv(event): + """ + bgp evpn local-es-evi parser; raw format - + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + """ + field_parsers = {"esi": print_esi} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_mh_local_es_evi_del_zrecv(event): + """ + bgp evpn local-es-evi parser; raw format - + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + """ + field_parsers = {"esi": print_esi} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_local_vni_add_zrecv(event): + """ + bgp evpn local-vni parser; raw format - + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_integer_network_hex(unsigned int, mc_grp, mc_grp.s_addr) + """ + field_parsers = {"vtep": print_net_ipv4_addr, + "mc_grp": print_net_ipv4_addr} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_local_l3vni_add_zrecv(event): + """ + bgp evpn local-l3vni parser; raw format - + ctf_integer_network_hex(unsigned int, vtep, vtep.s_addr) + ctf_array(unsigned char, svi_rmac, svi_rmac, sizeof(struct ethaddr)) + ctf_array(unsigned char, vrr_rmac, vrr_rmac, sizeof(struct ethaddr)) + """ + field_parsers = {"vtep": print_net_ipv4_addr, + "svi_rmac": print_mac, + "vrr_rmac": print_mac} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_local_macip_add_zrecv(event): + """ + bgp evpn local-mac-ip parser; raw format - + ctf_array(unsigned char, ip, ip, sizeof(struct ipaddr)) + ctf_array(unsigned char, mac, mac, sizeof(struct ethaddr)) + ctf_array(unsigned char, esi, esi, sizeof(esi_t)) + """ + field_parsers = {"ip": print_ip_addr, + "mac": print_mac, + "esi": print_esi} + + parse_event(event, field_parsers) + +def parse_frr_bgp_evpn_local_macip_del_zrecv(event): + """ + bgp evpn local-mac-ip del parser; raw format - + ctf_array(unsigned char, ip, ip, sizeof(struct ipaddr)) + ctf_array(unsigned char, mac, mac, sizeof(struct ethaddr)) + """ + field_parsers = {"ip": print_ip_addr, + "mac": print_mac} + + parse_event(event, field_parsers) + +############################ evpn parsers - end *############################# def main(): - ''' + """ FRR lttng trace output parser; babel trace plugin - ''' - event_parsers = {'frr_bgp:evpn_mac_ip_zsend': + """ + event_parsers = {"frr_bgp:evpn_mac_ip_zsend": parse_frr_bgp_evpn_mac_ip_zsend, - 'frr_bgp:evpn_bum_vtep_zsend': + "frr_bgp:evpn_bum_vtep_zsend": parse_frr_bgp_evpn_bum_vtep_zsend, - 'frr_bgp:evpn_mh_nh_rmac_zsend': - parse_frr_bgp_evpn_mh_nh_rmac_send} + "frr_bgp:evpn_mh_nh_rmac_zsend": + parse_frr_bgp_evpn_mh_nh_rmac_send, + "frr_bgp:evpn_mh_local_es_add_zrecv": + parse_frr_bgp_evpn_mh_local_es_add_zrecv, + "frr_bgp:evpn_mh_local_es_del_zrecv": + parse_frr_bgp_evpn_mh_local_es_del_zrecv, + "frr_bgp:evpn_mh_local_es_evi_add_zrecv": + parse_frr_bgp_evpn_mh_local_es_evi_add_zrecv, + "frr_bgp:evpn_mh_local_es_evi_del_zrecv": + parse_frr_bgp_evpn_mh_local_es_evi_del_zrecv, + "frr_bgp:evpn_local_vni_add_zrecv": + parse_frr_bgp_evpn_local_vni_add_zrecv, + "frr_bgp:evpn_local_l3vni_add_zrecv": + parse_frr_bgp_evpn_local_l3vni_add_zrecv, + "frr_bgp:evpn_local_macip_add_zrecv": + parse_frr_bgp_evpn_local_macip_add_zrecv, + "frr_bgp:evpn_local_macip_del_zrecv": + parse_frr_bgp_evpn_local_macip_del_zrecv, +} # get the trace path from the first command line argument trace_path = sys.argv[1] # grab events trace_collection = babeltrace.TraceCollection() - trace_collection.add_traces_recursive(trace_path, 'ctf') + trace_collection.add_traces_recursive(trace_path, "ctf") for event in trace_collection.events: if event.name in event_parsers: @@ -159,5 +262,5 @@ def main(): else: parse_event(event, {}) -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/tools/generate_support_bundle.py b/tools/generate_support_bundle.py index 56b2872d1e..104d9714d4 100755 --- a/tools/generate_support_bundle.py +++ b/tools/generate_support_bundle.py @@ -26,19 +26,28 @@ import os import subprocess import tempfile + def open_with_backup(path): if os.path.exists(path): print("Making backup of " + path) - subprocess.check_call("mv {0} {0}.prev".format(path)) + subprocess.check_call("mv {0} {0}.prev".format(path), shell=True) return open(path, "w") + def main(): parser = argparse.ArgumentParser() - parser.add_argument("-c", "--config", default="/etc/frr/support_bundle_commands.conf", help="input config") - parser.add_argument("-l", "--log-dir", default="/var/log/frr", help="directory for logfiles") + parser.add_argument( + "-c", + "--config", + default="/etc/frr/support_bundle_commands.conf", + help="input config", + ) + parser.add_argument( + "-l", "--log-dir", default="/var/log/frr", help="directory for logfiles" + ) args = parser.parse_args() - collecting = False # file format has sentinels (seem superfluous) + collecting = False # file format has sentinels (seem superfluous) proc_cmds = {} proc = None temp = None @@ -85,5 +94,6 @@ def main(): for p in procs: p.wait() + if __name__ == "__main__": main() diff --git a/tools/release_notes.py b/tools/release_notes.py new file mode 100755 index 0000000000..7481cc18c3 --- /dev/null +++ b/tools/release_notes.py @@ -0,0 +1,93 @@ +#!/usr/bin/python3 +# +# 2021 Jafar Al-Gharaibeh, ATCorp +# +# Generate a draft FRR release notes +# + +import sys +import os +import getopt +import subprocess + +def run(cmd): + proc = subprocess.Popen(cmd, stdout=subprocess.PIPE) + rv = proc.communicate("")[0].decode("UTF-8") + proc.wait() + return rv + + +def usage(n): + print(os.path.basename(__file__), " [-b <branch>] [-t <tag> ]") + print(" Generate one line logs for non merge commits") + print(" -branch: branch name to use, default to HEAD") + print(" -tag : generate logs up to this tag, default to latest tag") + sys.exit(n) + + +def main(argv): + branch = tag = None + try: + opts, args = getopt.getopt(argv, "hb:t:", ["branch=", "tag="]) + except getopt.GetoptError: + usage(2) + for opt, arg in opts: + if opt == "-h": + usage(0) + elif opt in ("-b", "--branch"): + branch = arg + elif opt in ("-t", "--tag"): + tag = arg + + if branch is None: + branch = "HEAD" + if tag is None: + tag = run(["git", "describe", "--abbrev=0"]).strip("\n") + + chnglog = run( + ["git", "log", "--no-merges", "--pretty=format:'%s%d'", tag + ".." + branch] + ) + chnglog = chnglog.split("\n") + + chnglist = [] + daemons = [ + "babel", + "bgp", + "eigrp", + "nhrp", + "ospf", + "ospf6", + "pbr", + "pim", + "rip", + "ripng", + "sharp", + "vrrp", + "zebra", + ] + + for line in chnglog: + line = line.strip("'") + colon = line.partition(":") + label = colon[0].strip().lower() + if label in daemons: + label = label + "d" + comment = colon[2].strip().capitalize() + chnglist.append(label + ":" + comment) + + chnglist.sort() + lastlabel = "" + for line in chnglist: + colon = line.partition(":") + label = colon[0] + comment = colon[2] + if label != lastlabel: + print("") + print(label) + lastlabel = label + + print(" ", comment) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/tools/subdir.am b/tools/subdir.am index e4b9ecd84f..64ca0bd514 100644 --- a/tools/subdir.am +++ b/tools/subdir.am @@ -21,6 +21,7 @@ sbin_SCRIPTS += \ tools/frrcommon.sh \ tools/frrinit.sh \ tools/generate_support_bundle.py \ + tools/frr_babeltrace.py \ tools/watchfrr.sh \ # end @@ -58,6 +59,7 @@ EXTRA_DIST += \ tools/frr.service \ tools/frr@.service \ tools/generate_support_bundle.py \ + tools/frr_babeltrace.py \ tools/multiple-bgpd.sh \ tools/rrcheck.pl \ tools/rrlookup.pl \ diff --git a/tools/valgrind.supp b/tools/valgrind.supp index 88f46bf575..da3d4a8d6d 100644 --- a/tools/valgrind.supp +++ b/tools/valgrind.supp @@ -78,3 +78,11 @@ ... fun:yang_module_load } +{ + <libyang2 lys_compile_type_range> + Memcheck:Leak + ... + fun:lys_compile_type_range + ... + fun:yang_module_load +} diff --git a/vrrpd/subdir.am b/vrrpd/subdir.am index dfa9b261c3..02e0497eef 100644 --- a/vrrpd/subdir.am +++ b/vrrpd/subdir.am @@ -3,17 +3,17 @@ # if VRRPD -noinst_LIBRARIES += vrrpd/libvrrp.a sbin_PROGRAMS += vrrpd/vrrpd vtysh_scan += vrrpd/vrrp_vty.c vtysh_daemons += vrrpd man8 += $(MANBUILD)/frr-vrrpd.8 endif -vrrpd_libvrrp_a_SOURCES = \ +vrrpd_vrrpd_SOURCES = \ vrrpd/vrrp.c \ vrrpd/vrrp_arp.c \ vrrpd/vrrp_debug.c \ + vrrpd/vrrp_main.c \ vrrpd/vrrp_ndisc.c \ vrrpd/vrrp_northbound.c \ vrrpd/vrrp_packet.c \ @@ -35,8 +35,7 @@ clippy_scan += \ vrrpd/vrrp_vty.c \ # end -vrrpd_vrrpd_SOURCES = vrrpd/vrrp_main.c -vrrpd_vrrpd_LDADD = vrrpd/libvrrp.a lib/libfrr.la @LIBCAP@ +vrrpd_vrrpd_LDADD = lib/libfrr.la @LIBCAP@ nodist_vrrpd_vrrpd_SOURCES = \ yang/frr-vrrpd.yang.c \ # end diff --git a/vrrpd/vrrp.c b/vrrpd/vrrp.c index 775611b3e3..4e2c12c4e0 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -216,7 +216,7 @@ static struct vrrp_vrouter *vrrp_lookup_by_if_mvl(struct interface *mvl_ifp) return NULL; } - p = if_lookup_by_index(mvl_ifp->link_ifindex, mvl_ifp->vrf_id); + p = if_lookup_by_index(mvl_ifp->link_ifindex, mvl_ifp->vrf->vrf_id); if (!p) { DEBUGD(&vrrp_dbg_zebra, @@ -544,7 +544,7 @@ static bool vrrp_attach_interface(struct vrrp_router *r) size_t ifps_cnt = if_lookup_by_hwaddr(r->vmac.octet, sizeof(r->vmac.octet), &ifps, - r->vr->ifp->vrf_id); + r->vr->ifp->vrf->vrf_id); /* * Filter to only those macvlan interfaces whose parent is the base @@ -1083,9 +1083,9 @@ static int vrrp_socket(struct vrrp_router *r) frr_with_privs(&vrrp_privs) { r->sock_rx = vrf_socket(r->family, SOCK_RAW, IPPROTO_VRRP, - r->vr->ifp->vrf_id, NULL); + r->vr->ifp->vrf->vrf_id, NULL); r->sock_tx = vrf_socket(r->family, SOCK_RAW, IPPROTO_VRRP, - r->vr->ifp->vrf_id, NULL); + r->vr->ifp->vrf->vrf_id, NULL); } if (r->sock_rx < 0 || r->sock_tx < 0) { @@ -1102,7 +1102,7 @@ static int vrrp_socket(struct vrrp_router *r) * Bind Tx socket to macvlan device - necessary for VRF support, * otherwise the kernel will select the vrf device */ - if (r->vr->ifp->vrf_id != VRF_DEFAULT) { + if (r->vr->ifp->vrf->vrf_id != VRF_DEFAULT) { frr_with_privs (&vrrp_privs) { ret = setsockopt(r->sock_tx, SOL_SOCKET, SO_BINDTODEVICE, r->mvl_ifp->name, @@ -1751,7 +1751,7 @@ vrrp_autoconfig_autocreate(struct interface *mvl_ifp) struct interface *p; struct vrrp_vrouter *vr; - p = if_lookup_by_index(mvl_ifp->link_ifindex, mvl_ifp->vrf_id); + p = if_lookup_by_index(mvl_ifp->link_ifindex, mvl_ifp->vrf->vrf_id); if (!p) return NULL; diff --git a/vrrpd/vrrp_main.c b/vrrpd/vrrp_main.c index 990fa9e382..59769788e7 100644 --- a/vrrpd/vrrp_main.c +++ b/vrrpd/vrrp_main.c @@ -93,7 +93,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t vrrp_signals[] = { +struct frr_signal_t vrrp_signals[] = { { .signal = SIGHUP, .handler = &sighup, diff --git a/vrrpd/vrrp_vty.c b/vrrpd/vrrp_vty.c index 91ff6fe28e..c11254c71a 100644 --- a/vrrpd/vrrp_vty.c +++ b/vrrpd/vrrp_vty.c @@ -75,7 +75,7 @@ DEFPY_YANG(vrrp_vrid, return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); } -void cli_show_vrrp(struct vty *vty, struct lyd_node *dnode, bool show_defaults) +void cli_show_vrrp(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrid = yang_dnode_get_string(dnode, "./virtual-router-id"); const char *ver = yang_dnode_get_string(dnode, "./version"); @@ -103,7 +103,7 @@ DEFPY_YANG(vrrp_shutdown, return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); } -void cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, +void cli_show_shutdown(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id"); @@ -145,7 +145,7 @@ DEFPY_YANG(no_vrrp_priority, return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); } -void cli_show_priority(struct vty *vty, struct lyd_node *dnode, +void cli_show_priority(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id"); @@ -191,7 +191,7 @@ DEFPY_YANG(no_vrrp_advertisement_interval, return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); } -void cli_show_advertisement_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_advertisement_interval(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id"); @@ -220,7 +220,7 @@ DEFPY_YANG(vrrp_ip, return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); } -void cli_show_ip(struct vty *vty, struct lyd_node *dnode, bool show_defaults) +void cli_show_ip(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrid = yang_dnode_get_string(dnode, "../../virtual-router-id"); @@ -248,7 +248,7 @@ DEFPY_YANG(vrrp_ip6, return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); } -void cli_show_ipv6(struct vty *vty, struct lyd_node *dnode, bool show_defaults) +void cli_show_ipv6(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrid = yang_dnode_get_string(dnode, "../../virtual-router-id"); @@ -274,7 +274,7 @@ DEFPY_YANG(vrrp_preempt, return nb_cli_apply_changes(vty, VRRP_XPATH_ENTRY, vrid); } -void cli_show_preempt(struct vty *vty, struct lyd_node *dnode, +void cli_show_preempt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults) { const char *vrid = yang_dnode_get_string(dnode, "../virtual-router-id"); @@ -715,35 +715,6 @@ DEFUN_NOSH (show_debugging_vrrp, /* clang-format on */ -/* - * Write per interface VRRP config. - */ -static int vrrp_config_write_interface(struct vty *vty) -{ - struct vrf *vrf; - int write = 0; - - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct interface *ifp; - - FOR_ALL_INTERFACES (vrf, ifp) { - struct lyd_node *dnode; - - dnode = yang_dnode_getf( - running_config->dnode, - "/frr-interface:lib/interface[name='%s'][vrf='%s']", - ifp->name, vrf->name); - if (dnode == NULL) - continue; - - write = 1; - nb_cli_show_dnode_cmds(vty, dnode, false); - } - } - - return write; -} - static struct cmd_node debug_node = { .name = "debug", .node = DEBUG_NODE, @@ -763,7 +734,7 @@ void vrrp_vty_init(void) install_node(&debug_node); install_node(&vrrp_node); vrf_cmd_init(NULL); - if_cmd_init(vrrp_config_write_interface); + if_cmd_init_default(); install_element(VIEW_NODE, &vrrp_vrid_show_cmd); install_element(VIEW_NODE, &vrrp_vrid_show_summary_cmd); diff --git a/vrrpd/vrrp_vty.h b/vrrpd/vrrp_vty.h index 6c6eef0327..587537a6f3 100644 --- a/vrrpd/vrrp_vty.h +++ b/vrrpd/vrrp_vty.h @@ -25,16 +25,20 @@ void vrrp_vty_init(void); /* Northbound callbacks */ -void cli_show_vrrp(struct vty *vty, struct lyd_node *dnode, bool show_defaults); -void cli_show_shutdown(struct vty *vty, struct lyd_node *dnode, +void cli_show_vrrp(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); +void cli_show_shutdown(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_priority(struct vty *vty, struct lyd_node *dnode, +void cli_show_priority(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); -void cli_show_advertisement_interval(struct vty *vty, struct lyd_node *dnode, +void cli_show_advertisement_interval(struct vty *vty, + const struct lyd_node *dnode, bool show_defaults); -void cli_show_ip(struct vty *vty, struct lyd_node *dnode, bool show_defaults); -void cli_show_ipv6(struct vty *vty, struct lyd_node *dnode, bool show_defaults); -void cli_show_preempt(struct vty *vty, struct lyd_node *dnode, +void cli_show_ip(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); +void cli_show_ipv6(struct vty *vty, const struct lyd_node *dnode, + bool show_defaults); +void cli_show_preempt(struct vty *vty, const struct lyd_node *dnode, bool show_defaults); #endif /* __VRRP_VTY_H__ */ diff --git a/vrrpd/vrrp_zebra.c b/vrrpd/vrrp_zebra.c index 385d443571..4cea8ebe4a 100644 --- a/vrrpd/vrrp_zebra.c +++ b/vrrpd/vrrp_zebra.c @@ -34,15 +34,15 @@ static struct zclient *zclient; -static void vrrp_zebra_debug_if_state(struct interface *ifp, vrf_id_t vrf_id, - const char *func) +static void vrrp_zebra_debug_if_state(struct interface *ifp, const char *func) { DEBUGD(&vrrp_dbg_zebra, - "%s: %s index %d(%u) parent %d mac %02x:%02x:%02x:%02x:%02x:%02x flags %ld metric %d mtu %d operative %d", - func, ifp->name, vrf_id, ifp->link_ifindex, ifp->ifindex, - ifp->hw_addr[0], ifp->hw_addr[1], ifp->hw_addr[2], - ifp->hw_addr[3], ifp->hw_addr[4], ifp->hw_addr[5], - (long)ifp->flags, ifp->metric, ifp->mtu, if_is_operative(ifp)); + "%s: %s index %d vrf %s(%u) parent %d mac %02x:%02x:%02x:%02x:%02x:%02x flags %ld metric %d mtu %d operative %d", + func, ifp->name, ifp->ifindex, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->link_ifindex, ifp->hw_addr[0], ifp->hw_addr[1], + ifp->hw_addr[2], ifp->hw_addr[3], ifp->hw_addr[4], + ifp->hw_addr[5], (long)ifp->flags, ifp->metric, ifp->mtu, + if_is_operative(ifp)); } static void vrrp_zebra_debug_if_dump_address(struct interface *ifp, @@ -82,7 +82,7 @@ static int vrrp_router_id_update_zebra(int command, struct zclient *zclient, int vrrp_ifp_create(struct interface *ifp) { - vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__); + vrrp_zebra_debug_if_state(ifp, __func__); vrrp_if_add(ifp); @@ -91,7 +91,7 @@ int vrrp_ifp_create(struct interface *ifp) int vrrp_ifp_destroy(struct interface *ifp) { - vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__); + vrrp_zebra_debug_if_state(ifp, __func__); vrrp_if_del(ifp); @@ -100,7 +100,7 @@ int vrrp_ifp_destroy(struct interface *ifp) int vrrp_ifp_up(struct interface *ifp) { - vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__); + vrrp_zebra_debug_if_state(ifp, __func__); vrrp_if_up(ifp); @@ -109,7 +109,7 @@ int vrrp_ifp_up(struct interface *ifp) int vrrp_ifp_down(struct interface *ifp) { - vrrp_zebra_debug_if_state(ifp, ifp->vrf_id, __func__); + vrrp_zebra_debug_if_state(ifp, __func__); vrrp_if_down(ifp); @@ -134,7 +134,7 @@ static int vrrp_zebra_if_address_add(int command, struct zclient *zclient, if (!c) return 0; - vrrp_zebra_debug_if_state(c->ifp, vrf_id, __func__); + vrrp_zebra_debug_if_state(c->ifp, __func__); vrrp_zebra_debug_if_dump_address(c->ifp, __func__); vrrp_if_address_add(c->ifp); @@ -160,7 +160,7 @@ static int vrrp_zebra_if_address_del(int command, struct zclient *client, if (!c) return 0; - vrrp_zebra_debug_if_state(c->ifp, vrf_id, __func__); + vrrp_zebra_debug_if_state(c->ifp, __func__); vrrp_zebra_debug_if_dump_address(c->ifp, __func__); vrrp_if_address_del(c->ifp); @@ -175,8 +175,8 @@ void vrrp_zebra_radv_set(struct vrrp_router *r, bool enable) "Requesting Zebra to turn router advertisements %s for %s", r->vr->vrid, enable ? "on" : "off", r->mvl_ifp->name); - zclient_send_interface_radv_req(zclient, r->mvl_ifp->vrf_id, r->mvl_ifp, - enable, VRRP_RADV_INT); + zclient_send_interface_radv_req(zclient, r->mvl_ifp->vrf->vrf_id, + r->mvl_ifp, enable, VRRP_RADV_INT); } void vrrp_zclient_send_interface_protodown(struct interface *ifp, bool down) @@ -185,21 +185,25 @@ void vrrp_zclient_send_interface_protodown(struct interface *ifp, bool down) VRRP_LOGPFX "Requesting Zebra to set %s protodown %s", ifp->name, down ? "on" : "off"); - zclient_send_interface_protodown(zclient, ifp->vrf_id, ifp, down); + zclient_send_interface_protodown(zclient, ifp->vrf->vrf_id, ifp, down); } +static zclient_handler *const vrrp_handlers[] = { + [ZEBRA_ROUTER_ID_UPDATE] = vrrp_router_id_update_zebra, + [ZEBRA_INTERFACE_ADDRESS_ADD] = vrrp_zebra_if_address_add, + [ZEBRA_INTERFACE_ADDRESS_DELETE] = vrrp_zebra_if_address_del, +}; + void vrrp_zebra_init(void) { if_zapi_callbacks(vrrp_ifp_create, vrrp_ifp_up, vrrp_ifp_down, vrrp_ifp_destroy); /* Socket for receiving updates from Zebra daemon */ - zclient = zclient_new(master, &zclient_options_default); + zclient = zclient_new(master, &zclient_options_default, vrrp_handlers, + array_size(vrrp_handlers)); zclient->zebra_connected = vrrp_zebra_connected; - zclient->router_id_update = vrrp_router_id_update_zebra; - zclient->interface_address_add = vrrp_zebra_if_address_add; - zclient->interface_address_delete = vrrp_zebra_if_address_del; zclient_init(zclient, ZEBRA_ROUTE_VRRP, 0, &vrrp_privs); diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index beb7045a7d..c56b72fcbb 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -484,7 +484,7 @@ static int vtysh_execute_func(const char *line, int pager) if (vtysh_add_timestamp && strncmp(line, "exit", 4)) { char ts[48]; - (void)quagga_timestamp(3, ts, sizeof(ts)); + (void)frr_timestamp(3, ts, sizeof(ts)); vty_out(vty, "%% %s\n\n", ts); } @@ -1184,7 +1184,6 @@ static struct cmd_node srte_candidate_dyn_node = { .prompt = "%s(config-sr-te-candidate)# ", }; -#if defined(HAVE_PATHD_PCEP) static struct cmd_node pcep_node = { .name = "srte pcep", .node = PCEP_NODE, @@ -1212,7 +1211,6 @@ static struct cmd_node pcep_pce_config_node = { .parent_node = PCEP_NODE, .prompt = "%s(pcep-sr-te-pcep-pce-config)# ", }; -#endif /* HAVE_PATHD_PCEP */ #endif /* HAVE_PATHD */ static struct cmd_node vrf_node = { @@ -1279,6 +1277,7 @@ static struct cmd_node bgp_vpnv4_node = { .node = BGP_VPNV4_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_vpnv6_node = { @@ -1286,6 +1285,7 @@ static struct cmd_node bgp_vpnv6_node = { .node = BGP_VPNV6_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_flowspecv4_node = { @@ -1293,6 +1293,7 @@ static struct cmd_node bgp_flowspecv4_node = { .node = BGP_FLOWSPECV4_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_flowspecv6_node = { @@ -1300,6 +1301,7 @@ static struct cmd_node bgp_flowspecv6_node = { .node = BGP_FLOWSPECV6_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv4_node = { @@ -1307,6 +1309,7 @@ static struct cmd_node bgp_ipv4_node = { .node = BGP_IPV4_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv4m_node = { @@ -1314,6 +1317,7 @@ static struct cmd_node bgp_ipv4m_node = { .node = BGP_IPV4M_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv4l_node = { @@ -1321,6 +1325,7 @@ static struct cmd_node bgp_ipv4l_node = { .node = BGP_IPV4L_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv6_node = { @@ -1328,6 +1333,7 @@ static struct cmd_node bgp_ipv6_node = { .node = BGP_IPV6_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_ipv6m_node = { @@ -1335,6 +1341,7 @@ static struct cmd_node bgp_ipv6m_node = { .node = BGP_IPV6M_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_evpn_node = { @@ -1342,6 +1349,7 @@ static struct cmd_node bgp_evpn_node = { .node = BGP_EVPN_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; static struct cmd_node bgp_evpn_vni_node = { @@ -1356,6 +1364,7 @@ static struct cmd_node bgp_ipv6l_node = { .node = BGP_IPV6L_NODE, .parent_node = BGP_NODE, .prompt = "%s(config-router-af)# ", + .no_xpath = true, }; #ifdef ENABLE_BGP_VNC @@ -1516,6 +1525,7 @@ struct cmd_node link_params_node = { .node = LINK_PARAMS_NODE, .parent_node = INTERFACE_NODE, .prompt = "%s(config-link-params)# ", + .no_xpath = true, }; #ifdef HAVE_BGPD @@ -1799,22 +1809,6 @@ DEFUNSH(VTYSH_BGPD, address_family_evpn, address_family_evpn_cmd, return CMD_SUCCESS; } -#if defined(HAVE_CUMULUS) -#if CONFDATE > 20211115 -CPP_NOTICE("Use of `address-family evpn` is deprecated please remove don't forget frr-reload.py") -#endif -DEFUNSH_HIDDEN(VTYSH_BGPD, address_family_evpn2, address_family_evpn2_cmd, - "address-family evpn", - "Enter Address Family command mode\n" - "EVPN Address family\n") -{ - vty_out(vty, - "This command is deprecated please convert to `address-family l2vpn evpn`\n"); - vty->node = BGP_EVPN_NODE; - return CMD_SUCCESS; -} -#endif - DEFUNSH(VTYSH_BGPD, bgp_evpn_vni, bgp_evpn_vni_cmd, "vni " CMD_VNI_RANGE, "VXLAN Network Identifier\n" "VNI number\n") @@ -2109,8 +2103,6 @@ DEFUNSH(VTYSH_PATHD, srte_policy_candidate_dyn_path, return CMD_SUCCESS; } -#if defined(HAVE_PATHD_PCEP) - DEFUNSH(VTYSH_PATHD, pcep, pcep_cmd, "pcep", "Configure SR pcep\n") @@ -2145,12 +2137,10 @@ DEFUNSH(VTYSH_PATHD, pcep_cli_pcep_pce_config, pcep_cli_pcep_pce_config_cmd, return CMD_SUCCESS; } -#endif /* HAVE_PATHD_PCEP */ - #endif /* HAVE_PATHD */ DEFUNSH(VTYSH_RMAP, vtysh_route_map, vtysh_route_map_cmd, - "route-map WORD <deny|permit> (1-65535)", + "route-map RMAP_NAME <deny|permit> (1-65535)", "Create route-map or enter route-map command mode\n" "Route map tag\n" "Route map denies set operations\n" @@ -3023,6 +3013,60 @@ DEFUNSH(VTYSH_ALL, vtysh_debug_memstats, return CMD_SUCCESS; } +DEFUN(vtysh_debug_uid_backtrace, + vtysh_debug_uid_backtrace_cmd, + "[no] debug unique-id UID backtrace", + NO_STR + DEBUG_STR + "Options per individual log message, by unique ID\n" + "Log message unique ID (XXXXX-XXXXX)\n" + "Add backtrace to log when message is printed\n") +{ + unsigned int i, ok = 0; + int err = CMD_SUCCESS, ret; + const char *uid; + char line[64]; + + if (!strcmp(argv[0]->text, "no")) { + uid = argv[3]->arg; + snprintfrr(line, sizeof(line), + "no debug unique-id %s backtrace", uid); + } else { + uid = argv[2]->arg; + snprintfrr(line, sizeof(line), "debug unique-id %s backtrace", + uid); + } + + for (i = 0; i < array_size(vtysh_client); i++) + if (vtysh_client[i].fd >= 0 || vtysh_client[i].next) { + ret = vtysh_client_execute(&vtysh_client[i], line); + switch (ret) { + case CMD_SUCCESS: + ok++; + break; + case CMD_ERR_NOTHING_TODO: + /* ignore this daemon + * + * note this doesn't need to handle instances + * of the same daemon individually because + * the same daemon will have the same UIDs + */ + break; + default: + if (err == CMD_SUCCESS) + err = ret; + break; + } + } + + if (err == CMD_SUCCESS && !ok) { + vty_out(vty, "%% no running daemon recognizes unique-ID %s\n", + uid); + err = CMD_WARNING; + } + return err; +} + DEFUNSH(VTYSH_ALL, vtysh_service_password_encrypt, vtysh_service_password_encrypt_cmd, "service password-encryption", "Set up miscellaneous service\n" @@ -3923,6 +3967,8 @@ void vtysh_uninit(void) void vtysh_init_vty(void) { + cmd_defer_tree(true); + /* Make vty structure. */ vty = vty_new(); vty->type = VTY_SHELL; @@ -4052,9 +4098,6 @@ void vtysh_init_vty(void) install_node(&bgp_evpn_node); install_element(BGP_NODE, &address_family_evpn_cmd); -#if defined(HAVE_CUMULUS) - install_element(BGP_NODE, &address_family_evpn2_cmd); -#endif 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); @@ -4268,7 +4311,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); -#if defined(HAVE_PATHD_PCEP) install_node(&pcep_node); install_node(&pcep_pcc_node); install_node(&pcep_pce_node); @@ -4292,7 +4334,6 @@ void vtysh_init_vty(void) install_element(PCEP_NODE, &pcep_cli_pcc_cmd); install_element(PCEP_NODE, &pcep_cli_pcep_pce_config_cmd); install_element(PCEP_NODE, &pcep_cli_pce_cmd); -#endif /* HAVE_PATHD_PCEP */ #endif /* HAVE_PATHD */ @@ -4447,6 +4488,8 @@ void vtysh_init_vty(void) install_element(CONFIG_NODE, &vtysh_debug_all_cmd); install_element(ENABLE_NODE, &vtysh_debug_memstats_cmd); install_element(CONFIG_NODE, &vtysh_debug_memstats_cmd); + install_element(ENABLE_NODE, &vtysh_debug_uid_backtrace_cmd); + install_element(CONFIG_NODE, &vtysh_debug_uid_backtrace_cmd); /* northbound */ install_element(ENABLE_NODE, &show_config_running_cmd); diff --git a/vtysh/vtysh_config.c b/vtysh/vtysh_config.c index 7d66319669..3bd5489eef 100644 --- a/vtysh/vtysh_config.c +++ b/vtysh/vtysh_config.c @@ -44,8 +44,12 @@ struct config { /* Configuration string line. */ struct list *line; - /* Configuration can be nest. */ - struct config *config; + /* Configuration can be nested. */ + struct config *parent; + vector nested; + + /* Exit command. */ + char *exit; /* Index of this config. */ uint32_t index; @@ -76,7 +80,10 @@ static struct config *config_new(void) static void config_del(struct config *config) { + vector_free(config->nested); list_delete(&config->line); + if (config->exit) + XFREE(MTYPE_VTYSH_CONFIG_LINE, config->exit); XFREE(MTYPE_VTYSH_CONFIG_LINE, config->name); XFREE(MTYPE_VTYSH_CONFIG, config); } @@ -104,7 +111,7 @@ struct configuration { struct config_master_hash_head hash_master; }; -static struct config *config_get(int index, const char *line) +static struct config *config_get_vec(vector vec, int index, const char *line) { struct config *config, *config_loop; struct configuration *configuration; @@ -112,14 +119,14 @@ static struct config *config_get(int index, const char *line) config = config_loop = NULL; - configuration = vector_lookup_ensure(configvec, index); + configuration = vector_lookup_ensure(vec, index); if (!configuration) { configuration = XMALLOC(MTYPE_VTYSH_CONFIG, sizeof(struct configuration)); config_master_init(&configuration->master); config_master_hash_init(&configuration->hash_master); - vector_set_index(configvec, index, configuration); + vector_set_index(vec, index, configuration); } lookup.name = (char *)line; @@ -131,13 +138,31 @@ static struct config *config_get(int index, const char *line) config->line->del = (void (*)(void *))line_del; config->line->cmp = (int (*)(void *, void *))line_cmp; config->name = XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line); + config->exit = NULL; config->index = index; + config->nested = vector_init(1); config_master_add_tail(&configuration->master, config); config_master_hash_add(&configuration->hash_master, config); } return config; } +static struct config *config_get(int index, const char *line) +{ + return config_get_vec(configvec, index, line); +} + +static struct config *config_get_nested(struct config *parent, int index, + const char *line) +{ + struct config *config; + + config = config_get_vec(parent->nested, index, line); + config->parent = parent; + + return config; +} + void config_add_line(struct list *config, const char *line) { listnode_add(config, XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line)); @@ -259,9 +284,23 @@ void vtysh_config_parse_line(void *arg, const char *line) case ' ': /* Store line to current configuration. */ if (config) { - if (strncmp(line, " link-params", - strlen(" link-params")) - == 0) { + if (config->index == KEYCHAIN_NODE + && strncmp(line, " key", strlen(" key")) == 0) { + config = config_get_nested( + config, KEYCHAIN_KEY_NODE, line); + } else if (config->index == KEYCHAIN_KEY_NODE) { + if (strncmp(line, " exit", strlen(" exit")) + == 0) { + config_add_line_uniq_end(config->line, + line); + config = config->parent; + } else { + config_add_line_uniq(config->line, + line); + } + } else if (strncmp(line, " link-params", + strlen(" link-params")) + == 0) { config_add_line(config->line, line); config->index = LINK_PARAMS_NODE; } else if (strncmp(line, " ip multicast boundary", @@ -269,7 +308,8 @@ void vtysh_config_parse_line(void *arg, const char *line) == 0) { config_add_line_uniq_end(config->line, line); } else if (strncmp(line, " ip igmp query-interval", - strlen(" ip igmp query-interval")) == 0) { + strlen(" ip igmp query-interval")) + == 0) { config_add_line_uniq_end(config->line, line); } else if (config->index == LINK_PARAMS_NODE && strncmp(line, " exit-link-params", @@ -281,7 +321,8 @@ void vtysh_config_parse_line(void *arg, const char *line) || !strncmp(line, " no vrrp", strlen(" no vrrp"))) { config_add_line(config->line, line); - } else if (!strncmp(line, " ip mroute", strlen(" ip mroute"))) { + } else if (!strncmp(line, " ip mroute", + strlen(" ip mroute"))) { config_add_line_uniq_end(config->line, line); } else if (config->index == RMAP_NODE || config->index == INTERFACE_NODE @@ -296,7 +337,8 @@ void vtysh_config_parse_line(void *arg, const char *line) default: if (strncmp(line, "exit", strlen("exit")) == 0) { if (config) - config_add_line_uniq_end(config->line, line); + config->exit = + XSTRDUP(MTYPE_VTYSH_CONFIG_LINE, line); } else if (strncmp(line, "interface", strlen("interface")) == 0) config = config_get(INTERFACE_NODE, line); else if (strncmp(line, "pseudowire", strlen("pseudowire")) == 0) @@ -433,6 +475,8 @@ void vtysh_config_parse_line(void *arg, const char *line) config = config_get(SEGMENT_ROUTING_NODE, line); else if (strncmp(line, "bfd", strlen("bfd")) == 0) config = config_get(BFD_NODE, line); + else if (strncmp(line, "rpki", strlen("rpki")) == 0) + config = config_get(RPKI_NODE, line); else { if (strncmp(line, "log", strlen("log")) == 0 || strncmp(line, "hostname", strlen("hostname")) == 0 @@ -461,25 +505,18 @@ void vtysh_config_parse_line(void *arg, const char *line) || (I) == FORWARDING_NODE || (I) == DEBUG_NODE || (I) == AAA_NODE \ || (I) == VRF_DEBUG_NODE || (I) == NORTHBOUND_DEBUG_NODE \ || (I) == RMAP_DEBUG_NODE || (I) == RESOLVER_DEBUG_NODE \ - || (I) == MPLS_NODE) + || (I) == MPLS_NODE || (I) == KEYCHAIN_KEY_NODE) -/* Display configuration to file pointer. */ -void vtysh_config_dump(void) +static void configvec_dump(vector vec, bool nested) { - struct listnode *node, *nnode; struct listnode *mnode, *mnnode; struct config *config; struct configuration *configuration; char *line; unsigned int i; - for (ALL_LIST_ELEMENTS(config_top, node, nnode, line)) - vty_out(vty, "%s\n", line); - - vty_out(vty, "!\n"); - - for (i = 0; i < vector_active(configvec); i++) - if ((configuration = vector_slot(configvec, i)) != NULL) { + for (i = 0; i < vector_active(vec); i++) + if ((configuration = vector_slot(vec, i)) != NULL) { while ((config = config_master_pop( &configuration->master))) { config_master_hash_del( @@ -505,23 +542,39 @@ void vtysh_config_dump(void) for (ALL_LIST_ELEMENTS(config->line, mnode, mnnode, line)) vty_out(vty, "%s\n", line); + + configvec_dump(config->nested, true); + + if (config->exit) + vty_out(vty, "%s\n", config->exit); + if (!NO_DELIMITER(i)) vty_out(vty, "!\n"); config_del(config); } - if (NO_DELIMITER(i)) - vty_out(vty, "!\n"); - } - - for (i = 0; i < vector_active(configvec); i++) - if ((configuration = vector_slot(configvec, i)) != NULL) { config_master_fini(&configuration->master); config_master_hash_fini(&configuration->hash_master); XFREE(MTYPE_VTYSH_CONFIG, configuration); - vector_slot(configvec, i) = NULL; + vector_slot(vec, i) = NULL; + if (!nested && NO_DELIMITER(i)) + vty_out(vty, "!\n"); } +} + +void vtysh_config_dump(void) +{ + struct listnode *node, *nnode; + char *line; + + for (ALL_LIST_ELEMENTS(config_top, node, nnode, line)) + vty_out(vty, "%s\n", line); + list_delete_all_node(config_top); + + vty_out(vty, "!\n"); + + configvec_dump(configvec, false); } /* Read up configuration file from file_name. */ diff --git a/watchfrr/watchfrr.c b/watchfrr/watchfrr.c index b09d092458..0d9734a756 100644 --- a/watchfrr/watchfrr.c +++ b/watchfrr/watchfrr.c @@ -1301,7 +1301,7 @@ struct zebra_privs_t watchfrr_privs = { #endif }; -static struct quagga_signal_t watchfrr_signals[] = { +static struct frr_signal_t watchfrr_signals[] = { { .signal = SIGINT, .handler = sigint, diff --git a/yang/confd/confd.frr-ripd.yang b/yang/confd/confd.frr-ripd.yang index 9b21c0756f..7bbe54cca9 100644 --- a/yang/confd/confd.frr-ripd.yang +++ b/yang/confd/confd.frr-ripd.yang @@ -11,8 +11,10 @@ module confd.frr-ripd { tailf:annotate-module "frr-ripd" { tailf:annotate-statement "container[name='ripd']" { - tailf:annotate-statement "container[name='state']" { - tailf:callpoint "state"; + tailf:annotate-statement "list[name='instance']" { + tailf:annotate-statement "container[name='state']" { + tailf:callpoint "state"; + } } } tailf:annotate-statement "rpc[name='clear-rip-route']" { diff --git a/yang/confd/confd.frr-ripngd.yang b/yang/confd/confd.frr-ripngd.yang index 5d876ff4d3..83383fb454 100644 --- a/yang/confd/confd.frr-ripngd.yang +++ b/yang/confd/confd.frr-ripngd.yang @@ -11,8 +11,10 @@ module confd.frr-ripngd { tailf:annotate-module "frr-ripngd" { tailf:annotate-statement "container[name='ripngd']" { - tailf:annotate-statement "container[name='state']" { - tailf:callpoint "state"; + tailf:annotate-statement "list[name='instance']" { + tailf:annotate-statement "container[name='state']" { + tailf:callpoint "state"; + } } } tailf:annotate-statement "rpc[name='clear-ripng-route']" { diff --git a/yang/frr-bgp-bmp.yang b/yang/frr-bgp-bmp.yang index 2417874ea0..cf945cabef 100644 --- a/yang/frr-bgp-bmp.yang +++ b/yang/frr-bgp-bmp.yang @@ -13,6 +13,8 @@ submodule frr-bgp-bmp { prefix frr-bt; } + include "frr-bgp-common-multiprotocol"; + organization "FRRouting"; contact diff --git a/yang/frr-bgp-common-structure.yang b/yang/frr-bgp-common-structure.yang index 2ad22a1435..3378c10c03 100644 --- a/yang/frr-bgp-common-structure.yang +++ b/yang/frr-bgp-common-structure.yang @@ -25,6 +25,8 @@ submodule frr-bgp-common-structure { prefix frr-bt; } + include "frr-bgp-common"; + organization "FRRouting"; contact diff --git a/yang/frr-bgp-neighbor.yang b/yang/frr-bgp-neighbor.yang index 03af643ba2..6d73580661 100644 --- a/yang/frr-bgp-neighbor.yang +++ b/yang/frr-bgp-neighbor.yang @@ -5,6 +5,10 @@ submodule frr-bgp-neighbor { prefix "bgp"; } + include "frr-bgp-common-multiprotocol"; + + include "frr-bgp-common-structure"; + organization "FRRouting"; contact diff --git a/yang/frr-bgp-peer-group.yang b/yang/frr-bgp-peer-group.yang index 80c9ecff2a..15c31bf010 100644 --- a/yang/frr-bgp-peer-group.yang +++ b/yang/frr-bgp-peer-group.yang @@ -13,6 +13,10 @@ submodule frr-bgp-peer-group { prefix frr-bt; } + include "frr-bgp-common-structure"; + + include "frr-bgp-neighbor"; + organization "FRRouting"; contact diff --git a/yang/frr-interface.yang b/yang/frr-interface.yang index 46c03a1d1f..4a152aadda 100644 --- a/yang/frr-interface.yang +++ b/yang/frr-interface.yang @@ -288,13 +288,11 @@ module frr-interface { container lib { list interface { - key "name vrf"; + key "name"; description "Interface."; leaf name { - type string { - length "1..16"; - } + type string; description "Interface name."; } @@ -303,6 +301,7 @@ module frr-interface { type frr-vrf:vrf-ref; description "VRF this interface is associated with."; + config false; } leaf description { diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index c4eb78608b..1e8c04bc6f 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -106,6 +106,18 @@ module frr-route-map { "Match an IPv6 prefix-list"; } + identity ipv6-next-hop-list { + base rmap-match-type; + description + "Match an IPv6 next-hop"; + } + + identity ipv6-next-hop-prefix-list { + base rmap-match-type; + description + "Match an IPv6 next-hop prefix list"; + } + identity ipv6-next-hop-type { base rmap-match-type; description @@ -200,6 +212,8 @@ module frr-route-map { + "derived-from-or-self(../condition, 'ipv4-next-hop-list') or " + "derived-from-or-self(../condition, 'ipv4-next-hop-prefix-list') or " + "derived-from-or-self(../condition, 'ipv6-address-list') or " + + "derived-from-or-self(../condition, 'ipv6-next-hop-list') or " + + "derived-from-or-self(../condition, 'ipv6-next-hop-prefix-list') or " + "derived-from-or-self(../condition, 'ipv6-prefix-list')"; leaf list-name { type filter:access-list-name; diff --git a/yang/frr-routing.yang b/yang/frr-routing.yang index f8441669af..6a721b2924 100644 --- a/yang/frr-routing.yang +++ b/yang/frr-routing.yang @@ -1,7 +1,7 @@ module frr-routing { yang-version "1.1"; namespace "http://frrouting.org/yang/routing"; - prefix "rt"; + prefix "frr-routing"; import ietf-yang-types { prefix "yang"; diff --git a/yang/ietf/frr-ietf-translator.json b/yang/ietf/frr-ietf-translator.json index 38a609982f..36d6ddc8af 100644 --- a/yang/ietf/frr-ietf-translator.json +++ b/yang/ietf/frr-ietf-translator.json @@ -3,20 +3,6 @@ "family": "ietf", "module": [ { - "name": "ietf-interfaces@2018-01-09", - "deviations": "frr-deviations-ietf-interfaces", - "mappings": [ - { - "custom": "/ietf-interfaces:interfaces/interface[name='KEY1']", - "native": "/frr-interface:lib/interface[name='KEY1'][vrf='default']" - }, - { - "custom": "/ietf-interfaces:interfaces/interface[name='KEY1']/description", - "native": "/frr-interface:lib/interface[name='KEY1'][vrf='default']/description" - } - ] - }, - { "name": "ietf-routing@2018-01-25", "deviations": "frr-deviations-ietf-routing", "mappings": [ @@ -60,7 +46,7 @@ }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/interfaces/interface[interface='KEY1']/split-horizon", - "native": "/frr-interface:lib/interface[name='KEY1'][vrf='default']/frr-ripd:rip/split-horizon" + "native": "/frr-interface:lib/interface[name='KEY1']/frr-ripd:rip/split-horizon" }, { "custom": "/ietf-routing:routing/control-plane-protocols/control-plane-protocol[type='ietf-rip:ripv2'][name='main']/ietf-rip:rip/ipv4/neighbors/neighbor[ipv4-address='KEY1']", diff --git a/yang/subdir.am b/yang/subdir.am index a2243fb8e4..828ebd9086 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -88,6 +88,10 @@ dist_yangmodels_DATA += yang/frr-bgp-types.yang dist_yangmodels_DATA += yang/frr-bgp.yang endif +if OSPFD +dist_yangmodels_DATA += yang/frr-ospfd.yang +endif + if PATHD dist_yangmodels_DATA += yang/frr-pathd.yang endif @@ -97,3 +101,29 @@ CLEANFILES += \ yang/ietf/*.c \ yang/confd/*.c \ # + +if CONFD + +SUBMODULES = $(shell cd $(top_srcdir); grep -l belongs-to $(dist_yangmodels_DATA)) +EXCLUDED_MODULES = $(SUBMODULES) yang/frr-module-translator.yang +YANG_MODULES = $(filter-out $(EXCLUDED_MODULES),$(dist_yangmodels_DATA)) + +fxsdir = $(sysconfdir)/confd +fxs_DATA = $(YANG_MODULES:.yang=.fxs) + +SUFFIXES += .fxs +CLEANFILES += $(fxs_DATA) + +AM_V_CONFDC = $(AM_V_CONFDC_@AM_V@) +AM_V_CONFDC_ = $(AM_V_CONFDC_@AM_DEFAULT_V@) +AM_V_CONFDC_0 = @echo " CONFDC " $@; + +CONFDC_FLAGS = --yangpath $(srcdir)/yang --yangpath $(srcdir)/yang/ietf + +yang/%.fxs: yang/%.yang yang/confd/confd.%.yang + $(AM_V_CONFDC)$(CONFDC) $(CONFDC_FLAGS) -c -o $@ -a $(srcdir)/yang/confd/confd.$*.yang -- $< + +yang/%.fxs: yang/%.yang + $(AM_V_CONFDC)$(CONFDC) $(CONFDC_FLAGS) -c -o $@ -- $< + +endif diff --git a/zebra/connected.c b/zebra/connected.c index 80d434bafc..b261ddb791 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -73,7 +73,7 @@ static void connected_announce(struct interface *ifp, struct connected *ifc) if (!ifc) return; - if (!if_is_loopback_or_vrf(ifp) && ifc->address->family == AF_INET) { + if (!if_is_loopback(ifp) && ifc->address->family == AF_INET) { if (ifc->address->prefixlen == IPV4_MAX_BITLEN) SET_FLAG(ifc->flags, ZEBRA_IFA_UNNUMBERED); else @@ -201,7 +201,7 @@ void connected_up(struct interface *ifp, struct connected *ifc) struct nexthop nh = { .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, - .vrf_id = ifp->vrf_id, + .vrf_id = ifp->vrf->vrf_id, }; struct zebra_vrf *zvrf; uint32_t metric; @@ -210,12 +210,12 @@ void connected_up(struct interface *ifp, struct connected *ifc) struct listnode *cnode; struct connected *c; - zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + zvrf = ifp->vrf->info; if (!zvrf) { flog_err( EC_ZEBRA_VRF_NOT_FOUND, - "%s: Received Up for interface but no associated zvrf: %d", - __func__, ifp->vrf_id); + "%s: Received Up for interface but no associated zvrf: %s(%d)", + __func__, ifp->vrf->name, ifp->vrf->vrf_id); return; } if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) @@ -381,19 +381,19 @@ void connected_down(struct interface *ifp, struct connected *ifc) struct nexthop nh = { .type = NEXTHOP_TYPE_IFINDEX, .ifindex = ifp->ifindex, - .vrf_id = ifp->vrf_id, + .vrf_id = ifp->vrf->vrf_id, }; struct zebra_vrf *zvrf; uint32_t count = 0; struct listnode *cnode; struct connected *c; - zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + zvrf = ifp->vrf->info; if (!zvrf) { flog_err( EC_ZEBRA_VRF_NOT_FOUND, - "%s: Received Down for interface but no associated zvrf: %d", - __func__, ifp->vrf_id); + "%s: Received Down for interface but no associated zvrf: %s(%d)", + __func__, ifp->vrf->name, ifp->vrf->vrf_id); return; } @@ -491,12 +491,12 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p) connected_withdraw(ifc); /* Schedule LSP forwarding entries for processing, if appropriate. */ - if (ifp->vrf_id == VRF_DEFAULT) { + if (ifp->vrf->vrf_id == VRF_DEFAULT) { if (IS_ZEBRA_DEBUG_MPLS) zlog_debug( "%u: IF %s IP %pFX address delete, scheduling MPLS processing", - ifp->vrf_id, ifp->name, p); - mpls_mark_lsps_for_processing(vrf_info_lookup(ifp->vrf_id), p); + ifp->vrf->vrf_id, ifp->name, p); + mpls_mark_lsps_for_processing(ifp->vrf->info, p); } } diff --git a/zebra/debug_nl.c b/zebra/debug_nl.c index 842579f89e..0e0ccccb6a 100644 --- a/zebra/debug_nl.c +++ b/zebra/debug_nl.c @@ -29,6 +29,7 @@ #include <stdint.h> #include "zebra/rt_netlink.h" +#include "zebra/kernel_netlink.h" const char *nlmsg_type2str(uint16_t type) { @@ -926,7 +927,7 @@ next_rta: plen = RTA_PAYLOAD(rta); zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len, plen, rta->rta_type, neigh_rta2str(rta->rta_type)); - switch (rta->rta_type) { + switch (rta->rta_type & ~ NLA_F_NESTED) { case NDA_LLADDR: datap = RTA_DATA(rta); dbuf[0] = 0; @@ -1044,7 +1045,7 @@ next_rta: plen = RTA_PAYLOAD(rta); zlog_debug(" rta [len=%d (payload=%zu) type=(%d) %s]", rta->rta_len, plen, rta->rta_type, nhm_rta2str(rta->rta_type)); - switch (rta->rta_type) { + switch (rta->rta_type & ~NLA_F_NESTED) { case NHA_ID: u32v = *(uint32_t *)RTA_DATA(rta); zlog_debug(" %u", u32v); diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 2f39284fb0..3b02128c90 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -363,8 +363,7 @@ DEFUN(fpm_show_counters_json, fpm_show_counters_json_cmd, json_object_int_add(jo, "user-configures", gfnc->counters.user_configures); json_object_int_add(jo, "user-disables", gfnc->counters.user_disables); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); return CMD_SUCCESS; } diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 14d8ac442e..4e4ebc9cda 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -109,7 +109,8 @@ static int interface_list_ioctl(void) unsigned int size; ifreq = (struct ifreq *)((caddr_t)ifconf.ifc_req + n); - ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT); + ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT, + VRF_DEFAULT_NAME); if_add_update(ifp); size = ifreq->ifr_addr.sa_len; if (size < sizeof(ifreq->ifr_addr)) @@ -119,7 +120,8 @@ static int interface_list_ioctl(void) } #else for (n = 0; n < ifconf.ifc_len; n += sizeof(struct ifreq)) { - ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT); + ifp = if_get_by_name(ifreq->ifr_name, VRF_DEFAULT, + VRF_DEFAULT_NAME); if_add_update(ifp); ifreq++; } @@ -150,7 +152,7 @@ static int if_get_hwaddr(struct interface *ifp) ifreq.ifr_addr.sa_family = AF_INET; /* Fetch Hardware address if available. */ - ret = vrf_if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq, ifp->vrf_id); + ret = vrf_if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq, ifp->vrf->vrf_id); if (ret < 0) ifp->hw_addr_len = 0; else { diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 15645d024d..1c6c70ae84 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -423,8 +423,7 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) /* use ioctl to get IP address of an interface */ frr_with_privs(&zserv_privs) { sd = vrf_socket(PF_INET, SOCK_DGRAM, IPPROTO_IP, - interface->vrf_id, - NULL); + interface->vrf->vrf_id, NULL); if (sd < 0) { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("Failure to read interface %s speed: %d %s", @@ -435,7 +434,7 @@ static uint32_t get_iflink_speed(struct interface *interface, int *error) return 0; } /* Get the current link state for the interface */ - rc = vrf_ioctl(interface->vrf_id, sd, SIOCETHTOOL, + rc = vrf_ioctl(interface->vrf->vrf_id, sd, SIOCETHTOOL, (char *)&ifdata); } if (rc < 0) { @@ -972,17 +971,9 @@ static int netlink_interface(struct nlmsghdr *h, ns_id_t ns_id, int startup) link_nsid = ns_id_get_absolute(ns_id, link_nsid); } - /* Add interface. - * We add by index first because in some cases such as the master - * interface, we have the index before we have the name. Fixing - * back references on the slave interfaces is painful if not done - * this way, i.e. by creating by ifindex. - */ - ifp = if_get_by_ifindex(ifi->ifi_index, vrf_id); + ifp = if_get_by_name(name, vrf_id, NULL); set_ifindex(ifp, ifi->ifi_index, zns); /* add it to ns struct */ - if_set_name(ifp, name); - ifp->flags = ifi->ifi_flags & 0x0000fffff; ifp->mtu6 = ifp->mtu = *(uint32_t *)RTA_DATA(tb[IFLA_MTU]); ifp->metric = 0; @@ -1292,11 +1283,22 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) ifp = if_lookup_by_index_per_ns(zns, ifa->ifa_index); if (ifp == NULL) { - flog_err( - EC_LIB_INTERFACE, - "netlink_interface_addr can't find interface by index %d", - ifa->ifa_index); - return -1; + if (startup) { + /* During startup, failure to lookup the referenced + * interface should not be an error, so we have + * downgraded this condition to warning, and we permit + * the startup interface state retrieval to continue. + */ + flog_warn(EC_LIB_INTERFACE, + "%s: can't find interface by index %d", + __func__, ifa->ifa_index); + return 0; + } else { + flog_err(EC_LIB_INTERFACE, + "%s: can't find interface by index %d", + __func__, ifa->ifa_index); + return -1; + } } /* Flags passed through */ @@ -1803,10 +1805,10 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) if (ifp == NULL) { /* unknown interface */ - ifp = if_get_by_name(name, vrf_id); + ifp = if_get_by_name(name, vrf_id, NULL); } else { /* pre-configured interface, learnt now */ - if (ifp->vrf_id != vrf_id) + if (ifp->vrf->vrf_id != vrf_id) if_update_to_new_vrf(ifp, vrf_id); } @@ -1832,6 +1834,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* Update link. */ zebra_if_update_link(ifp, link_ifindex, ns_id); + ifp->ll_type = + netlink_to_zebra_link_type(ifi->ifi_type); netlink_interface_update_hw_addr(tb, ifp); /* Inform clients, install any configured addresses. */ @@ -1858,13 +1862,13 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) netlink_proc_dplane_if_protodown(ifp->info, !!protodown); } - } else if (ifp->vrf_id != vrf_id) { + } else if (ifp->vrf->vrf_id != vrf_id) { /* VRF change for an interface. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "RTM_NEWLINK vrf-change for %s(%u) vrf_id %u -> %u flags 0x%x", - name, ifp->ifindex, ifp->vrf_id, vrf_id, - ifi->ifi_flags); + name, ifp->ifindex, ifp->vrf->vrf_id, + vrf_id, ifi->ifi_flags); if_handle_vrf_change(ifp, vrf_id); } else { @@ -1899,6 +1903,8 @@ int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) /* Update link. */ zebra_if_update_link(ifp, link_ifindex, ns_id); + ifp->ll_type = + netlink_to_zebra_link_type(ifi->ifi_type); netlink_interface_update_hw_addr(tb, ifp); if (if_is_no_ptm_operative(ifp)) { diff --git a/zebra/interface.c b/zebra/interface.c index a68d00d55c..8b5dbabb92 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -584,7 +584,7 @@ void if_add_update(struct interface *ifp) { struct zebra_if *if_data; struct zebra_ns *zns; - struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id); + struct zebra_vrf *zvrf = ifp->vrf->info; /* case interface populate before vrf enabled */ if (zvrf->zns) @@ -611,8 +611,8 @@ void if_add_update(struct interface *ifp) if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug( "interface %s vrf %s(%u) index %d is shutdown. Won't wake it up.", - ifp->name, VRF_LOGNAME(zvrf->vrf), - ifp->vrf_id, ifp->ifindex); + ifp->name, ifp->vrf->name, + ifp->vrf->vrf_id, ifp->ifindex); } return; @@ -623,14 +623,14 @@ void if_add_update(struct interface *ifp) if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( "interface %s vrf %s(%u) index %d becomes active.", - ifp->name, VRF_LOGNAME(zvrf->vrf), ifp->vrf_id, + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, ifp->ifindex); } else { if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("interface %s vrf %s(%u) index %d is added.", - ifp->name, VRF_LOGNAME(zvrf->vrf), - ifp->vrf_id, ifp->ifindex); + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex); } } @@ -769,12 +769,11 @@ void if_delete_update(struct interface *ifp) struct zebra_if *zif; if (if_is_up(ifp)) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - flog_err( EC_LIB_INTERFACE, "interface %s vrf %s(%u) index %d is still up while being deleted.", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex); + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, + ifp->ifindex); return; } @@ -784,13 +783,10 @@ void if_delete_update(struct interface *ifp) /* Mark interface as inactive */ UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE); - if (IS_ZEBRA_DEBUG_KERNEL) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("interface %s vrf %s(%u) index %d is now inactive.", - ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id, ifp->ifindex); - } /* Delete connected routes from the kernel. */ if_delete_connected(ifp); @@ -814,7 +810,7 @@ void if_delete_update(struct interface *ifp) * occur with this implementation whereas it is not possible with * vrf-lite). */ - if (ifp->vrf_id && !vrf_is_backend_netns()) + if (ifp->vrf->vrf_id && !vrf_is_backend_netns()) if_handle_vrf_change(ifp, VRF_DEFAULT); /* Reset some zebra interface params to default values. */ @@ -842,7 +838,7 @@ void if_handle_vrf_change(struct interface *ifp, vrf_id_t vrf_id) { vrf_id_t old_vrf_id; - old_vrf_id = ifp->vrf_id; + old_vrf_id = ifp->vrf->vrf_id; /* Uninstall connected routes. */ if_uninstall_connected(ifp); @@ -884,7 +880,7 @@ void if_nbr_mac_to_ipv4ll_neigh_update(struct interface *ifp, struct in6_addr *address, int add) { - struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id); + struct zebra_vrf *zvrf = ifp->vrf->info; struct zebra_if *zif = ifp->info; char buf[16] = "169.254.0.1"; struct in_addr ipv4_ll; @@ -1022,11 +1018,11 @@ void if_up(struct interface *ifp) { struct zebra_if *zif; struct interface *link_if; - struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id); + struct zebra_vrf *zvrf = ifp->vrf->info; zif = ifp->info; zif->up_count++; - quagga_timestamp(2, zif->up_last, sizeof(zif->up_last)); + frr_timestamp(2, zif->up_last, sizeof(zif->up_last)); /* Notify the protocol daemons. */ if (ifp->ptm_enable && (ifp->ptm_status == ZEBRA_PTM_STATUS_DOWN)) { @@ -1086,11 +1082,11 @@ void if_down(struct interface *ifp) { struct zebra_if *zif; struct interface *link_if; - struct zebra_vrf *zvrf = vrf_info_lookup(ifp->vrf_id); + struct zebra_vrf *zvrf = ifp->vrf->info; zif = ifp->info; zif->down_count++; - quagga_timestamp(2, zif->down_last, sizeof(zif->down_last)); + frr_timestamp(2, zif->down_last, sizeof(zif->down_last)); if_down_nhg_dependents(ifp); @@ -1175,7 +1171,7 @@ void zebra_if_update_all_links(struct zebra_ns *zns) zlog_debug("bond mbr %s map to bond %d", zif->ifp->name, zif->bondslave_info.bond_ifindex); - zebra_l2_map_slave_to_bond(zif, ifp->vrf_id); + zebra_l2_map_slave_to_bond(zif, ifp->vrf->vrf_id); } /* update SVI linkages */ @@ -1314,7 +1310,6 @@ static void connected_dump_vty(struct vty *vty, json_object *json, { struct prefix *p; json_object *json_addr = NULL; - char buf[PREFIX2STR_BUFFER]; /* Print interface address. */ p = connected->address; @@ -1322,8 +1317,7 @@ static void connected_dump_vty(struct vty *vty, json_object *json, if (json) { json_addr = json_object_new_object(); json_object_array_add(json, json_addr); - json_object_string_add(json_addr, "address", - prefix2str(p, buf, sizeof(buf))); + json_object_string_addf(json_addr, "address", "%pFX", p); } else { vty_out(vty, " %s %pFX", prefix_family_str(p), p); } @@ -1331,10 +1325,8 @@ static void connected_dump_vty(struct vty *vty, json_object *json, /* If there is destination address, print it. */ if (CONNECTED_PEER(connected) && connected->destination) { if (json) { - json_object_string_add( - json_addr, "peer", - prefix2str(connected->destination, buf, - sizeof(buf))); + json_object_string_addf(json_addr, "peer", "%pFX", + connected->destination); } else { vty_out(vty, " peer %pFX", connected->destination); } @@ -1616,7 +1608,6 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) struct listnode *node; struct route_node *rn; struct zebra_if *zebra_if; - struct vrf *vrf; char pd_buf[ZEBRA_PROTODOWN_RC_STR_LEN]; zebra_if = ifp->info; @@ -1644,8 +1635,7 @@ static void if_dump_vty(struct vty *vty, struct interface *ifp) zebra_ptm_show_status(vty, NULL, ifp); - vrf = vrf_lookup_by_id(ifp->vrf_id); - vty_out(vty, " vrf: %s\n", vrf->name); + vty_out(vty, " vrf: %s\n", ifp->vrf->name); if (ifp->desc) vty_out(vty, " Description: %s\n", ifp->desc); @@ -1941,7 +1931,6 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, struct listnode *node; struct route_node *rn; struct zebra_if *zebra_if; - struct vrf *vrf; char pd_buf[ZEBRA_PROTODOWN_RC_STR_LEN]; char buf[BUFSIZ]; json_object *json_if; @@ -1979,8 +1968,7 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, zebra_ptm_show_status(vty, json, ifp); - vrf = vrf_lookup_by_id(ifp->vrf_id); - json_object_string_add(json_if, "vrfName", vrf->name); + json_object_string_add(json_if, "vrfName", ifp->vrf->name); if (ifp->desc) json_object_string_add(json_if, "description", ifp->desc); @@ -2066,18 +2054,14 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, vxlan_info = &zebra_if->l2info.vxl; json_object_int_add(json_if, "vxlanId", vxlan_info->vni); if (vxlan_info->vtep_ip.s_addr != INADDR_ANY) - json_object_string_add(json_if, "vtepIp", - inet_ntop(AF_INET, - &vxlan_info->vtep_ip, - buf, sizeof(buf))); + json_object_string_addf(json_if, "vtepIp", "%pI4", + &vxlan_info->vtep_ip); if (vxlan_info->access_vlan) json_object_int_add(json_if, "accessVlanId", vxlan_info->access_vlan); if (vxlan_info->mcast_grp.s_addr != INADDR_ANY) - json_object_string_add(json_if, "mcastGroup", - inet_ntop(AF_INET, - &vxlan_info->mcast_grp, - buf, sizeof(buf))); + json_object_string_addf(json_if, "mcastGroup", "%pI4", + &vxlan_info->mcast_grp); if (vxlan_info->ifindex_link && (vxlan_info->link_nsid != NS_UNKNOWN)) { struct interface *ifp; @@ -2094,16 +2078,12 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, gre_info = &zebra_if->l2info.gre; if (gre_info->vtep_ip.s_addr != INADDR_ANY) { - json_object_string_add(json_if, "vtepIp", - inet_ntop(AF_INET, - &gre_info->vtep_ip, - buf, sizeof(buf))); + json_object_string_addf(json_if, "vtepIp", "%pI4", + &gre_info->vtep_ip); if (gre_info->vtep_ip_remote.s_addr != INADDR_ANY) - json_object_string_add( - json_if, "vtepRemoteIp", - inet_ntop(AF_INET, - &gre_info->vtep_ip_remote, - buf, sizeof(buf))); + json_object_string_addf( + json_if, "vtepRemoteIp", "%pI4", + &gre_info->vtep_ip_remote); } if (gre_info->ifindex_link && (gre_info->link_nsid != NS_UNKNOWN)) { @@ -2237,9 +2217,8 @@ static void if_dump_vty_json(struct vty *vty, struct interface *ifp, json_object_double_add(json_te, "utilizedBandwidth", iflp->use_bw); if (IS_PARAM_SET(iflp, LP_RMT_AS)) - json_object_string_add(json_te, "neighborAsbrIp", - inet_ntop(AF_INET, &iflp->rmt_ip, - buf, sizeof(buf))); + json_object_string_addf(json_te, "neighborAsbrIp", + "%pI4", &iflp->rmt_ip); json_object_int_add(json_te, "neighborAsbrAs", iflp->rmt_as); } @@ -2365,12 +2344,8 @@ DEFPY(show_interface, show_interface_cmd, } } - if (json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (json) + vty_json(vty, json); return CMD_SUCCESS; } @@ -2412,12 +2387,8 @@ DEFPY (show_interface_vrf_all, } } - if (json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (json) + vty_json(vty, json); return CMD_SUCCESS; } @@ -2465,12 +2436,8 @@ DEFPY (show_interface_name_vrf, else if_dump_vty(vty, ifp); - if (json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (json) + vty_json(vty, json); return CMD_SUCCESS; } @@ -2485,12 +2452,24 @@ DEFPY (show_interface_name_vrf_all, VRF_ALL_CMD_HELP_STR JSON_STR) { - struct interface *ifp; + struct interface *ifp = NULL; + struct interface *ifptmp; + struct vrf *vrf; json_object *json = NULL; + int count = 0; interface_update_stats(); - ifp = if_lookup_by_name_all_vrf(ifname); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + ifptmp = if_lookup_by_name_vrf(ifname, vrf); + if (ifptmp) { + ifp = ifptmp; + count++; + if (!vrf_is_backend_netns()) + break; + } + } + if (ifp == NULL) { if (uj) vty_out(vty, "{}\n"); @@ -2498,6 +2477,17 @@ DEFPY (show_interface_name_vrf_all, vty_out(vty, "%% Can't find interface %s\n", ifname); return CMD_WARNING; } + if (count > 1) { + if (uj) { + vty_out(vty, "{}\n"); + } else { + vty_out(vty, + "%% There are multiple interfaces with name %s\n", + ifname); + vty_out(vty, "%% You must specify the VRF name\n"); + } + return CMD_WARNING; + } if (uj) json = json_object_new_object(); @@ -2507,12 +2497,8 @@ DEFPY (show_interface_name_vrf_all, else if_dump_vty(vty, ifp); - if (json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (json) + vty_json(vty, json); return CMD_SUCCESS; } @@ -2886,6 +2872,7 @@ struct cmd_node link_params_node = { .node = LINK_PARAMS_NODE, .parent_node = INTERFACE_NODE, .prompt = "%s(config-link-params)# ", + .no_xpath = true, }; static void link_param_cmd_set_uint32(struct interface *ifp, uint32_t *field, @@ -4206,23 +4193,21 @@ static int link_params_config_write(struct vty *vty, struct interface *ifp) static int if_config_write(struct vty *vty) { - struct vrf *vrf0; + struct vrf *vrf; struct interface *ifp; zebra_ptm_write(vty); - RB_FOREACH (vrf0, vrf_name_head, &vrfs_by_name) - FOR_ALL_INTERFACES (vrf0, ifp) { + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) + FOR_ALL_INTERFACES (vrf, ifp) { struct zebra_if *if_data; struct listnode *addrnode; struct connected *ifc; struct prefix *p; - struct vrf *vrf; if_data = ifp->info; - vrf = vrf_lookup_by_id(ifp->vrf_id); - if (ifp->vrf_id == VRF_DEFAULT) + if (ifp->vrf->vrf_id == VRF_DEFAULT) vty_frame(vty, "interface %s\n", ifp->name); else vty_frame(vty, "interface %s vrf %s\n", diff --git a/zebra/interface.h b/zebra/interface.h index 23e22bdda8..771398b547 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -340,9 +340,9 @@ struct zebra_if { /* Information about up/down changes */ unsigned int up_count; - char up_last[QUAGGA_TIMESTAMP_LEN]; + char up_last[FRR_TIMESTAMP_LEN]; unsigned int down_count; - char down_last[QUAGGA_TIMESTAMP_LEN]; + char down_last[FRR_TIMESTAMP_LEN]; #if defined(HAVE_RTADV) struct rtadvconf rtadv; diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 42a5bfd9db..8b30eea9f1 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -140,7 +140,7 @@ void if_get_metric(struct interface *ifp) ifreq_set_name(&ifreq, ifp); - if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq, ifp->vrf_id) < 0) + if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0) return; ifp->metric = ifreq.ifr_metric; if (ifp->metric == 0) @@ -158,7 +158,7 @@ void if_get_mtu(struct interface *ifp) ifreq_set_name(&ifreq, ifp); #if defined(SIOCGIFMTU) - if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq, ifp->vrf_id) < 0) { + if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq, ifp->vrf->vrf_id) < 0) { zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)"); ifp->mtu6 = ifp->mtu = -1; return; @@ -414,7 +414,7 @@ void if_get_flags(struct interface *ifp) ifreq_set_name(&ifreq, ifp); - ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); + ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id); if (ret < 0) { flog_err_sys(EC_LIB_SYSTEM_CALL, "vrf_if_ioctl(SIOCGIFFLAGS %s) failed: %s", @@ -443,13 +443,13 @@ void if_get_flags(struct interface *ifp) struct if_data *ifdata = &ifdr.ifdr_data; strlcpy(ifdr.ifdr_name, ifp->name, sizeof(ifdr.ifdr_name)); - ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifdr, ifp->vrf_id); + ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifdr, ifp->vrf->vrf_id); #else struct if_data ifd = {.ifi_link_state = 0}; struct if_data *ifdata = &ifd; ifreq.ifr_data = (caddr_t)ifdata; - ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreq, ifp->vrf_id); + ret = vrf_if_ioctl(SIOCGIFDATA, (caddr_t)&ifreq, ifp->vrf->vrf_id); #endif if (ret == -1) @@ -511,7 +511,7 @@ int if_set_flags(struct interface *ifp, uint64_t flags) ifreq.ifr_flags = ifp->flags; ifreq.ifr_flags |= flags; - ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); + ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id); if (ret < 0) { zlog_info("can't set interface flags"); @@ -532,7 +532,7 @@ int if_unset_flags(struct interface *ifp, uint64_t flags) ifreq.ifr_flags = ifp->flags; ifreq.ifr_flags &= ~flags; - ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); + ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf->vrf_id); if (ret < 0) { zlog_info("can't unset interface flags"); diff --git a/zebra/kernel_netlink.h b/zebra/kernel_netlink.h index 37c76b9e59..cf8b8c785e 100644 --- a/zebra/kernel_netlink.h +++ b/zebra/kernel_netlink.h @@ -27,6 +27,10 @@ extern "C" { #ifdef HAVE_NETLINK +#define RTM_NHA(h) \ + ((struct rtattr *)(((char *)(h)) + NLMSG_ALIGN(sizeof(struct nhmsg)))) + + #define NL_RCV_PKT_BUF_SIZE 32768 #define NL_PKT_BUF_SIZE 8192 diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index d9c69ceb6d..5ff66f7c63 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -61,7 +61,7 @@ extern struct zebra_privs_t zserv_privs; * Alignment of zero-sized sockaddrs is nonsensical, but historically * BSD defines RT_ROUNDUP(0) to be the alignment interval (rather than * 0). We follow this practice without questioning it, but it is a - * bug if quagga calls ROUNDUP with 0. + * bug if frr calls ROUNDUP with 0. */ #ifdef __APPLE__ #define ROUNDUP_TYPE int @@ -443,7 +443,8 @@ static int ifan_read(struct if_announcemsghdr *ifan) __func__, ifan->ifan_index, ifan->ifan_name); /* Create Interface */ - ifp = if_get_by_name(ifan->ifan_name, VRF_DEFAULT); + ifp = if_get_by_name(ifan->ifan_name, VRF_DEFAULT, + VRF_DEFAULT_NAME); if_set_index(ifp, ifan->ifan_index); if_get_metric(ifp); @@ -624,7 +625,8 @@ int ifm_read(struct if_msghdr *ifm) if (ifp == NULL) { /* Interface that zebra was not previously aware of, so * create. */ - ifp = if_create_name(ifname, VRF_DEFAULT); + ifp = if_get_by_name(ifname, VRF_DEFAULT, + VRF_DEFAULT_NAME); if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: creating ifp for ifindex %d", __func__, ifm->ifm_index); diff --git a/zebra/main.c b/zebra/main.c index 6162d36b43..2a8dc39771 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -71,7 +71,7 @@ struct thread_master *master; /* Route retain mode flag. */ int retain_mode = 0; -/* Allow non-quagga entities to delete quagga routes */ +/* Allow non-frr entities to delete frr routes */ int allow_delete = 0; int graceful_restart; @@ -182,6 +182,7 @@ static void sigint(void) SET_FLAG(zvrf->flags, ZEBRA_VRF_RETAIN); } } + if (zrouter.lsp_process_q) work_queue_free_and_null(&zrouter.lsp_process_q); @@ -235,7 +236,7 @@ static void sigusr1(void) zlog_rotate(); } -struct quagga_signal_t zebra_signals[] = { +struct frr_signal_t zebra_signals[] = { { .signal = SIGHUP, .handler = &sighup, @@ -442,8 +443,8 @@ int main(int argc, char **argv) * we have to have route_read() called before. */ zrouter.startup_time = monotime(NULL); - thread_add_timer(zrouter.master, rib_sweep_route, - NULL, graceful_restart, NULL); + thread_add_timer(zrouter.master, rib_sweep_route, NULL, + graceful_restart, &zrouter.sweeper); /* Needed for BSD routing socket. */ pid = getpid(); diff --git a/zebra/redistribute.c b/zebra/redistribute.c index 26f6d404e9..c59ff1bbec 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -449,8 +449,8 @@ void zebra_interface_up_update(struct interface *ifp) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("MESSAGE: ZEBRA_INTERFACE_UP %s(%u)", - ifp->name, ifp->vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_UP %s vrf %s(%u)", + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); if (ifp->ptm_status || !ifp->ptm_enable) { for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, @@ -475,8 +475,8 @@ void zebra_interface_down_update(struct interface *ifp) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("MESSAGE: ZEBRA_INTERFACE_DOWN %s(%u)", - ifp->name, ifp->vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_DOWN %s vrf %s(%u)", + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -494,8 +494,8 @@ void zebra_interface_add_update(struct interface *ifp) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADD %s(%u)", ifp->name, - ifp->vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_ADD %s vrf %s(%u)", + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -514,8 +514,8 @@ void zebra_interface_delete_update(struct interface *ifp) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("MESSAGE: ZEBRA_INTERFACE_DELETE %s(%u)", - ifp->name, ifp->vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_DELETE %s vrf %s(%u)", + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -538,8 +538,8 @@ void zebra_interface_address_add_update(struct interface *ifp, if (IS_ZEBRA_DEBUG_EVENT) { p = ifc->address; zlog_debug( - "MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %pFX on %s(%u)", - p, ifp->name, ifp->vrf_id); + "MESSAGE: ZEBRA_INTERFACE_ADDRESS_ADD %pFX on %s vrf %s(%u)", + p, ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); } if (!CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL)) @@ -575,8 +575,8 @@ void zebra_interface_address_delete_update(struct interface *ifp, if (IS_ZEBRA_DEBUG_EVENT) { p = ifc->address; zlog_debug( - "MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %pFX on %s(%u)", - p, ifp->name, ifp->vrf_id); + "MESSAGE: ZEBRA_INTERFACE_ADDRESS_DELETE %pFX on %s vrf %s(%u)", + p, ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); } zebra_vxlan_add_del_gw_macip(ifp, ifc->address, 0); @@ -607,7 +607,7 @@ void zebra_interface_vrf_update_del(struct interface *ifp, vrf_id_t new_vrf_id) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug( "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/DEL %s VRF Id %u -> %u", - ifp->name, ifp->vrf_id, new_vrf_id); + ifp->name, ifp->vrf->vrf_id, new_vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -634,7 +634,7 @@ void zebra_interface_vrf_update_add(struct interface *ifp, vrf_id_t old_vrf_id) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug( "MESSAGE: ZEBRA_INTERFACE_VRF_UPDATE/ADD %s VRF Id %u -> %u", - ifp->name, old_vrf_id, ifp->vrf_id); + ifp->name, old_vrf_id, ifp->vrf->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ @@ -925,8 +925,8 @@ void zebra_interface_parameters_update(struct interface *ifp) struct zserv *client; if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s(%u)", - ifp->name, ifp->vrf_id); + zlog_debug("MESSAGE: ZEBRA_INTERFACE_LINK_PARAMS %s vrf %s(%u)", + ifp->name, ifp->vrf->name, ifp->vrf->vrf_id); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { /* Do not send unsolicited messages to synchronous clients. */ diff --git a/zebra/rib.h b/zebra/rib.h index 8887053a4c..fa8193bedf 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -46,24 +46,22 @@ DECLARE_MGROUP(ZEBRA); DECLARE_MTYPE(RE); -enum rnh_type { RNH_NEXTHOP_TYPE, RNH_IMPORT_CHECK_TYPE }; - PREDECL_LIST(rnh_list); /* Nexthop structure. */ struct rnh { uint8_t flags; -#define ZEBRA_NHT_CONNECTED 0x1 -#define ZEBRA_NHT_DELETED 0x2 -#define ZEBRA_NHT_EXACT_MATCH 0x4 +#define ZEBRA_NHT_CONNECTED 0x1 +#define ZEBRA_NHT_DELETED 0x2 +#define ZEBRA_NHT_EXACT_MATCH 0x4 +#define ZEBRA_NHT_RESOLVE_VIA_DEFAULT 0x8 /* VRF identifier. */ vrf_id_t vrf_id; afi_t afi; - - enum rnh_type type; + safi_t safi; uint32_t seqno; @@ -110,8 +108,11 @@ struct route_entry { struct nexthop_group fib_ng; struct nexthop_group fib_backup_ng; - /* Nexthop group hash entry ID */ + /* Nexthop group hash entry IDs. The "installed" id is the id + * used in linux/netlink, if available. + */ uint32_t nhe_id; + uint32_t nhe_installed_id; /* Tag */ route_tag_t tag; diff --git a/zebra/router-id.c b/zebra/router-id.c index ac81d537d0..ea438b4367 100644 --- a/zebra/router-id.c +++ b/zebra/router-id.c @@ -159,7 +159,7 @@ void router_id_add_address(struct connected *ifc) struct prefix before; struct prefix after; struct zserv *client; - struct zebra_vrf *zvrf = vrf_info_get(ifc->ifp->vrf_id); + struct zebra_vrf *zvrf = ifc->ifp->vrf->info; afi_t afi; struct list *rid_lo; struct list *rid_all; @@ -206,7 +206,7 @@ void router_id_del_address(struct connected *ifc) struct prefix before; struct listnode *node; struct zserv *client; - struct zebra_vrf *zvrf = vrf_info_get(ifc->ifp->vrf_id); + struct zebra_vrf *zvrf = ifc->ifp->vrf->info; afi_t afi; struct list *rid_lo; struct list *rid_all; @@ -521,7 +521,7 @@ DEFUN (show_ip_router_id, vrf_name = argv[idx]->arg; } - zvrf = vrf_info_get(vrf_id); + zvrf = vrf_info_lookup(vrf_id); if (zvrf != NULL) { if (is_ipv6) { diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 488bca06da..24c01b7f51 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -507,7 +507,7 @@ parse_nexthop_unicast(ns_id_t ns_id, struct rtmsg *rtm, struct rtattr **tb, if (index) { ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), index); if (ifp) - nh_vrf_id = ifp->vrf_id; + nh_vrf_id = ifp->vrf->vrf_id; } nh.vrf_id = nh_vrf_id; @@ -581,7 +581,7 @@ static uint8_t parse_multipath_nexthops_unicast(ns_id_t ns_id, ifp = if_lookup_by_index_per_ns(zebra_ns_lookup(ns_id), index); if (ifp) - nh_vrf_id = ifp->vrf_id; + nh_vrf_id = ifp->vrf->vrf_id; else { flog_warn( EC_ZEBRA_UNKNOWN_INTERFACE, @@ -2799,7 +2799,7 @@ static struct nexthop netlink_nexthop_process_nh(struct rtattr **tb, if (ifp) *ifp = ifp_lookup; if (ifp_lookup) - nh.vrf_id = ifp_lookup->vrf_id; + nh.vrf_id = ifp_lookup->vrf->vrf_id; else { flog_warn( EC_ZEBRA_UNKNOWN_INTERFACE, @@ -2892,7 +2892,8 @@ int netlink_nexthop_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) return -1; } - netlink_parse_rtattr(tb, NHA_MAX, RTM_NHA(nhm), len); + netlink_parse_rtattr_flags(tb, NHA_MAX, RTM_NHA(nhm), len, + NLA_F_NESTED); if (!tb[NHA_ID]) { @@ -3502,8 +3503,8 @@ static int netlink_request_specific_mac_in_bridge(struct zebra_ns *zns, zlog_debug( "%s: Tx family %s IF %s(%u) vrf %s(%u) MAC %pEA vid %u", __func__, nl_family_to_str(req.ndm.ndm_family), - br_if->name, br_if->ifindex, - vrf_id_to_name(br_if->vrf_id), br_if->vrf_id, mac, vid); + br_if->name, br_if->ifindex, br_if->vrf->name, + br_if->vrf->vrf_id, mac, vid); return netlink_request(&zns->netlink_cmd, &req); } @@ -3675,7 +3676,6 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) struct interface *link_if; struct ethaddr mac; struct ipaddr ip; - struct vrf *vrf; char buf[ETHER_ADDR_STRLEN]; int mac_present = 0; bool is_ext; @@ -3694,7 +3694,6 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (!ifp || !ifp->info) return 0; - vrf = vrf_lookup_by_id(ifp->vrf_id); zif = (struct zebra_if *)ifp->info; /* Parse attributes and extract fields of interest. */ @@ -3704,7 +3703,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) zlog_debug("%s family %s IF %s(%u) vrf %s(%u) - no DST", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id); + ndm->ndm_ifindex, ifp->vrf->name, ifp->vrf->vrf_id); return 0; } @@ -3744,7 +3743,6 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (tb[NDA_LLADDR]) { /* copy LLADDR information */ l2_len = RTA_PAYLOAD(tb[NDA_LLADDR]); - memcpy(&mac, RTA_DATA(tb[NDA_LLADDR]), l2_len); } if (l2_len == IPV4_MAX_BYTELEN || l2_len == 0) { union sockunion link_layer_ipv4; @@ -3752,7 +3750,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) if (l2_len) { sockunion_family(&link_layer_ipv4) = AF_INET; memcpy((void *)sockunion_get_addr(&link_layer_ipv4), - &mac, l2_len); + RTA_DATA(tb[NDA_LLADDR]), l2_len); } else sockunion_family(&link_layer_ipv4) = AF_UNSPEC; zsend_nhrp_neighbor_notify( @@ -3801,7 +3799,8 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) nl_family_to_str( ndm->ndm_family), ifp->name, ndm->ndm_ifindex, - VRF_LOGNAME(vrf), ifp->vrf_id, + ifp->vrf->name, + ifp->vrf->vrf_id, (unsigned long)RTA_PAYLOAD( tb[NDA_LLADDR])); return 0; @@ -3825,8 +3824,8 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) "Rx %s family %s IF %s(%u) vrf %s(%u) IP %pIA MAC %s state 0x%x flags 0x%x ext_flags 0x%x", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id, - &ip, + ndm->ndm_ifindex, ifp->vrf->name, + ifp->vrf->vrf_id, &ip, mac_present ? prefix_mac2str(&mac, buf, sizeof(buf)) : "", @@ -3861,7 +3860,7 @@ static int netlink_ipneigh_change(struct nlmsghdr *h, int len, ns_id_t ns_id) zlog_debug("Rx %s family %s IF %s(%u) vrf %s(%u) IP %pIA", nl_msg_type_to_str(h->nlmsg_type), nl_family_to_str(ndm->ndm_family), ifp->name, - ndm->ndm_ifindex, VRF_LOGNAME(vrf), ifp->vrf_id, + ndm->ndm_ifindex, ifp->vrf->name, ifp->vrf->vrf_id, &ip); /* Process the delete - it may result in re-adding the neighbor if it is @@ -4004,7 +4003,7 @@ int netlink_neigh_read_specific_ip(const struct ipaddr *ip, { int ret = 0; struct zebra_ns *zns; - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(vlan_if->vrf_id); + struct zebra_vrf *zvrf = vlan_if->vrf->info; struct zebra_dplane_info dp_info; zns = zvrf->zns; @@ -4014,7 +4013,7 @@ int netlink_neigh_read_specific_ip(const struct ipaddr *ip, if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug("%s: neigh request IF %s(%u) IP %pIA vrf %s(%u)", __func__, vlan_if->name, vlan_if->ifindex, ip, - vrf_id_to_name(vlan_if->vrf_id), vlan_if->vrf_id); + vlan_if->vrf->name, vlan_if->vrf->vrf_id); ret = netlink_request_specific_neigh_in_vlan(zns, RTM_GETNEIGH, ip, vlan_if->ifindex); diff --git a/zebra/rtadv.c b/zebra/rtadv.c index 9610f71d09..350b97cc5d 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -99,7 +99,7 @@ static struct zebra_vrf *rtadv_interface_get_zvrf(const struct interface *ifp) if (!vrf_is_backend_netns()) return vrf_info_lookup(VRF_DEFAULT); - return vrf_info_lookup(ifp->vrf_id); + return ifp->vrf->info; } static int rtadv_increment_received(struct zebra_vrf *zvrf, ifindex_t *ifindex) @@ -210,12 +210,9 @@ static void rtadv_send_packet(int sock, struct interface *ifp, } /* Logging of packet. */ - if (IS_ZEBRA_DEBUG_PACKET) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s(%s:%u): Tx RA, socket %u", ifp->name, - VRF_LOGNAME(vrf), ifp->ifindex, sock); - } + ifp->vrf->name, ifp->ifindex, sock); /* Fill in sockaddr_in6. */ memset(&addr, 0, sizeof(struct sockaddr_in6)); @@ -387,11 +384,9 @@ static void rtadv_send_packet(int sock, struct interface *ifp, sizeof(struct nd_opt_rdnss) + sizeof(struct in6_addr); if (len + opt_len > max_len) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - zlog_warn( "%s(%s:%u): Tx RA: RDNSS option would exceed MTU, omitting it", - ifp->name, VRF_LOGNAME(vrf), ifp->ifindex); + ifp->name, ifp->vrf->name, ifp->ifindex); goto no_more_opts; } struct nd_opt_rdnss *opt = (struct nd_opt_rdnss *)(buf + len); @@ -493,8 +488,9 @@ static int rtadv_timer(struct thread *thread) RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) FOR_ALL_INTERFACES (vrf, ifp) { - if (if_is_loopback_or_vrf(ifp) - || !if_is_operative(ifp)) + if (if_is_loopback(ifp) || !if_is_operative(ifp) + || (vrf_is_backend_netns() + && ifp->vrf->vrf_id != zvrf->vrf->vrf_id)) continue; zif = ifp->info; @@ -509,17 +505,12 @@ static int rtadv_timer(struct thread *thread) <= 0) zif->rtadv.inFastRexmit = 0; - if (IS_ZEBRA_DEBUG_SEND) { - struct vrf *vrf = - vrf_lookup_by_id( - ifp->vrf_id); - + if (IS_ZEBRA_DEBUG_SEND) zlog_debug( "Fast RA Rexmit on interface %s(%s:%u)", ifp->name, - VRF_LOGNAME(vrf), + ifp->vrf->name, ifp->ifindex); - } rtadv_send_packet(zvrf->rtadv.sock, ifp, RA_ENABLE); @@ -619,14 +610,11 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len, inet_ntop(AF_INET6, &addr->sin6_addr, addr_str, INET6_ADDRSTRLEN); if (len < sizeof(struct nd_router_advert)) { - if (IS_ZEBRA_DEBUG_PACKET) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_ZEBRA_DEBUG_PACKET) zlog_debug( "%s(%s:%u): Rx RA with invalid length %d from %s", - ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, len, + ifp->name, ifp->vrf->name, ifp->ifindex, len, addr_str); - } return; } @@ -634,14 +622,11 @@ static void rtadv_process_advert(uint8_t *msg, unsigned int len, rtadv_process_optional(msg + sizeof(struct nd_router_advert), len - sizeof(struct nd_router_advert), ifp, addr); - if (IS_ZEBRA_DEBUG_PACKET) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_ZEBRA_DEBUG_PACKET) zlog_debug( "%s(%s:%u): Rx RA with non-linklocal source address from %s", - ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, + ifp->name, ifp->vrf->name, ifp->ifindex, addr_str); - } return; } @@ -719,14 +704,11 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len, return; } - if (IS_ZEBRA_DEBUG_PACKET) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s(%s:%u): Rx RA/RS len %d from %s", ifp->name, - VRF_LOGNAME(vrf), ifp->ifindex, len, addr_str); - } + ifp->vrf->name, ifp->ifindex, len, addr_str); - if (if_is_loopback_or_vrf(ifp)) + if (if_is_loopback(ifp)) return; /* Check interface configuration. */ @@ -736,11 +718,9 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len, /* ICMP message length check. */ if (len < sizeof(struct icmp6_hdr)) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - zlog_debug( "%s(%s:%u): Rx RA with Invalid ICMPV6 packet length %d", - ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, len); + ifp->name, ifp->vrf->name, ifp->ifindex, len); return; } @@ -749,20 +729,16 @@ static void rtadv_process_packet(uint8_t *buf, unsigned int len, /* ICMP message type check. */ if (icmph->icmp6_type != ND_ROUTER_SOLICIT && icmph->icmp6_type != ND_ROUTER_ADVERT) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - zlog_debug("%s(%s:%u): Rx RA - Unwanted ICMPV6 message type %d", - ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, + ifp->name, ifp->vrf->name, ifp->ifindex, icmph->icmp6_type); return; } /* Hoplimit check. */ if (hoplimit >= 0 && hoplimit != 255) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - zlog_debug("%s(%s:%u): Rx RA - Invalid hoplimit %d", ifp->name, - VRF_LOGNAME(vrf), ifp->ifindex, hoplimit); + ifp->vrf->name, ifp->ifindex, hoplimit); return; } @@ -1295,14 +1271,12 @@ static void zebra_interface_radv_set(ZAPI_HANDLER_ARGS, int enable) zebra_route_string(client->proto)); return; } - if (vrf_is_backend_netns() && ifp->vrf_id != zvrf_id(zvrf)) { - struct vrf *vrf = zvrf->vrf; - + if (vrf_is_backend_netns() && ifp->vrf->vrf_id != zvrf_id(zvrf)) { zlog_debug( "%s:%u: IF %u RA %s client %s - VRF mismatch, IF VRF %u", - VRF_LOGNAME(vrf), zvrf_id(zvrf), ifindex, + ifp->vrf->name, zvrf_id(zvrf), ifindex, enable ? "enable" : "disable", - zebra_route_string(client->proto), ifp->vrf_id); + zebra_route_string(client->proto), ifp->vrf->vrf_id); return; } @@ -1462,7 +1436,7 @@ DEFUN (ipv6_nd_ra_fast_retrans, VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; - if (if_is_loopback_or_vrf(ifp)) { + if (if_is_loopback(ifp)) { vty_out(vty, "Cannot configure IPv6 Router Advertisements on this interface\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1484,7 +1458,7 @@ DEFUN (no_ipv6_nd_ra_fast_retrans, VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; - if (if_is_loopback_or_vrf(ifp)) { + if (if_is_loopback(ifp)) { vty_out(vty, "Cannot configure IPv6 Router Advertisements on this interface\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1506,7 +1480,7 @@ DEFPY (ipv6_nd_ra_hop_limit, VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; - if (if_is_loopback_or_vrf(ifp)) { + if (if_is_loopback(ifp)) { vty_out(vty, "Cannot configure IPv6 Router Advertisements on this interface\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1529,7 +1503,7 @@ DEFPY (no_ipv6_nd_ra_hop_limit, VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; - if (if_is_loopback_or_vrf(ifp)) { + if (if_is_loopback(ifp)) { vty_out(vty, "Cannot configure IPv6 Router Advertisements on this interface\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1551,7 +1525,7 @@ DEFPY (ipv6_nd_ra_retrans_interval, VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; - if (if_is_loopback_or_vrf(ifp)) { + if (if_is_loopback(ifp)) { vty_out(vty, "Cannot configure IPv6 Router Advertisements on loopback interface\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1574,7 +1548,7 @@ DEFPY (no_ipv6_nd_ra_retrans_interval, VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; - if (if_is_loopback_or_vrf(ifp)) { + if (if_is_loopback(ifp)) { vty_out(vty, "Cannot remove IPv6 Router Advertisements on loopback interface\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1595,7 +1569,7 @@ DEFUN (ipv6_nd_suppress_ra, VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; - if (if_is_loopback_or_vrf(ifp)) { + if (if_is_loopback(ifp)) { vty_out(vty, "Cannot configure IPv6 Router Advertisements on this interface\n"); return CMD_WARNING_CONFIG_FAILED; @@ -1619,7 +1593,7 @@ DEFUN (no_ipv6_nd_suppress_ra, VTY_DECLVAR_CONTEXT(interface, ifp); struct zebra_if *zif = ifp->info; - if (if_is_loopback_or_vrf(ifp)) { + if (if_is_loopback(ifp)) { vty_out(vty, "Cannot configure IPv6 Router Advertisements on this interface\n"); return CMD_WARNING_CONFIG_FAILED; @@ -2608,7 +2582,7 @@ static int rtadv_config_write(struct vty *vty, struct interface *ifp) zif = ifp->info; - if (!if_is_loopback_or_vrf(ifp)) { + if (!if_is_loopback(ifp)) { if (zif->rtadv.AdvSendAdvertisements && CHECK_FLAG(zif->rtadv.ra_configured, VTY_RA_CONFIGURED)) vty_out(vty, " no ipv6 nd suppress-ra\n"); @@ -2856,13 +2830,10 @@ static int if_join_all_router(int sock, struct interface *ifp) ifp->name, ifp->ifindex, sock, safe_strerror(errno)); - if (IS_ZEBRA_DEBUG_EVENT) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (IS_ZEBRA_DEBUG_EVENT) zlog_debug( "%s(%s:%u): Join All-Routers multicast group, socket %u", - ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock); - } + ifp->name, ifp->vrf->name, ifp->ifindex, sock); return 0; } @@ -2879,22 +2850,18 @@ static int if_leave_all_router(int sock, struct interface *ifp) ret = setsockopt(sock, IPPROTO_IPV6, IPV6_LEAVE_GROUP, (char *)&mreq, sizeof(mreq)); - if (ret < 0) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); - + if (ret < 0) flog_err_sys( EC_LIB_SOCKET, "%s(%s:%u): Failed to leave group, socket %u error %s", - ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock, + ifp->name, ifp->vrf->name, ifp->ifindex, sock, safe_strerror(errno)); - } - if (IS_ZEBRA_DEBUG_EVENT) { - struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + if (IS_ZEBRA_DEBUG_EVENT) zlog_debug( "%s(%s:%u): Leave All-Routers multicast group, socket %u", - ifp->name, VRF_LOGNAME(vrf), ifp->ifindex, sock); - } + ifp->name, ifp->vrf->name, ifp->ifindex, sock); + return 0; } diff --git a/zebra/subdir.am b/zebra/subdir.am index c3d8a73aaa..f0cc6ce71b 100644 --- a/zebra/subdir.am +++ b/zebra/subdir.am @@ -116,6 +116,7 @@ zebra_zebra_SOURCES = \ zebra/zebra_routemap.c \ zebra/zebra_routemap_nb.c \ zebra/zebra_routemap_nb_config.c \ + zebra/zebra_script.c \ zebra/zebra_srte.c \ zebra/zebra_vrf.c \ zebra/zebra_vty.c \ @@ -185,6 +186,7 @@ noinst_HEADERS += \ zebra/zebra_routemap.h \ zebra/zebra_routemap_nb.h \ zebra/zebra_router.h \ + zebra/zebra_script.h \ zebra/zebra_srte.h \ zebra/zebra_vrf.h \ zebra/zebra_vxlan.h \ diff --git a/zebra/table_manager.c b/zebra/table_manager.c index 9f3b44f944..ffc7a48eb9 100644 --- a/zebra/table_manager.c +++ b/zebra/table_manager.c @@ -72,7 +72,8 @@ void table_manager_enable(struct zebra_vrf *zvrf) if (zvrf->tbl_mgr) return; - if (!vrf_is_backend_netns() && zvrf_id(zvrf) != VRF_DEFAULT) { + if (!vrf_is_backend_netns() + && strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { struct zebra_vrf *def = zebra_vrf_lookup_by_id(VRF_DEFAULT); if (def) @@ -82,7 +83,6 @@ void table_manager_enable(struct zebra_vrf *zvrf) zvrf->tbl_mgr = XCALLOC(MTYPE_TM_TABLE, sizeof(struct table_manager)); zvrf->tbl_mgr->lc_list = list_new(); zvrf->tbl_mgr->lc_list->del = delete_table_chunk; - hook_register(zserv_client_close, release_daemon_table_chunks); } /** @@ -285,7 +285,8 @@ void table_manager_disable(struct zebra_vrf *zvrf) { if (!zvrf->tbl_mgr) return; - if (!vrf_is_backend_netns() && zvrf_id(zvrf) != VRF_DEFAULT) { + if (!vrf_is_backend_netns() + && strcmp(zvrf_name(zvrf), VRF_DEFAULT_NAME)) { zvrf->tbl_mgr = NULL; return; } diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index ecfc7da883..421438a051 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -185,7 +185,7 @@ int zsend_interface_add(struct zserv *client, struct interface *ifp) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_ADD, ifp->vrf->vrf_id); zserv_encode_interface(s, ifp); client->ifadd_cnt++; @@ -197,7 +197,7 @@ int zsend_interface_delete(struct zserv *client, struct interface *ifp) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_DELETE, ifp->vrf->vrf_id); zserv_encode_interface(s, ifp); client->ifdel_cnt++; @@ -237,7 +237,7 @@ int zsend_interface_link_params(struct zserv *client, struct interface *ifp) return 0; } - zclient_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_LINK_PARAMS, ifp->vrf->vrf_id); /* Add Interface Index */ stream_putl(s, ifp->ifindex); @@ -299,7 +299,7 @@ int zsend_interface_address(int cmd, struct zserv *client, struct prefix *p; struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf->vrf_id); stream_putl(s, ifp->ifindex); /* Interface address flag. */ @@ -341,7 +341,7 @@ static int zsend_interface_nbr_address(int cmd, struct zserv *client, struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); struct prefix *p; - zclient_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf->vrf_id); stream_putl(s, ifp->ifindex); /* Prefix information. */ @@ -459,7 +459,7 @@ int zsend_interface_vrf_update(struct zserv *client, struct interface *ifp, { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf_id); + zclient_create_header(s, ZEBRA_INTERFACE_VRF_UPDATE, ifp->vrf->vrf_id); /* Fill in the name of the interface and its new VRF (id) */ stream_put(s, ifp->name, INTERFACE_NAMSIZ); @@ -534,7 +534,7 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp) { struct stream *s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, cmd, ifp->vrf_id); + zclient_create_header(s, cmd, ifp->vrf->vrf_id); zserv_encode_interface(s, ifp); if (cmd == ZEBRA_INTERFACE_UP) @@ -604,8 +604,6 @@ int zsend_redistribute_route(int cmd, struct zserv *client, api_nh->bh_type = nexthop->bh_type; break; case NEXTHOP_TYPE_IPV4: - api_nh->gate.ipv4 = nexthop->gate.ipv4; - break; case NEXTHOP_TYPE_IPV4_IFINDEX: api_nh->gate.ipv4 = nexthop->gate.ipv4; api_nh->ifindex = nexthop->ifindex; @@ -614,8 +612,6 @@ int zsend_redistribute_route(int cmd, struct zserv *client, api_nh->ifindex = nexthop->ifindex; break; case NEXTHOP_TYPE_IPV6: - api_nh->gate.ipv6 = nexthop->gate.ipv6; - break; case NEXTHOP_TYPE_IPV6_IFINDEX: api_nh->gate.ipv6 = nexthop->gate.ipv6; api_nh->ifindex = nexthop->ifindex; @@ -875,8 +871,7 @@ void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, struct zebra_pbr_iptable ipt; uint16_t cmd = ZEBRA_IPTABLE_NOTIFY_OWNER; - if (!dplane_ctx_get_pbr_iptable(ctx, &ipt)) - return; + dplane_ctx_get_pbr_iptable(ctx, &ipt); if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: Notifying %s id %u note %u", __func__, @@ -893,7 +888,7 @@ void zsend_iptable_notify_owner(const struct zebra_dplane_ctx *ctx, s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, VRF_DEFAULT); - stream_put(s, ¬e, sizeof(note)); + stream_putw(s, note); stream_putl(s, ipt.unique); stream_put(s, ipt.ipset_name, ZEBRA_IPSET_NAME_SIZE); stream_putw_at(s, 0, stream_get_endp(s)); @@ -910,8 +905,7 @@ void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, struct zebra_pbr_ipset ipset; uint16_t cmd = ZEBRA_IPSET_NOTIFY_OWNER; - if (!dplane_ctx_get_pbr_ipset(ctx, &ipset)) - return; + dplane_ctx_get_pbr_ipset(ctx, &ipset); if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: Notifying %s id %u note %u", __func__, @@ -928,7 +922,7 @@ void zsend_ipset_notify_owner(const struct zebra_dplane_ctx *ctx, s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, VRF_DEFAULT); - stream_put(s, ¬e, sizeof(note)); + stream_putw(s, note); stream_putl(s, ipset.unique); stream_put(s, ipset.ipset_name, ZEBRA_IPSET_NAME_SIZE); stream_putw_at(s, 0, stream_get_endp(s)); @@ -946,10 +940,8 @@ void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, struct zebra_pbr_ipset ipset; uint16_t cmd = ZEBRA_IPSET_ENTRY_NOTIFY_OWNER; - if (!dplane_ctx_get_pbr_ipset_entry(ctx, &ipent)) - return; - if (!dplane_ctx_get_pbr_ipset(ctx, &ipset)) - return; + dplane_ctx_get_pbr_ipset_entry(ctx, &ipent); + dplane_ctx_get_pbr_ipset(ctx, &ipset); if (IS_ZEBRA_DEBUG_PACKET) zlog_debug("%s: Notifying %s id %u note %u", __func__, @@ -966,7 +958,7 @@ void zsend_ipset_entry_notify_owner(const struct zebra_dplane_ctx *ctx, s = stream_new(ZEBRA_MAX_PACKET_SIZ); zclient_create_header(s, cmd, VRF_DEFAULT); - stream_put(s, ¬e, sizeof(note)); + stream_putw(s, note); stream_putl(s, ipent.unique); stream_put(s, ipset.ipset_name, ZEBRA_IPSET_NAME_SIZE); stream_putw_at(s, 0, stream_get_endp(s)); @@ -993,7 +985,8 @@ void zsend_nhrp_neighbor_notify(int cmd, struct interface *ifp, family2addrsize(sockunion_family(&ip))); for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) { - if (!vrf_bitmap_check(client->nhrp_neighinfo[afi], ifp->vrf_id)) + if (!vrf_bitmap_check(client->nhrp_neighinfo[afi], + ifp->vrf->vrf_id)) continue; s = stream_new(ZEBRA_MAX_PACKET_SIZ); @@ -1164,13 +1157,6 @@ int zsend_zebra_srv6_locator_delete(struct zserv *client, /* Inbound message handling ------------------------------------------------ */ -const int cmd2type[] = { - [ZEBRA_NEXTHOP_REGISTER] = RNH_NEXTHOP_TYPE, - [ZEBRA_NEXTHOP_UNREGISTER] = RNH_NEXTHOP_TYPE, - [ZEBRA_IMPORT_ROUTE_REGISTER] = RNH_IMPORT_CHECK_TYPE, - [ZEBRA_IMPORT_ROUTE_UNREGISTER] = RNH_IMPORT_CHECK_TYPE, -}; - /* Nexthop register */ static void zread_rnh_register(ZAPI_HANDLER_ARGS) { @@ -1178,17 +1164,17 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) struct stream *s; struct prefix p; unsigned short l = 0; - uint8_t flags = 0; - uint16_t type = cmd2type[hdr->command]; + uint8_t connected = 0; + uint8_t resolve_via_default; bool exist; bool flag_changed = false; uint8_t orig_flags; + safi_t safi; if (IS_ZEBRA_DEBUG_NHT) zlog_debug( - "rnh_register msg from client %s: hdr->length=%d, type=%s vrf=%u", + "rnh_register msg from client %s: hdr->length=%d vrf=%u", zebra_route_string(client->proto), hdr->length, - (type == RNH_NEXTHOP_TYPE) ? "nexthop" : "route", zvrf->vrf->vrf_id); s = msg; @@ -1197,10 +1183,12 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) client->nh_reg_time = monotime(NULL); while (l < hdr->length) { - STREAM_GETC(s, flags); + STREAM_GETC(s, connected); + STREAM_GETC(s, resolve_via_default); + STREAM_GETW(s, safi); STREAM_GETW(s, p.family); STREAM_GETC(s, p.prefixlen); - l += 4; + l += 7; if (p.family == AF_INET) { client->v4_nh_watch_add_cnt++; if (p.prefixlen > IPV4_MAX_BITLEN) { @@ -1228,37 +1216,29 @@ static void zread_rnh_register(ZAPI_HANDLER_ARGS) p.family); return; } - rnh = zebra_add_rnh(&p, zvrf_id(zvrf), type, &exist); + rnh = zebra_add_rnh(&p, zvrf_id(zvrf), &exist); if (!rnh) return; orig_flags = rnh->flags; - if (type == RNH_NEXTHOP_TYPE) { - if (flags - && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) - SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); - else if (!flags - && CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) - UNSET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); - } else if (type == RNH_IMPORT_CHECK_TYPE) { - if (flags - && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH)) - SET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH); - else if (!flags - && CHECK_FLAG(rnh->flags, - ZEBRA_NHT_EXACT_MATCH)) - UNSET_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH); - } + if (connected && !CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + SET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + else if (!connected + && CHECK_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED)) + UNSET_FLAG(rnh->flags, ZEBRA_NHT_CONNECTED); + + if (resolve_via_default) + SET_FLAG(rnh->flags, ZEBRA_NHT_RESOLVE_VIA_DEFAULT); if (orig_flags != rnh->flags) flag_changed = true; /* Anything not AF_INET/INET6 has been filtered out above */ if (!exist || flag_changed) - zebra_evaluate_rnh(zvrf, family2afi(p.family), 1, type, - &p); + zebra_evaluate_rnh(zvrf, family2afi(p.family), 1, &p, + safi); - zebra_add_rnh_client(rnh, client, type, zvrf_id(zvrf)); + zebra_add_rnh_client(rnh, client, zvrf_id(zvrf)); } stream_failure: @@ -1272,7 +1252,7 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS) struct stream *s; struct prefix p; unsigned short l = 0; - uint16_t type = cmd2type[hdr->command]; + safi_t safi; if (IS_ZEBRA_DEBUG_NHT) zlog_debug( @@ -1283,15 +1263,19 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS) s = msg; while (l < hdr->length) { - uint8_t flags; + uint8_t ignore; - STREAM_GETC(s, flags); - if (flags != 0) + STREAM_GETC(s, ignore); + if (ignore != 0) + goto stream_failure; + STREAM_GETC(s, ignore); + if (ignore != 0) goto stream_failure; + STREAM_GETW(s, safi); STREAM_GETW(s, p.family); STREAM_GETC(s, p.prefixlen); - l += 4; + l += 7; if (p.family == AF_INET) { client->v4_nh_watch_rem_cnt++; if (p.prefixlen > IPV4_MAX_BITLEN) { @@ -1319,10 +1303,10 @@ static void zread_rnh_unregister(ZAPI_HANDLER_ARGS) p.family); return; } - rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), type); + rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), safi); if (rnh) { client->nh_dereg_time = monotime(NULL); - zebra_remove_rnh_client(rnh, client, type); + zebra_remove_rnh_client(rnh, client); } } stream_failure: @@ -3199,6 +3183,12 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) STREAM_GETW(s, zpr.rule.filter.dst_port); STREAM_GETC(s, zpr.rule.filter.dsfield); STREAM_GETL(s, zpr.rule.filter.fwmark); + + STREAM_GETL(s, zpr.rule.action.queue_id); + STREAM_GETW(s, zpr.rule.action.vlan_id); + STREAM_GETW(s, zpr.rule.action.vlan_flags); + STREAM_GETW(s, zpr.rule.action.pcp); + STREAM_GETL(s, zpr.rule.action.table); STREAM_GET(ifname, s, INTERFACE_NAMSIZ); @@ -3432,7 +3422,7 @@ static inline void zebra_gre_get(ZAPI_HANDLER_ARGS) zebra_ns_lookup(gre_info->link_nsid), gre_info->ifindex_link); if (ifp_link) - vrf_id_link = ifp_link->vrf_id; + vrf_id_link = ifp_link->vrf->vrf_id; stream_putl(s, vrf_id_link); stream_putl(s, gre_info->vtep_ip.s_addr); stream_putl(s, gre_info->vtep_ip_remote.s_addr); @@ -3443,6 +3433,7 @@ static inline void zebra_gre_get(ZAPI_HANDLER_ARGS) stream_putl(s, IFINDEX_INTERNAL); stream_putl(s, VRF_UNKNOWN); stream_putl(s, 0); + stream_putl(s, 0); } /* Write packet size. */ stream_putw_at(s, 0, stream_get_endp(s)); @@ -3683,8 +3674,6 @@ void (*const zserv_handlers[])(ZAPI_HANDLER_ARGS) = { [ZEBRA_HELLO] = zread_hello, [ZEBRA_NEXTHOP_REGISTER] = zread_rnh_register, [ZEBRA_NEXTHOP_UNREGISTER] = zread_rnh_unregister, - [ZEBRA_IMPORT_ROUTE_REGISTER] = zread_rnh_register, - [ZEBRA_IMPORT_ROUTE_UNREGISTER] = zread_rnh_unregister, [ZEBRA_BFD_DEST_UPDATE] = zebra_ptm_bfd_dst_register, [ZEBRA_BFD_DEST_REGISTER] = zebra_ptm_bfd_dst_register, [ZEBRA_BFD_DEST_DEREGISTER] = zebra_ptm_bfd_dst_deregister, diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index ab06ea6438..bf34fb54a9 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -261,6 +261,13 @@ struct dplane_ctx_rule { struct prefix src_ip; struct prefix dst_ip; uint8_t ip_proto; + + uint8_t action_pcp; + uint16_t action_vlan_id; + uint16_t action_vlan_flags; + + uint32_t action_queue_id; + char ifname[INTERFACE_NAMSIZ + 1]; }; @@ -334,7 +341,7 @@ struct zebra_dplane_ctx { struct dplane_rule_info rule; struct zebra_pbr_iptable iptable; struct zebra_pbr_ipset ipset; - union { + struct { struct zebra_pbr_ipset_entry entry; struct zebra_pbr_ipset_info info; } ipset_entry; @@ -2138,43 +2145,40 @@ dplane_ctx_get_br_port_backup_nhg_id(const struct zebra_dplane_ctx *ctx) } /* Accessors for PBR iptable information */ -bool -dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, - struct zebra_pbr_iptable *table) +void dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_iptable *table) { DPLANE_CTX_VALID(ctx); memcpy(table, &ctx->u.iptable, sizeof(struct zebra_pbr_iptable)); - return true; } -bool dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx, +void dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx, struct zebra_pbr_ipset *ipset) { DPLANE_CTX_VALID(ctx); - if (!ipset) - return false; + assert(ipset); + if (ctx->zd_op == DPLANE_OP_IPSET_ENTRY_ADD || ctx->zd_op == DPLANE_OP_IPSET_ENTRY_DELETE) { memset(ipset, 0, sizeof(struct zebra_pbr_ipset)); ipset->type = ctx->u.ipset_entry.info.type; + ipset->family = ctx->u.ipset_entry.info.family; memcpy(&ipset->ipset_name, &ctx->u.ipset_entry.info.ipset_name, ZEBRA_IPSET_NAME_SIZE); } else memcpy(ipset, &ctx->u.ipset, sizeof(struct zebra_pbr_ipset)); - return true; } -bool dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, +void dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, struct zebra_pbr_ipset_entry *entry) { DPLANE_CTX_VALID(ctx); - if (!entry) - return false; + assert(entry); + memcpy(entry, &ctx->u.ipset_entry.entry, sizeof(struct zebra_pbr_ipset_entry)); - return true; } /* @@ -2444,6 +2448,8 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, ret = ENOENT; goto done; } + + re->nhe_installed_id = nhe->id; } #endif /* HAVE_NETLINK */ @@ -2770,6 +2776,12 @@ static void dplane_ctx_rule_init_single(struct dplane_ctx_rule *dplane_rule, dplane_rule->ip_proto = rule->rule.filter.ip_proto; prefix_copy(&(dplane_rule->dst_ip), &rule->rule.filter.dst_ip); prefix_copy(&(dplane_rule->src_ip), &rule->rule.filter.src_ip); + + dplane_rule->action_pcp = rule->rule.action.pcp; + dplane_rule->action_vlan_flags = rule->rule.action.vlan_flags; + dplane_rule->action_vlan_id = rule->rule.action.vlan_id; + dplane_rule->action_queue_id = rule->rule.action.queue_id; + strlcpy(dplane_rule->ifname, rule->ifname, INTERFACE_NAMSIZ); } @@ -2930,6 +2942,7 @@ dplane_ctx_ipset_entry_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, sizeof(struct zebra_pbr_ipset_entry)); ctx->u.ipset_entry.entry.backpointer = NULL; ctx->u.ipset_entry.info.type = ipset->type; + ctx->u.ipset_entry.info.family = ipset->family; memcpy(&ctx->u.ipset_entry.info.ipset_name, &ipset->ipset_name, ZEBRA_IPSET_NAME_SIZE); @@ -3558,9 +3571,9 @@ dplane_br_port_update(const struct interface *ifp, bool non_df, ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; - ctx->zd_vrf_id = ifp->vrf_id; + ctx->zd_vrf_id = ifp->vrf->vrf_id; - zns = zebra_ns_lookup(ifp->vrf_id); + zns = zebra_ns_lookup(ifp->vrf->vrf_id); dplane_ctx_ns_init(ctx, zns, false); ctx->zd_ifindex = ifp->ifindex; @@ -3635,16 +3648,16 @@ static enum zebra_dplane_result intf_addr_update_internal( if (IS_ZEBRA_DEBUG_DPLANE_DETAIL) zlog_debug("init intf ctx %s: idx %d, addr %u:%pFX", - dplane_op2str(op), ifp->ifindex, ifp->vrf_id, + dplane_op2str(op), ifp->ifindex, ifp->vrf->vrf_id, ifc->address); ctx = dplane_ctx_alloc(); ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; - ctx->zd_vrf_id = ifp->vrf_id; + ctx->zd_vrf_id = ifp->vrf->vrf_id; - zns = zebra_ns_lookup(ifp->vrf_id); + zns = zebra_ns_lookup(ifp->vrf->vrf_id); dplane_ctx_ns_init(ctx, zns, false); /* Init the interface-addr-specific area */ @@ -3842,9 +3855,9 @@ void dplane_mac_init(struct zebra_dplane_ctx *ctx, struct zebra_ns *zns; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; - ctx->zd_vrf_id = ifp->vrf_id; + ctx->zd_vrf_id = ifp->vrf->vrf_id; - zns = zebra_ns_lookup(ifp->vrf_id); + zns = zebra_ns_lookup(ifp->vrf->vrf_id); dplane_ctx_ns_init(ctx, zns, false); strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname)); @@ -4067,9 +4080,9 @@ enum zebra_dplane_result dplane_neigh_table_update(const struct interface *ifp, ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; - ctx->zd_vrf_id = ifp->vrf_id; + ctx->zd_vrf_id = ifp->vrf->vrf_id; - zns = zebra_ns_lookup(ifp->vrf_id); + zns = zebra_ns_lookup(ifp->vrf->vrf_id); dplane_ctx_ns_init(ctx, zns, false); strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname)); @@ -4141,10 +4154,10 @@ neigh_update_internal(enum dplane_op_e op, const struct interface *ifp, ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; - ctx->zd_vrf_id = ifp->vrf_id; + ctx->zd_vrf_id = ifp->vrf->vrf_id; dplane_ctx_set_type(ctx, protocol); - zns = zebra_ns_lookup(ifp->vrf_id); + zns = zebra_ns_lookup(ifp->vrf->vrf_id); dplane_ctx_ns_init(ctx, zns, false); strlcpy(ctx->zd_ifname, ifp->name, sizeof(ctx->zd_ifname)); @@ -4392,13 +4405,13 @@ dplane_gre_set(struct interface *ifp, struct interface *ifp_link, ctx->zd_op = op; ctx->zd_status = ZEBRA_DPLANE_REQUEST_SUCCESS; - zns = zebra_ns_lookup(ifp->vrf_id); + zns = zebra_ns_lookup(ifp->vrf->vrf_id); if (!zns) return result; dplane_ctx_ns_init(ctx, zns, false); dplane_ctx_set_ifname(ctx, ifp->name); - ctx->zd_vrf_id = ifp->vrf_id; + ctx->zd_vrf_id = ifp->vrf->vrf_id; ctx->zd_ifindex = ifp->ifindex; if (ifp_link) ctx->u.gre.link_ifindex = ifp_link->ifindex; @@ -5045,29 +5058,30 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) case DPLANE_OP_IPTABLE_DELETE: { struct zebra_pbr_iptable ipt; - if (dplane_ctx_get_pbr_iptable(ctx, &ipt)) - zlog_debug("Dplane iptable update op %s, unique(%u), ctx %p", - dplane_op2str(dplane_ctx_get_op(ctx)), ipt.unique, ctx); + dplane_ctx_get_pbr_iptable(ctx, &ipt); + zlog_debug("Dplane iptable update op %s, unique(%u), ctx %p", + dplane_op2str(dplane_ctx_get_op(ctx)), ipt.unique, + ctx); } break; case DPLANE_OP_IPSET_ADD: case DPLANE_OP_IPSET_DELETE: { struct zebra_pbr_ipset ipset; - if (dplane_ctx_get_pbr_ipset(ctx, &ipset)) - zlog_debug("Dplane ipset update op %s, unique(%u), ctx %p", - dplane_op2str(dplane_ctx_get_op(ctx)), - ipset.unique, ctx); + dplane_ctx_get_pbr_ipset(ctx, &ipset); + zlog_debug("Dplane ipset update op %s, unique(%u), ctx %p", + dplane_op2str(dplane_ctx_get_op(ctx)), ipset.unique, + ctx); } break; case DPLANE_OP_IPSET_ENTRY_ADD: case DPLANE_OP_IPSET_ENTRY_DELETE: { struct zebra_pbr_ipset_entry ipent; - if (dplane_ctx_get_pbr_ipset_entry(ctx, &ipent)) - zlog_debug("Dplane ipset entry update op %s, unique(%u), ctx %p", - dplane_op2str(dplane_ctx_get_op(ctx)), - ipent.unique, ctx); + dplane_ctx_get_pbr_ipset_entry(ctx, &ipent); + zlog_debug( + "Dplane ipset entry update op %s, unique(%u), ctx %p", + dplane_op2str(dplane_ctx_get_op(ctx)), ipent.unique, + ctx); } break; - case DPLANE_OP_NEIGH_TABLE_UPDATE: zlog_debug("Dplane neigh table op %s, ifp %s, family %s", dplane_op2str(dplane_ctx_get_op(ctx)), diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index a23de61c80..977f00bd2a 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -526,17 +526,14 @@ const struct prefix * dplane_ctx_rule_get_old_dst_ip(const struct zebra_dplane_ctx *ctx); /* Accessors for policy based routing iptable information */ struct zebra_pbr_iptable; -bool -dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, - struct zebra_pbr_iptable *table); +void dplane_ctx_get_pbr_iptable(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_iptable *table); struct zebra_pbr_ipset; -bool -dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx, - struct zebra_pbr_ipset *ipset); +void dplane_ctx_get_pbr_ipset(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset *ipset); struct zebra_pbr_ipset_entry; -bool -dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, - struct zebra_pbr_ipset_entry *entry); +void dplane_ctx_get_pbr_ipset_entry(const struct zebra_dplane_ctx *ctx, + struct zebra_pbr_ipset_entry *entry); /* Accessors for bridge port information */ uint32_t dplane_ctx_get_br_port_flags(const struct zebra_dplane_ctx *ctx); uint32_t diff --git a/zebra/zebra_evpn.c b/zebra/zebra_evpn.c index d5e043eea8..13b9cc2002 100644 --- a/zebra/zebra_evpn.c +++ b/zebra/zebra_evpn.c @@ -152,12 +152,10 @@ void zebra_evpn_print(struct zebra_evpn *zevpn, void **ctxt) json_object_int_add(json, "sviIfindex", zevpn->svi_if->ifindex); } - json_object_string_add(json, "vtepIp", - inet_ntop(AF_INET, &zevpn->local_vtep_ip, - buf, sizeof(buf))); - json_object_string_add(json, "mcastGroup", - inet_ntop(AF_INET, &zevpn->mcast_grp, - buf, sizeof(buf))); + json_object_string_addf(json, "vtepIp", "%pI4", + &zevpn->local_vtep_ip); + json_object_string_addf(json, "mcastGroup", "%pI4", + &zevpn->mcast_grp); json_object_string_add(json, "advertiseGatewayMacip", zevpn->advertise_gw_macip ? "Yes" : "No"); json_object_string_add(json, "advertiseSviMacip", @@ -419,10 +417,10 @@ int zebra_evpn_advertise_subnet(struct zebra_evpn *zevpn, struct interface *ifp, apply_mask(&p); if (advertise) - ip_prefix_send_to_client(ifp->vrf_id, &p, + ip_prefix_send_to_client(ifp->vrf->vrf_id, &p, ZEBRA_IP_PREFIX_ROUTE_ADD); else - ip_prefix_send_to_client(ifp->vrf_id, &p, + ip_prefix_send_to_client(ifp->vrf->vrf_id, &p, ZEBRA_IP_PREFIX_ROUTE_DEL); } return 0; @@ -483,7 +481,7 @@ int zebra_evpn_gw_macip_del(struct interface *ifp, struct zebra_evpn *zevpn, if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug( "%u:SVI %s(%u) VNI %u, sending GW MAC %pEA IP %pIA del to BGP", - ifp->vrf_id, ifp->name, ifp->ifindex, zevpn->vni, + ifp->vrf->vrf_id, ifp->name, ifp->ifindex, zevpn->vni, &n->emac, ip); /* Remove neighbor from BGP. */ @@ -1423,8 +1421,24 @@ void zebra_evpn_rem_macip_add(vni_t vni, const struct ethaddr *macaddr, * REMOTE - if ES is not local */ if (flags & ZEBRA_MACIP_TYPE_SYNC_PATH) { - zebra_evpn_process_sync_macip_add(zevpn, macaddr, ipa_len, - ipaddr, flags, seq, esi); + struct zebra_evpn_es *es; + + es = zebra_evpn_es_find(esi); + if (es && (es->flags & ZEBRA_EVPNES_READY_FOR_BGP)) { + zebra_evpn_process_sync_macip_add(zevpn, macaddr, + ipa_len, ipaddr, + flags, seq, esi); + } else { + if (IS_ZEBRA_DEBUG_EVPN_MH_ES) { + char esi_str[ESI_STR_LEN]; + + esi_to_str(esi, esi_str, sizeof(esi_str)); + zlog_debug( + "Ignore sync-macip add; ES %s is not ready", + esi_str); + } + } + return; } @@ -1517,7 +1531,7 @@ void zebra_evpn_rem_macip_del(vni_t vni, const struct ethaddr *macaddr, if (!mac && !n) return; - zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id); + zvrf = zevpn->vxlan_if->vrf->info; /* Ignore the delete if this mac is a gateway mac-ip */ if (CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL) diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index 472e53b730..d3791f3e58 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -106,19 +106,6 @@ static void zebra_evpn_mac_ifp_new(struct zebra_if *zif) listset_app_node_mem(zif->mac_list); } -/* Free up the mac_list if any as a part of the interface del/cleanup */ -void zebra_evpn_mac_ifp_del(struct interface *ifp) -{ - struct zebra_if *zif = ifp->info; - - if (zif->mac_list) { - if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) - zlog_debug("MAC list deleted for ifp %s (%u)", - zif->ifp->name, zif->ifp->ifindex); - list_delete(&zif->mac_list); - } -} - /* Unlink local mac from a destination access port */ static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac) { @@ -139,6 +126,25 @@ static void zebra_evpn_mac_ifp_unlink(struct zebra_mac *zmac) zmac->ifp = NULL; } +/* Free up the mac_list if any as a part of the interface del/cleanup */ +void zebra_evpn_mac_ifp_del(struct interface *ifp) +{ + struct zebra_if *zif = ifp->info; + struct listnode *node; + struct zebra_mac *zmac; + + if (zif->mac_list) { + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug("MAC list deleted for ifp %s (%u)", + zif->ifp->name, zif->ifp->ifindex); + + for (ALL_LIST_ELEMENTS_RO(zif->mac_list, node, zmac)) { + zebra_evpn_mac_ifp_unlink(zmac); + } + list_delete(&zif->mac_list); + } +} + /* Link local mac to destination access port. This is done only if the * local mac is associated with a zero ESI i.e. single attach or lacp-bypass * bridge port member @@ -613,7 +619,6 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) struct listnode *node = NULL; char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; - char addr_buf[PREFIX_STRLEN]; struct zebra_vrf *zvrf; struct timeval detect_start_time = {0, 0}; char timebuf[MONOTIME_STRLEN]; @@ -652,10 +657,8 @@ void zebra_evpn_print_mac(struct zebra_mac *mac, void *ctxt, json_object *json) json_object_int_add(json_mac, "vlan", vid); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_REMOTE)) { json_object_string_add(json_mac, "type", "remote"); - json_object_string_add( - json_mac, "remoteVtep", - inet_ntop(AF_INET, &mac->fwd_info.r_vtep_ip, - addr_buf, sizeof(addr_buf))); + json_object_string_addf(json_mac, "remoteVtep", "%pI4", + &mac->fwd_info.r_vtep_ip); } else if (CHECK_FLAG(mac->flags, ZEBRA_MAC_AUTO)) json_object_string_add(json_mac, "type", "auto"); @@ -938,10 +941,8 @@ void zebra_evpn_print_mac_hash(struct hash_bucket *bucket, void *ctxt) "", mac->loc_seq, mac->rem_seq); } else { json_object_string_add(json_mac, "type", "remote"); - json_object_string_add( - json_mac, "remoteVtep", - inet_ntop(AF_INET, &mac->fwd_info.r_vtep_ip, - addr_buf, sizeof(addr_buf))); + json_object_string_addf(json_mac, "remoteVtep", "%pI4", + &mac->fwd_info.r_vtep_ip); json_object_object_add(json_mac_hdr, buf1, json_mac); json_object_int_add(json_mac, "localSequence", mac->loc_seq); @@ -1342,6 +1343,25 @@ int zebra_evpn_sync_mac_dp_install(struct zebra_mac *mac, bool set_inactive, struct zebra_if *zif; struct interface *br_ifp; + /* If the ES-EVI doesn't exist defer install. When the ES-EVI is + * created we will attempt to install the mac entry again + */ + if (mac->es) { + struct zebra_evpn_es_evi *es_evi; + + es_evi = zebra_evpn_es_evi_find(mac->es, mac->zevpn); + if (!es_evi) { + if (IS_ZEBRA_DEBUG_EVPN_MH_MAC) + zlog_debug( + "%s: dp-install sync-mac vni %u mac %pEA es %s 0x%x %sskipped, no es-evi", + caller, zevpn->vni, &mac->macaddr, + mac->es ? mac->es->esi_str : "-", + mac->flags, + set_inactive ? "inactive " : ""); + return -1; + } + } + /* get the access vlan from the vxlan_device */ zebra_evpn_mac_get_access_info(mac, &ifp, &vid); @@ -1857,7 +1877,7 @@ static bool zebra_evpn_local_mac_update_fwd_info(struct zebra_mac *mac, struct zebra_vrf *zvrf; struct zebra_evpn_es *es; - zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + zvrf = ifp->vrf->info; if (zvrf && zvrf->zns) local_ns_id = zvrf->zns->ns_id; @@ -2014,13 +2034,6 @@ int zebra_evpn_mac_remote_macip_add( if (update_mac) { if (!mac) { mac = zebra_evpn_mac_add(zevpn, macaddr); - if (!mac) { - zlog_warn( - "Failed to add MAC %pEA VNI %u Remote VTEP %pI4", - macaddr, zevpn->vni, &vtep_ip); - return -1; - } - zebra_evpn_es_mac_ref(mac, esi); /* Is this MAC created for a MACIP? */ @@ -2162,14 +2175,6 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, local_inactive ? " local-inactive" : ""); mac = zebra_evpn_mac_add(zevpn, macaddr); - if (!mac) { - flog_err( - EC_ZEBRA_MAC_ADD_FAILED, - "Failed to add MAC %pEA intf %s(%u) VID %u VNI %u", - macaddr, ifp->name, ifp->ifindex, vid, - zevpn->vni); - return -1; - } SET_FLAG(mac->flags, ZEBRA_MAC_LOCAL); es_change = zebra_evpn_local_mac_update_fwd_info(mac, ifp, vid); if (sticky) @@ -2216,7 +2221,7 @@ int zebra_evpn_add_update_local_mac(struct zebra_vrf *zvrf, zlog_debug( " Add/Update %sMAC %pEA intf %s(%u) VID %u -> VNI %u%s, " "entry exists and has not changed ", - sticky ? "sticky " : "", + sticky ? "sticky " : "", macaddr, ifp->name, ifp->ifindex, vid, zevpn->vni, local_inactive @@ -2461,20 +2466,13 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, struct zebra_evpn *zevpn, ns_id_t local_ns_id = NS_DEFAULT; struct zebra_vrf *zvrf; - zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + zvrf = ifp->vrf->info; if (zvrf && zvrf->zns) local_ns_id = zvrf->zns->ns_id; mac = zebra_evpn_mac_lookup(zevpn, macaddr); - if (!mac) { + if (!mac) mac = zebra_evpn_mac_add(zevpn, macaddr); - if (!mac) { - flog_err(EC_ZEBRA_MAC_ADD_FAILED, - "Failed to add MAC %pEA intf %s(%u) VID %u", - macaddr, ifp->name, ifp->ifindex, vlan_id); - return -1; - } - } /* Set "local" forwarding info. */ zebra_evpn_mac_clear_fwd_info(mac); diff --git a/zebra/zebra_evpn_mh.c b/zebra/zebra_evpn_mh.c index e03cf9db06..af4629e41c 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -186,8 +186,8 @@ static void zebra_evpn_es_evi_free(struct zebra_evpn_es_evi *es_evi) } /* find the ES-EVI in the per-L2-VNI RB tree */ -static struct zebra_evpn_es_evi * -zebra_evpn_es_evi_find(struct zebra_evpn_es *es, struct zebra_evpn *zevpn) +struct zebra_evpn_es_evi *zebra_evpn_es_evi_find(struct zebra_evpn_es *es, + struct zebra_evpn *zevpn) { struct zebra_evpn_es_evi es_evi; @@ -229,6 +229,34 @@ static void zebra_evpn_local_es_evi_del(struct zebra_evpn_es *es, zebra_evpn_local_es_evi_do_del(es_evi); } +/* If there are any existing MAC entries for this es/zevpn we need + * to install it in the dataplane. + * + * Note: primary purpose of this is to handle es del/re-add windows where + * sync MAC entries may be added by bgpd before the es-evi membership is + * created in the dataplane and in zebra + */ +static void zebra_evpn_es_evi_mac_install(struct zebra_evpn_es_evi *es_evi) +{ + struct zebra_mac *mac; + struct listnode *node; + struct zebra_evpn_es *es = es_evi->es; + + if (listcount(es->mac_list) && IS_ZEBRA_DEBUG_EVPN_MH_ES) + zlog_debug("dp-mac install on es %s evi %d add", es->esi_str, + es_evi->zevpn->vni); + + for (ALL_LIST_ELEMENTS_RO(es->mac_list, node, mac)) { + if (mac->zevpn != es_evi->zevpn) + continue; + + if (!CHECK_FLAG(mac->flags, ZEBRA_MAC_LOCAL)) + continue; + + zebra_evpn_sync_mac_dp_install(mac, false, false, __func__); + } +} + /* Create an ES-EVI if it doesn't already exist and tell BGP */ static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es *es, struct zebra_evpn *zevpn) @@ -250,6 +278,8 @@ static void zebra_evpn_local_es_evi_add(struct zebra_evpn_es *es, listnode_add(zevpn->local_es_evi_list, &es_evi->l2vni_listnode); zebra_evpn_es_evi_re_eval_send_to_client(es_evi); + + zebra_evpn_es_evi_mac_install(es_evi); } } @@ -388,12 +418,8 @@ void zebra_evpn_es_evi_show(struct vty *vty, bool uj, int detail) hash_iterate(zvrf->evpn_table, zebra_evpn_es_evi_show_one_evpn_hash_cb, &wctx); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail) @@ -416,12 +442,8 @@ void zebra_evpn_es_evi_show_vni(struct vty *vty, bool uj, vni_t vni, int detail) vty_out(vty, "VNI %d doesn't exist\n", vni); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } /* Initialize the ES tables maintained per-L2_VNI */ @@ -968,12 +990,8 @@ void zebra_evpn_acc_vl_show(struct vty *vty, bool uj) hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash, &wctx); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj) @@ -991,12 +1009,8 @@ void zebra_evpn_acc_vl_show_detail(struct vty *vty, bool uj) hash_iterate(zmh_info->evpn_vlan_table, zebra_evpn_acc_vl_show_hash, &wctx); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid) @@ -1015,12 +1029,8 @@ void zebra_evpn_acc_vl_show_vid(struct vty *vty, bool uj, vlanid_t vid) vty_out(vty, "VLAN %u not present\n", vid); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); } /* Initialize VLAN member bitmap on an interface. Although VLAN membership @@ -1050,15 +1060,15 @@ void zebra_evpn_if_cleanup(struct zebra_if *zif) vlanid_t vid; struct zebra_evpn_es *es; - if (!bf_is_inited(zif->vlan_bitmap)) - return; + if (bf_is_inited(zif->vlan_bitmap)) { + bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) + { + zebra_evpn_vl_mbr_deref(vid, zif); + } - bf_for_each_set_bit(zif->vlan_bitmap, vid, IF_VLAN_BITMAP_MAX) { - zebra_evpn_vl_mbr_deref(vid, zif); + bf_free(zif->vlan_bitmap); } - bf_free(zif->vlan_bitmap); - /* Delete associated Ethernet Segment */ es = zif->es_info.es; if (es) @@ -1295,12 +1305,9 @@ static void zebra_evpn_es_l2_nh_show_entry(struct zebra_evpn_l2_nh *nh, { if (json_array) { json_object *json = NULL; - char ip_buf[INET6_ADDRSTRLEN]; json = json_object_new_object(); - json_object_string_add(json, "vtep", - inet_ntop(AF_INET, &nh->vtep_ip, ip_buf, - sizeof(ip_buf))); + json_object_string_addf(json, "vtep", "%pI4", &nh->vtep_ip); json_object_int_add(json, "nhId", nh->nh_id); json_object_int_add(json, "refCnt", nh->ref_cnt); @@ -1336,12 +1343,8 @@ void zebra_evpn_l2_nh_show(struct vty *vty, bool uj) hash_iterate(zmh_info->nh_ip_table, zebra_evpn_l2_nh_show_cb, &wctx); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } static struct zebra_evpn_l2_nh *zebra_evpn_l2_nh_find(struct in_addr vtep_ip) @@ -2978,13 +2981,11 @@ static void zebra_evpn_es_json_vtep_fill(struct zebra_evpn_es *es, struct listnode *node; json_object *json_vtep_entry; char alg_buf[EVPN_DF_ALG_STR_LEN]; - char ip_buf[INET6_ADDRSTRLEN]; for (ALL_LIST_ELEMENTS_RO(es->es_vtep_list, node, es_vtep)) { json_vtep_entry = json_object_new_object(); - json_object_string_add(json_vtep_entry, "vtep", - inet_ntop(AF_INET, &es_vtep->vtep_ip, - ip_buf, sizeof(ip_buf))); + json_object_string_addf(json_vtep_entry, "vtep", "%pI4", + &es_vtep->vtep_ip); if (es_vtep->flags & ZEBRA_EVPNES_VTEP_RXED_ESR) { json_object_string_add( json_vtep_entry, "dfAlgorithm", @@ -3192,12 +3193,8 @@ void zebra_evpn_es_show(struct vty *vty, bool uj) RB_FOREACH(es, zebra_es_rb_head, &zmh_info->es_rb_tree) zebra_evpn_es_show_entry(vty, es, json_array); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } void zebra_evpn_es_show_detail(struct vty *vty, bool uj) @@ -3218,12 +3215,8 @@ void zebra_evpn_es_show_detail(struct vty *vty, bool uj) json_object_array_add(json_array, json); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (uj) + vty_json(vty, json_array); } void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi) @@ -3246,12 +3239,8 @@ void zebra_evpn_es_show_esi(struct vty *vty, bool uj, esi_t *esi) } } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); } int zebra_evpn_mh_if_write(struct vty *vty, struct interface *ifp) diff --git a/zebra/zebra_evpn_mh.h b/zebra/zebra_evpn_mh.h index 853af7c4bc..af6832092b 100644 --- a/zebra/zebra_evpn_mh.h +++ b/zebra/zebra_evpn_mh.h @@ -387,5 +387,7 @@ extern void zebra_evpn_acc_bd_svi_mac_add(struct interface *vlan_if); extern void zebra_evpn_es_bypass_update(struct zebra_evpn_es *es, struct interface *ifp, bool bypass); extern void zebra_evpn_proc_remote_nh(ZAPI_HANDLER_ARGS); +extern struct zebra_evpn_es_evi * +zebra_evpn_es_evi_find(struct zebra_evpn_es *es, struct zebra_evpn *zevpn); #endif /* _ZEBRA_EVPN_MH_H */ diff --git a/zebra/zebra_evpn_neigh.c b/zebra/zebra_evpn_neigh.c index af46ea6d7a..7299391ef6 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -923,7 +923,7 @@ void zebra_evpn_process_neigh_on_local_mac_change(struct zebra_evpn *zevpn, struct listnode *node = NULL; struct zebra_vrf *zvrf = NULL; - zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id); + zvrf = zevpn->vxlan_if->vrf->info; if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug("Processing neighbors on local MAC %pEA %s, VNI %u", @@ -1286,12 +1286,6 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn, macaddr, ip, zevpn->vni); zmac = zebra_evpn_mac_add(zevpn, macaddr); - if (!zmac) { - zlog_debug("Failed to add MAC %pEA VNI %u", macaddr, - zevpn->vni); - return -1; - } - zebra_evpn_mac_clear_fwd_info(zmac); memset(&zmac->flags, 0, sizeof(uint32_t)); SET_FLAG(zmac->flags, ZEBRA_MAC_AUTO); @@ -1308,11 +1302,11 @@ int zebra_evpn_local_neigh_update(struct zebra_evpn *zevpn, } } - zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id); + zvrf = zevpn->vxlan_if->vrf->info; if (!zvrf) { if (IS_ZEBRA_DEBUG_VXLAN) zlog_debug(" Unable to find vrf for: %d", - zevpn->vxlan_if->vrf_id); + zevpn->vxlan_if->vrf->vrf_id); return -1; } @@ -1725,7 +1719,6 @@ void zebra_evpn_print_neigh(struct zebra_neigh *n, void *ctxt, struct vty *vty; char buf1[ETHER_ADDR_STRLEN]; char buf2[INET6_ADDRSTRLEN]; - char addr_buf[PREFIX_STRLEN]; const char *type_str; const char *state_str; bool flags_present = false; @@ -1812,10 +1805,8 @@ void zebra_evpn_print_neigh(struct zebra_neigh *n, void *ctxt, n->mac->es->esi_str); } else { if (json) - json_object_string_add( - json, "remoteVtep", - inet_ntop(AF_INET, &n->r_vtep_ip, - addr_buf, sizeof(addr_buf))); + json_object_string_addf(json, "remoteVtep", + "%pI4", &n->r_vtep_ip); else vty_out(vty, " Remote VTEP: %pI4\n", &n->r_vtep_ip); @@ -1974,10 +1965,8 @@ void zebra_evpn_print_neigh_hash(struct hash_bucket *bucket, void *ctxt) json_object_string_add(json_row, "remoteEs", n->mac->es->esi_str); else - json_object_string_add( - json_row, "remoteVtep", - inet_ntop(AF_INET, &n->r_vtep_ip, - addr_buf, sizeof(addr_buf))); + json_object_string_addf(json_row, "remoteVtep", + "%pI4", &n->r_vtep_ip); if (CHECK_FLAG(n->flags, ZEBRA_NEIGH_DEF_GW)) json_object_boolean_true_add(json_row, "defaultGateway"); @@ -2342,7 +2331,7 @@ int zebra_evpn_neigh_del_ip(struct zebra_evpn *zevpn, const struct ipaddr *ip) return 0; } - zvrf = vrf_info_lookup(zevpn->vxlan_if->vrf_id); + zvrf = zevpn->vxlan_if->vrf->info; if (!zvrf) { zlog_debug("%s: VNI %u vrf lookup failed.", __func__, zevpn->vni); diff --git a/zebra/zebra_evpn_vxlan.h b/zebra/zebra_evpn_vxlan.h index c7acd23436..3884a1e7ea 100644 --- a/zebra/zebra_evpn_vxlan.h +++ b/zebra/zebra_evpn_vxlan.h @@ -28,7 +28,7 @@ zebra_get_vrr_intf_for_svi(struct interface *ifp) struct interface *tmp_if = NULL; struct zebra_if *zif = NULL; - zvrf = vrf_info_lookup(ifp->vrf_id); + zvrf = ifp->vrf->info; assert(zvrf); FOR_ALL_INTERFACES (zvrf->vrf, tmp_if) { diff --git a/zebra/zebra_l2.c b/zebra/zebra_l2.c index 5a02149611..8a9f3dffe3 100644 --- a/zebra/zebra_l2.c +++ b/zebra/zebra_l2.c @@ -58,7 +58,7 @@ static void map_slaves_to_bridge(struct interface *br_if, int link, struct zebra_vrf *zvrf; struct zebra_ns *zns; - zvrf = zebra_vrf_lookup_by_id(br_if->vrf_id); + zvrf = br_if->vrf->info; assert(zvrf); zns = zvrf->zns; assert(zns); @@ -162,7 +162,7 @@ void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf_id) struct zebra_if *bond_zif; struct zebra_l2info_bondslave *bond_slave = &zif->bondslave_info; - bond_if = if_lookup_by_index_all_vrf(bond_slave->bond_ifindex); + bond_if = if_lookup_by_index(bond_slave->bond_ifindex, vrf_id); if (bond_if == bond_slave->bond_if) return; @@ -425,16 +425,16 @@ void zebra_l2if_update_bridge_slave(struct interface *ifp, zif = ifp->info; assert(zif); - zvrf = zebra_vrf_lookup_by_id(ifp->vrf_id); + zvrf = ifp->vrf->info; if (!zvrf) return; if (zif->zif_type == ZEBRA_IF_VXLAN && chgflags != ZEBRA_BRIDGE_NO_ACTION) { - if (ZEBRA_BRIDGE_MASTER_MAC_CHANGE) + if (chgflags & ZEBRA_BRIDGE_MASTER_MAC_CHANGE) zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_MAC_CHANGE); - if (ZEBRA_BRIDGE_MASTER_UP) + if (chgflags & ZEBRA_BRIDGE_MASTER_UP) zebra_vxlan_if_update(ifp, ZEBRA_VXLIF_MASTER_CHANGE); } old_bridge_ifindex = zif->brslave_info.bridge_ifindex; @@ -505,7 +505,7 @@ void zebra_l2if_update_bond_slave(struct interface *ifp, ifindex_t bond_ifindex, /* Set up or remove link with master */ if (bond_ifindex != IFINDEX_INTERNAL) - zebra_l2_map_slave_to_bond(zif, ifp->vrf_id); + zebra_l2_map_slave_to_bond(zif, ifp->vrf->vrf_id); else if (old_bond_ifindex != IFINDEX_INTERNAL) zebra_l2_unmap_slave_from_bond(zif); } diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 00ac98cbc0..924a43049b 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -1037,6 +1037,16 @@ static void lsp_processq_del(struct work_queue *wq, void *data) struct zebra_lsp *lsp; struct hash *lsp_table; struct zebra_nhlfe *nhlfe; + bool in_shutdown = false; + + /* If zebra is shutting down, don't delete any structs, + * just ignore this callback. The LSPs will be cleaned up + * during the shutdown processing. + */ + in_shutdown = atomic_load_explicit(&zrouter.in_shutdown, + memory_order_relaxed); + if (in_shutdown) + return; zvrf = vrf_info_lookup(VRF_DEFAULT); assert(zvrf); @@ -1504,7 +1514,6 @@ static int mpls_static_lsp_uninstall_all(struct zebra_vrf *zvrf, static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe) { - char buf[BUFSIZ]; json_object *json_nhlfe = NULL; json_object *json_backups = NULL; json_object *json_label_stack; @@ -1531,15 +1540,13 @@ static json_object *nhlfe_json(struct zebra_nhlfe *nhlfe) switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - json_object_string_add(json_nhlfe, "nexthop", - inet_ntop(AF_INET, &nexthop->gate.ipv4, - buf, sizeof(buf))); + json_object_string_addf(json_nhlfe, "nexthop", "%pI4", + &nexthop->gate.ipv4); break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - json_object_string_add( - json_nhlfe, "nexthop", - inet_ntop(AF_INET6, &nexthop->gate.ipv6, buf, BUFSIZ)); + json_object_string_addf(json_nhlfe, "nexthop", "%pI6", + &nexthop->gate.ipv6); if (nexthop->ifindex) json_object_string_add(json_nhlfe, "interface", @@ -3718,9 +3725,7 @@ void zebra_mpls_print_lsp(struct vty *vty, struct zebra_vrf *zvrf, if (use_json) { json = lsp_json(lsp); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else lsp_print(vty, lsp); } @@ -3747,9 +3752,7 @@ void zebra_mpls_print_lsp_table(struct vty *vty, struct zebra_vrf *zvrf, sizeof(buf)), lsp_json(lsp)); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { struct ttable *tt; diff --git a/zebra/zebra_netns_notify.c b/zebra/zebra_netns_notify.c index 61f97ce6a9..391f28d18f 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -42,6 +42,7 @@ #include "zebra_netns_notify.h" #include "zebra_netns_id.h" #include "zebra_errors.h" +#include "interface.h" #ifdef HAVE_NETLINK @@ -66,6 +67,18 @@ static int zebra_ns_continue_read(struct zebra_netns_info *zns_info, int stop_retry); static int zebra_ns_notify_read(struct thread *t); +static struct vrf *vrf_handler_create(struct vty *vty, const char *vrfname) +{ + if (strlen(vrfname) > VRF_NAMSIZ) { + flog_warn(EC_LIB_VRF_LENGTH, + "%% VRF name %s invalid: length exceeds %d bytes", + vrfname, VRF_NAMSIZ); + return NULL; + } + + return vrf_get(VRF_UNKNOWN, vrfname); +} + static void zebra_ns_notify_create_context_from_entry_name(const char *name) { char *netnspath = ns_netns_pathname(NULL, name); @@ -91,7 +104,8 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name) vrf->name, netnspath); return; } - if (vrf_handler_create(NULL, name, &vrf) != CMD_SUCCESS) { + vrf = vrf_handler_create(NULL, name); + if (!vrf) { flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED, "NS notify : failed to create VRF %s", name); ns_map_nsid_with_external(ns_id, false); @@ -108,10 +122,9 @@ static void zebra_ns_notify_create_context_from_entry_name(const char *name) } frr_with_privs(&zserv_privs) { - ret = vrf_netns_handler_create(NULL, vrf, netnspath, - ns_id_external, - ns_id, - ns_id_relative); + ret = zebra_vrf_netns_handler_create(NULL, vrf, netnspath, + ns_id_external, ns_id, + ns_id_relative); } if (ret != CMD_SUCCESS) { flog_warn(EC_ZEBRA_NS_VRF_CREATION_FAILED, @@ -142,6 +155,7 @@ static int zebra_ns_continue_read(struct zebra_netns_info *zns_info, static int zebra_ns_delete(char *name) { struct vrf *vrf = vrf_lookup_by_name(name); + struct interface *ifp, *tmp; struct ns *ns; if (!vrf) { @@ -149,10 +163,30 @@ static int zebra_ns_delete(char *name) "NS notify : no VRF found using NS %s", name); return 0; } + + /* + * We don't receive interface down/delete notifications from kernel + * when a netns is deleted. Therefore we have to manually replicate + * the necessary actions here. + */ + RB_FOREACH_SAFE (ifp, if_name_head, &vrf->ifaces_by_name, tmp) { + if (!CHECK_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE)) + continue; + + if (if_is_no_ptm_operative(ifp)) { + UNSET_FLAG(ifp->flags, IFF_RUNNING); + if_down(ifp); + } + + UNSET_FLAG(ifp->flags, IFF_UP); + if_delete_update(ifp); + } + ns = (struct ns *)vrf->ns_ctxt; /* the deletion order is the same * as the one used when siging signal is received */ + vrf->ns_ctxt = NULL; vrf_delete(vrf); if (ns) ns_delete(ns); @@ -249,8 +283,8 @@ static int zebra_ns_notify_read(struct thread *t) char buf[BUFSIZ]; ssize_t len; - zebra_netns_notify_current = thread_add_read( - zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); + thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, + &zebra_netns_notify_current); len = read(fd_monitor, buf, sizeof(buf)); if (len < 0) { flog_err_sys(EC_ZEBRA_NS_NOTIFY_READ, @@ -359,8 +393,8 @@ void zebra_ns_notify_init(void) "NS notify watch: failed to add watch (%s)", safe_strerror(errno)); } - zebra_netns_notify_current = thread_add_read( - zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, NULL); + thread_add_read(zrouter.master, zebra_ns_notify_read, NULL, fd_monitor, + &zebra_netns_notify_current); } void zebra_ns_notify_close(void) diff --git a/zebra/zebra_pbr.c b/zebra/zebra_pbr.c index 3607110aa2..e66d7aaf5c 100644 --- a/zebra/zebra_pbr.c +++ b/zebra/zebra_pbr.c @@ -552,13 +552,12 @@ void zebra_pbr_process_iptable(struct zebra_dplane_ctx *ctx) else mode = 0; - if (dplane_ctx_get_pbr_iptable(ctx, &ipt)) { - ret = hook_call(zebra_pbr_iptable_update, mode, &ipt); - if (ret) - dplane_ctx_set_status(ctx, - ZEBRA_DPLANE_REQUEST_SUCCESS); - } - if (!ret) + dplane_ctx_get_pbr_iptable(ctx, &ipt); + + ret = hook_call(zebra_pbr_iptable_update, mode, &ipt); + if (ret) + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); + else dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); } @@ -571,13 +570,13 @@ void zebra_pbr_process_ipset(struct zebra_dplane_ctx *ctx) mode = 1; else mode = 0; - if (dplane_ctx_get_pbr_ipset(ctx, &ipset)) { - ret = hook_call(zebra_pbr_ipset_update, mode, &ipset); - if (ret) - dplane_ctx_set_status(ctx, - ZEBRA_DPLANE_REQUEST_SUCCESS); - } - if (!ret) + + dplane_ctx_get_pbr_ipset(ctx, &ipset); + + ret = hook_call(zebra_pbr_ipset_update, mode, &ipset); + if (ret) + dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_SUCCESS); + else dplane_ctx_set_status(ctx, ZEBRA_DPLANE_REQUEST_FAILURE); } @@ -592,10 +591,9 @@ void zebra_pbr_process_ipset_entry(struct zebra_dplane_ctx *ctx) else mode = 0; - if (!dplane_ctx_get_pbr_ipset_entry(ctx, &ipset_entry)) - return; - if (!dplane_ctx_get_pbr_ipset(ctx, &ipset)) - return; + dplane_ctx_get_pbr_ipset_entry(ctx, &ipset_entry); + dplane_ctx_get_pbr_ipset(ctx, &ipset); + ipset_entry.backpointer = &ipset; ret = hook_call(zebra_pbr_ipset_entry_update, mode, &ipset_entry); diff --git a/zebra/zebra_pbr.h b/zebra/zebra_pbr.h index 2e9658e7e5..c5102df4fa 100644 --- a/zebra/zebra_pbr.h +++ b/zebra/zebra_pbr.h @@ -70,6 +70,8 @@ struct zebra_pbr_ipset_info { */ uint32_t type; + uint8_t family; + char ipset_name[ZEBRA_IPSET_NAME_SIZE]; }; diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index e17465b112..32edb78c7d 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -518,7 +518,7 @@ static int zebra_ptm_handle_bfd_msg(void *arg, void *in_ctxt, } if (!strcmp(ZEBRA_PTM_INVALID_VRF, vrf_str) && ifp) { - vrf_id = ifp->vrf_id; + vrf_id = ifp->vrf->vrf_id; } else { struct vrf *pVrf; @@ -609,7 +609,17 @@ static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt) } if (strcmp(ZEBRA_PTM_INVALID_PORT_NAME, port_str)) { - ifp = if_lookup_by_name_all_vrf(port_str); + struct vrf *vrf; + int count = 0; + + RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { + ifp = if_lookup_by_name_vrf(port_str, vrf); + if (ifp) { + count++; + if (!vrf_is_backend_netns()) + break; + } + } if (!ifp) { flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE, @@ -617,6 +627,12 @@ static int zebra_ptm_handle_msg_cb(void *arg, void *in_ctxt) __func__, port_str); return -1; } + if (count > 1) { + flog_warn(EC_ZEBRA_UNKNOWN_INTERFACE, + "%s: multiple interface with name %s", + __func__, port_str); + return -1; + } } ptm_lib_find_key_in_msg(in_ctxt, ZEBRA_PTM_CBL_STR, cbl_str); @@ -1364,7 +1380,7 @@ static int _zebra_ptm_bfd_client_deregister(struct zserv *zs) } /* - * The message type will be BFD_DEST_REPLY so we can use only + * The message type will be ZEBRA_BFD_DEST_REPLAY so we can use only * one callback at the `bfdd` side, however the real command * number will be included right after the zebra header. */ diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index d5083d4cbe..57276974c3 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -783,9 +783,7 @@ static void vty_show_mpls_pseudowire_detail_json(struct vty *vty) vty_show_mpls_pseudowire(pw, json_pws); } json_object_object_add(json, "pw", json_pws); - vty_out(vty, "%s\n", - json_object_to_json_string_ext(json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } DEFUN(show_pseudowires_detail, show_pseudowires_detail_cmd, diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 24c51e485f..625c966301 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -39,6 +39,7 @@ #include "nexthop_group_private.h" #include "frr_pthread.h" #include "printfrr.h" +#include "frrscript.h" #include "zebra/zebra_router.h" #include "zebra/connected.h" @@ -57,6 +58,7 @@ #include "zebra/zapi_msg.h" #include "zebra/zebra_dplane.h" #include "zebra/zebra_evpn_mh.h" +#include "zebra/zebra_script.h" DEFINE_MGROUP(ZEBRA, "zebra"); @@ -303,35 +305,41 @@ static void route_entry_attach_ref(struct route_entry *re, { re->nhe = new; re->nhe_id = new->id; + re->nhe_installed_id = 0; zebra_nhg_increment_ref(new); } +/* Replace (if 'new_nhghe') or clear (if that's NULL) an re's nhe. */ int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new_nhghe) { - struct nhg_hash_entry *old; int ret = 0; + struct nhg_hash_entry *old_nhg = NULL; if (new_nhghe == NULL) { - if (re->nhe) - zebra_nhg_decrement_ref(re->nhe); + old_nhg = re->nhe; + + re->nhe_id = 0; + re->nhe_installed_id = 0; re->nhe = NULL; goto done; } if ((re->nhe_id != 0) && re->nhe && (re->nhe != new_nhghe)) { - old = re->nhe; + /* Capture previous nhg, if any */ + old_nhg = re->nhe; route_entry_attach_ref(re, new_nhghe); - - if (old) - zebra_nhg_decrement_ref(old); } else if (!re->nhe) /* This is the first time it's being attached */ route_entry_attach_ref(re, new_nhghe); done: + /* Detach / deref previous nhg */ + if (old_nhg) + zebra_nhg_decrement_ref(old_nhg); + return ret; } @@ -730,10 +738,9 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - "%s(%u):%pRN has Nexthop(%pFX) Type: %s depending on it, evaluating %u:%u", - zvrf_name(zvrf), zvrf_id(zvrf), - rn, p, rnh_type2str(rnh->type), seq, - rnh->seqno); + "%s(%u):%pRN has Nexthop(%pFX) depending on it, evaluating %u:%u", + zvrf_name(zvrf), zvrf_id(zvrf), rn, p, + seq, rnh->seqno); /* * If we have evaluated this node on this pass @@ -755,8 +762,8 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) } rnh->seqno = seq; - zebra_evaluate_rnh(zvrf, family2afi(p->family), 0, - rnh->type, p); + zebra_evaluate_rnh(zvrf, family2afi(p->family), 0, p, + rnh->safi); } rn = rn->parent; @@ -1025,7 +1032,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, struct interface *ifp = if_lookup_by_index( nexthop->ifindex, alternate->vrf_id); - if (ifp && if_is_loopback_or_vrf(ifp)) + if (ifp && if_is_loopback(ifp)) return alternate; } @@ -1033,7 +1040,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, struct interface *ifp = if_lookup_by_index( nexthop->ifindex, current->vrf_id); - if (ifp && if_is_loopback_or_vrf(ifp)) + if (ifp && if_is_loopback(ifp)) return current; } @@ -1256,14 +1263,6 @@ static void rib_process(struct route_node *rn) bool selected_changed = new_selected && CHECK_FLAG(new_selected->status, ROUTE_ENTRY_CHANGED); - /* Update fib according to selection results */ - if (new_fib && old_fib) - rib_process_update_fib(zvrf, rn, old_fib, new_fib); - else if (new_fib) - rib_process_add_fib(zvrf, rn, new_fib); - else if (old_fib) - rib_process_del_fib(zvrf, rn, old_fib); - /* Update SELECTED entry */ if (old_selected != new_selected || selected_changed) { @@ -1291,6 +1290,14 @@ static void rib_process(struct route_node *rn) } } + /* Update fib according to selection results */ + if (new_fib && old_fib) + rib_process_update_fib(zvrf, rn, old_fib, new_fib); + else if (new_fib) + rib_process_add_fib(zvrf, rn, new_fib); + else if (old_fib) + rib_process_del_fib(zvrf, rn, old_fib); + /* Remove all RE entries queued for removal */ RNODE_FOREACH_RE_SAFE (rn, re, next) { if (CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED)) { @@ -3092,7 +3099,8 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) if (re->nhe && re->nhe_id) { assert(re->nhe->id == re->nhe_id); - zebra_nhg_decrement_ref(re->nhe); + + route_entry_update_nhe(re, NULL); } else if (re->nhe && re->nhe->nhg.nexthop) nexthops_free(re->nhe->nhg.nexthop); @@ -3891,14 +3899,16 @@ void rib_update(enum rib_update_event event) { struct rib_update_ctx *ctx; - ctx = rib_update_ctx_init(0, event); + if (thread_is_scheduled(t_rib_update_threads[event])) + return; + ctx = rib_update_ctx_init(0, event); ctx->vrf_all = true; - if (!thread_add_event(zrouter.master, rib_update_handler, ctx, 0, - &t_rib_update_threads[event])) - rib_update_ctx_fini(&ctx); /* Already scheduled */ - else if (IS_ZEBRA_DEBUG_EVENT) + thread_add_event(zrouter.master, rib_update_handler, ctx, 0, + &t_rib_update_threads[event]); + + if (IS_ZEBRA_DEBUG_EVENT) zlog_debug("%s: Scheduled VRF (ALL), event %s", __func__, rib_update_event2str(event)); } @@ -4134,7 +4144,31 @@ static int rib_process_dplane_results(struct thread *thread) continue; } +#ifdef HAVE_SCRIPTING + char *script_name = frrscript_names_get_script_name( + ZEBRA_ON_RIB_PROCESS_HOOK_CALL); + + int ret = 1; + struct frrscript *fs; + + if (script_name) { + fs = frrscript_new(script_name); + if (fs) + ret = frrscript_load( + fs, ZEBRA_ON_RIB_PROCESS_HOOK_CALL, + NULL); + } +#endif /* HAVE_SCRIPTING */ + while (ctx) { + +#ifdef HAVE_SCRIPTING + if (ret == 0) + frrscript_call(fs, + ZEBRA_ON_RIB_PROCESS_HOOK_CALL, + ("ctx", ctx)); +#endif /* HAVE_SCRIPTING */ + switch (dplane_ctx_get_op(ctx)) { case DPLANE_OP_ROUTE_INSTALL: case DPLANE_OP_ROUTE_UPDATE: diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 017a4aae7f..f5faaab71b 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -71,21 +71,18 @@ void zebra_rnh_init(void) } static inline struct route_table *get_rnh_table(vrf_id_t vrfid, afi_t afi, - enum rnh_type type) + safi_t safi) { struct zebra_vrf *zvrf; struct route_table *t = NULL; zvrf = zebra_vrf_lookup_by_id(vrfid); - if (zvrf) - switch (type) { - case RNH_NEXTHOP_TYPE: + if (zvrf) { + if (safi == SAFI_UNICAST) t = zvrf->rnh_table[afi]; - break; - case RNH_IMPORT_CHECK_TYPE: - t = zvrf->import_check_table[afi]; - break; - } + else if (safi == SAFI_MULTICAST) + t = zvrf->rnh_table_multicast[afi]; + } return t; } @@ -93,7 +90,7 @@ static inline struct route_table *get_rnh_table(vrf_id_t vrfid, afi_t afi, static void zebra_rnh_remove_from_routing_table(struct rnh *rnh) { struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id); - struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST]; + struct route_table *table = zvrf->table[rnh->afi][rnh->safi]; struct route_node *rn; rib_dest_t *dest; @@ -117,7 +114,7 @@ static void zebra_rnh_remove_from_routing_table(struct rnh *rnh) static void zebra_rnh_store_in_routing_table(struct rnh *rnh) { struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id); - struct route_table *table = zvrf->table[rnh->afi][SAFI_UNICAST]; + struct route_table *table = zvrf->table[rnh->afi][rnh->safi]; struct route_node *rn; rib_dest_t *dest; @@ -135,27 +132,28 @@ static void zebra_rnh_store_in_routing_table(struct rnh *rnh) route_unlock_node(rn); } -struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, enum rnh_type type, - bool *exists) +struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, bool *exists) { struct route_table *table; struct route_node *rn; struct rnh *rnh = NULL; afi_t afi = family2afi(p->family); + safi_t safi = SAFI_UNICAST; if (IS_ZEBRA_DEBUG_NHT) { struct vrf *vrf = vrf_lookup_by_id(vrfid); - zlog_debug("%s(%u): Add RNH %pFX type %s", VRF_LOGNAME(vrf), - vrfid, p, rnh_type2str(type)); + zlog_debug("%s(%u): Add RNH %pFX for safi: %u", + VRF_LOGNAME(vrf), vrfid, p, safi); } - table = get_rnh_table(vrfid, afi, type); + + table = get_rnh_table(vrfid, afi, safi); if (!table) { struct vrf *vrf = vrf_lookup_by_id(vrfid); flog_warn(EC_ZEBRA_RNH_NO_TABLE, - "%s(%u): Add RNH %pFX type %s - table not found", - VRF_LOGNAME(vrf), vrfid, p, rnh_type2str(type)); + "%s(%u): Add RNH %pFX - table not found", + VRF_LOGNAME(vrf), vrfid, p); *exists = false; return NULL; } @@ -178,9 +176,9 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, enum rnh_type type, rnh->resolved_route.family = p->family; rnh->client_list = list_new(); rnh->vrf_id = vrfid; - rnh->type = type; rnh->seqno = 0; rnh->afi = afi; + rnh->safi = safi; rnh->zebra_pseudowire_list = list_new(); route_lock_node(rn); rn->info = rnh; @@ -195,13 +193,12 @@ struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, enum rnh_type type, return (rn->info); } -struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, - enum rnh_type type) +struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, safi_t safi) { struct route_table *table; struct route_node *rn; - table = get_rnh_table(vrfid, family2afi(PREFIX_FAMILY(p)), type); + table = get_rnh_table(vrfid, family2afi(PREFIX_FAMILY(p)), safi); if (!table) return NULL; @@ -228,7 +225,7 @@ void zebra_free_rnh(struct rnh *rnh) list_delete(&rnh->zebra_pseudowire_list); zvrf = zebra_vrf_lookup_by_id(rnh->vrf_id); - table = zvrf->table[family2afi(rnh->resolved_route.family)][SAFI_UNICAST]; + table = zvrf->table[family2afi(rnh->resolved_route.family)][rnh->safi]; if (table) { struct route_node *rern; @@ -247,7 +244,7 @@ void zebra_free_rnh(struct rnh *rnh) XFREE(MTYPE_RNH, rnh); } -static void zebra_delete_rnh(struct rnh *rnh, enum rnh_type type) +static void zebra_delete_rnh(struct rnh *rnh) { struct route_node *rn; @@ -261,8 +258,8 @@ static void zebra_delete_rnh(struct rnh *rnh, enum rnh_type type) if (IS_ZEBRA_DEBUG_NHT) { struct vrf *vrf = vrf_lookup_by_id(rnh->vrf_id); - zlog_debug("%s(%u): Del RNH %pRN type %s", VRF_LOGNAME(vrf), - rnh->vrf_id, rnh->node, rnh_type2str(type)); + zlog_debug("%s(%u): Del RNH %pRN", VRF_LOGNAME(vrf), + rnh->vrf_id, rnh->node); } zebra_free_rnh(rnh); @@ -279,15 +276,14 @@ static void zebra_delete_rnh(struct rnh *rnh, enum rnh_type type) * and as such it will have a resolved rnh. */ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, - enum rnh_type type, vrf_id_t vrf_id) + vrf_id_t vrf_id) { if (IS_ZEBRA_DEBUG_NHT) { struct vrf *vrf = vrf_lookup_by_id(vrf_id); - zlog_debug("%s(%u): Client %s registers for RNH %pRN type %s", + zlog_debug("%s(%u): Client %s registers for RNH %pRN", VRF_LOGNAME(vrf), vrf_id, - zebra_route_string(client->proto), rnh->node, - rnh_type2str(type)); + zebra_route_string(client->proto), rnh->node); } if (!listnode_lookup(rnh->client_list, client)) listnode_add(rnh->client_list, client); @@ -296,21 +292,20 @@ void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, * We always need to respond with known information, * currently multiple daemons expect this behavior */ - zebra_send_rnh_update(rnh, client, type, vrf_id, 0); + zebra_send_rnh_update(rnh, client, vrf_id, 0); } -void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, - enum rnh_type type) +void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client) { if (IS_ZEBRA_DEBUG_NHT) { struct vrf *vrf = vrf_lookup_by_id(rnh->vrf_id); - zlog_debug("Client %s unregisters for RNH %s(%u)%pRN type %s", + zlog_debug("Client %s unregisters for RNH %s(%u)%pRN", zebra_route_string(client->proto), VRF_LOGNAME(vrf), - vrf->vrf_id, rnh->node, rnh_type2str(type)); + vrf->vrf_id, rnh->node); } listnode_delete(rnh->client_list, client); - zebra_delete_rnh(rnh, type); + zebra_delete_rnh(rnh); } /* XXX move this utility function elsewhere? */ @@ -350,15 +345,15 @@ void zebra_register_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw, return; addr2hostprefix(pw->af, &pw->nexthop, &nh); - rnh = zebra_add_rnh(&nh, vrf_id, RNH_NEXTHOP_TYPE, &exists); + rnh = zebra_add_rnh(&nh, vrf_id, &exists); if (!rnh) return; if (!listnode_lookup(rnh->zebra_pseudowire_list, pw)) { listnode_add(rnh->zebra_pseudowire_list, pw); pw->rnh = rnh; - zebra_evaluate_rnh(zvrf, family2afi(pw->af), 1, - RNH_NEXTHOP_TYPE, &nh); + zebra_evaluate_rnh(zvrf, family2afi(pw->af), 1, &nh, + SAFI_UNICAST); } else *nht_exists = true; } @@ -374,7 +369,7 @@ void zebra_deregister_rnh_pseudowire(vrf_id_t vrf_id, struct zebra_pw *pw) listnode_delete(rnh->zebra_pseudowire_list, pw); pw->rnh = NULL; - zebra_delete_rnh(rnh, RNH_NEXTHOP_TYPE); + zebra_delete_rnh(rnh); } /* Clear the NEXTHOP_FLAG_RNH_FILTERED flags on all nexthops @@ -419,111 +414,6 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf, } /* - * Determine appropriate route (RE entry) resolving a tracked BGP route - * for BGP route for import. - */ -static struct route_entry * -zebra_rnh_resolve_import_entry(struct zebra_vrf *zvrf, afi_t afi, - struct route_node *nrn, struct rnh *rnh, - struct route_node **prn) -{ - struct route_table *route_table; - struct route_node *rn; - struct route_entry *re; - - *prn = NULL; - - route_table = zvrf->table[afi][SAFI_UNICAST]; - if (!route_table) // unexpected - return NULL; - - rn = route_node_match(route_table, &nrn->p); - if (!rn) - return NULL; - - /* Unlock route node - we don't need to lock when walking the tree. */ - route_unlock_node(rn); - - if (CHECK_FLAG(rnh->flags, ZEBRA_NHT_EXACT_MATCH) - && !prefix_same(&nrn->p, &rn->p)) - return NULL; - - if (IS_ZEBRA_DEBUG_NHT_DETAILED) { - zlog_debug("%s: %s(%u):%pRN Resolved Import Entry to %pRN", - __func__, VRF_LOGNAME(zvrf->vrf), rnh->vrf_id, - rnh->node, rn); - } - - /* Identify appropriate route entry. */ - RNODE_FOREACH_RE (rn, re) { - if (!CHECK_FLAG(re->status, ROUTE_ENTRY_REMOVED) - && CHECK_FLAG(re->flags, ZEBRA_FLAG_SELECTED) - && !CHECK_FLAG(re->status, ROUTE_ENTRY_QUEUED) - && (re->type != ZEBRA_ROUTE_BGP)) - break; - } - - if (re) - *prn = rn; - - if (!re && IS_ZEBRA_DEBUG_NHT_DETAILED) - zlog_debug(" Rejected due to removed or is a bgp route"); - - return re; -} - -/* - * See if a tracked route entry for import (by BGP) has undergone any - * change, and if so, notify the client. - */ -static void zebra_rnh_eval_import_check_entry(struct zebra_vrf *zvrf, afi_t afi, - int force, struct route_node *nrn, - struct rnh *rnh, - struct route_node *prn, - struct route_entry *re) -{ - int state_changed = 0; - struct zserv *client; - struct listnode *node; - - zebra_rnh_remove_from_routing_table(rnh); - if (prn) { - prefix_copy(&rnh->resolved_route, &prn->p); - } else { - int family = rnh->resolved_route.family; - - memset(&rnh->resolved_route.family, 0, sizeof(struct prefix)); - rnh->resolved_route.family = family; - } - zebra_rnh_store_in_routing_table(rnh); - - if (re && (rnh->state == NULL)) { - if (CHECK_FLAG(re->status, ROUTE_ENTRY_INSTALLED)) - state_changed = 1; - } else if (!re && (rnh->state != NULL)) - state_changed = 1; - - if (compare_state(re, rnh->state)) { - copy_state(rnh, re, nrn); - state_changed = 1; - } - - if (state_changed || force) { - if (IS_ZEBRA_DEBUG_NHT) - zlog_debug("%s(%u):%pRN: Route import check %s %s", - VRF_LOGNAME(zvrf->vrf), zvrf->vrf->vrf_id, - nrn, rnh->state ? "passed" : "failed", - state_changed ? "(state changed)" : ""); - /* state changed, notify clients */ - for (ALL_LIST_ELEMENTS_RO(rnh->client_list, node, client)) { - zebra_send_rnh_update(rnh, client, - RNH_IMPORT_CHECK_TYPE, - zvrf->vrf->vrf_id, 0); - } - } -} - -/* * Notify clients registered for this nexthop about a change. */ static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi, @@ -580,8 +470,7 @@ static void zebra_rnh_notify_protocol_clients(struct zebra_vrf *zvrf, afi_t afi, zebra_route_string(client->proto)); } - zebra_send_rnh_update(rnh, client, RNH_NEXTHOP_TYPE, - zvrf->vrf->vrf_id, 0); + zebra_send_rnh_update(rnh, client, zvrf->vrf->vrf_id, 0); } if (re) @@ -676,7 +565,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, *prn = NULL; - route_table = zvrf->table[afi][SAFI_UNICAST]; + route_table = zvrf->table[afi][rnh->safi]; if (!route_table) return NULL; @@ -700,10 +589,14 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, * match route to be exact if so specified */ if (is_default_prefix(&rn->p) - && !rnh_resolve_via_default(zvrf, rn->p.family)) { + && (!CHECK_FLAG(rnh->flags, ZEBRA_NHT_RESOLVE_VIA_DEFAULT) + && !rnh_resolve_via_default(zvrf, rn->p.family))) { if (IS_ZEBRA_DEBUG_NHT_DETAILED) zlog_debug( - " Not allowed to resolve through default prefix"); + " Not allowed to resolve through default prefix: rnh->resolve_via_default: %u", + CHECK_FLAG( + rnh->flags, + ZEBRA_NHT_RESOLVE_VIA_DEFAULT)); return NULL; } @@ -823,26 +716,22 @@ static void zebra_rnh_eval_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, /* Evaluate one tracked entry */ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi, - int force, enum rnh_type type, - struct route_node *nrn) + int force, struct route_node *nrn) { struct rnh *rnh; struct route_entry *re; struct route_node *prn; if (IS_ZEBRA_DEBUG_NHT) { - zlog_debug("%s(%u):%pRN: Evaluate RNH, type %s %s", + zlog_debug("%s(%u):%pRN: Evaluate RNH, %s", VRF_LOGNAME(zvrf->vrf), zvrf->vrf->vrf_id, nrn, - rnh_type2str(type), force ? "(force)" : ""); + force ? "(force)" : ""); } rnh = nrn->info; /* Identify route entry (RE) resolving this tracked entry. */ - if (type == RNH_IMPORT_CHECK_TYPE) - re = zebra_rnh_resolve_import_entry(zvrf, afi, nrn, rnh, &prn); - else - re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh, &prn); + re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh, &prn); /* If the entry cannot be resolved and that is also the existing state, * there is nothing further to do. @@ -851,12 +740,7 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi, return; /* Process based on type of entry. */ - if (type == RNH_IMPORT_CHECK_TYPE) - zebra_rnh_eval_import_check_entry(zvrf, afi, force, nrn, rnh, - prn, re); - else - zebra_rnh_eval_nexthop_entry(zvrf, afi, force, nrn, rnh, prn, - re); + zebra_rnh_eval_nexthop_entry(zvrf, afi, force, nrn, rnh, prn, re); } /* @@ -869,7 +753,7 @@ static void zebra_rnh_evaluate_entry(struct zebra_vrf *zvrf, afi_t afi, * covers multiple nexthops we are interested in. */ static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, afi_t afi, - enum rnh_type type, struct route_node *nrn) + struct route_node *nrn) { struct rnh *rnh; struct route_entry *re; @@ -878,12 +762,7 @@ static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, afi_t afi, rnh = nrn->info; /* Identify route entry (RIB) resolving this tracked entry. */ - if (type == RNH_IMPORT_CHECK_TYPE) - re = zebra_rnh_resolve_import_entry(zvrf, afi, nrn, rnh, - &prn); - else - re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh, - &prn); + re = zebra_rnh_resolve_nexthop_entry(zvrf, afi, nrn, rnh, &prn); if (re) UNSET_FLAG(re->status, ROUTE_ENTRY_LABELS_CHANGED); @@ -893,12 +772,12 @@ static void zebra_rnh_clear_nhc_flag(struct zebra_vrf *zvrf, afi_t afi, * of a particular VRF and address-family or a specific prefix. */ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, - enum rnh_type type, struct prefix *p) + struct prefix *p, safi_t safi) { struct route_table *rnh_table; struct route_node *nrn; - rnh_table = get_rnh_table(zvrf->vrf->vrf_id, afi, type); + rnh_table = get_rnh_table(zvrf->vrf->vrf_id, afi, safi); if (!rnh_table) // unexpected return; @@ -906,7 +785,7 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, /* Evaluating a specific entry, make sure it exists. */ nrn = route_node_lookup(rnh_table, p); if (nrn && nrn->info) - zebra_rnh_evaluate_entry(zvrf, afi, force, type, nrn); + zebra_rnh_evaluate_entry(zvrf, afi, force, nrn); if (nrn) route_unlock_node(nrn); @@ -915,26 +794,25 @@ void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, nrn = route_top(rnh_table); while (nrn) { if (nrn->info) - zebra_rnh_evaluate_entry(zvrf, afi, force, type, - nrn); + zebra_rnh_evaluate_entry(zvrf, afi, force, nrn); nrn = route_next(nrn); /* this will also unlock nrn */ } nrn = route_top(rnh_table); while (nrn) { if (nrn->info) - zebra_rnh_clear_nhc_flag(zvrf, afi, type, nrn); + zebra_rnh_clear_nhc_flag(zvrf, afi, nrn); nrn = route_next(nrn); /* this will also unlock nrn */ } } } void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, - enum rnh_type type, struct prefix *p) + struct prefix *p) { struct route_table *table; struct route_node *rn; - table = get_rnh_table(vrfid, afi, type); + table = get_rnh_table(vrfid, afi, SAFI_UNICAST); if (!table) { if (IS_ZEBRA_DEBUG_NHT) zlog_debug("print_rnhs: rnh table not found"); @@ -1271,8 +1149,7 @@ static bool compare_state(struct route_entry *r1, } int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, - enum rnh_type type, vrf_id_t vrf_id, - uint32_t srte_color) + vrf_id_t vrf_id, uint32_t srte_color) { struct stream *s = NULL; struct route_entry *re; @@ -1282,8 +1159,6 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, struct route_node *rn; int ret; uint32_t message = 0; - int cmd = (type == RNH_IMPORT_CHECK_TYPE) ? ZEBRA_IMPORT_CHECK_UPDATE - : ZEBRA_NEXTHOP_UPDATE; rn = rnh->node; re = rnh->state; @@ -1291,13 +1166,14 @@ int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, /* Get output stream. */ s = stream_new(ZEBRA_MAX_PACKET_SIZ); - zclient_create_header(s, cmd, vrf_id); + zclient_create_header(s, ZEBRA_NEXTHOP_UPDATE, vrf_id); /* Message flags. */ if (srte_color) SET_FLAG(message, ZAPI_MESSAGE_SRTE); stream_putl(s, message); + stream_putw(s, rnh->safi); stream_putw(s, rn->p.family); switch (rn->p.family) { case AF_INET: @@ -1444,7 +1320,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty) } static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, - struct zserv *client, enum rnh_type type) + struct zserv *client) { struct route_table *ntable; struct route_node *nrn; @@ -1453,14 +1329,12 @@ static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, if (IS_ZEBRA_DEBUG_NHT) { struct vrf *vrf = vrf_lookup_by_id(vrf_id); - zlog_debug( - "%s(%u): Client %s RNH cleanup for family %s type %s", - VRF_LOGNAME(vrf), vrf_id, - zebra_route_string(client->proto), afi2str(afi), - rnh_type2str(type)); + zlog_debug("%s(%u): Client %s RNH cleanup for family %s", + VRF_LOGNAME(vrf), vrf_id, + zebra_route_string(client->proto), afi2str(afi)); } - ntable = get_rnh_table(vrf_id, afi, type); + ntable = get_rnh_table(vrf_id, afi, SAFI_UNICAST); if (!ntable) { zlog_debug("cleanup_rnh_client: rnh table not found"); return -1; @@ -1471,7 +1345,7 @@ static int zebra_cleanup_rnh_client(vrf_id_t vrf_id, afi_t afi, continue; rnh = nrn->info; - zebra_remove_rnh_client(rnh, client, type); + zebra_remove_rnh_client(rnh, client); } return 1; } @@ -1485,14 +1359,9 @@ static int zebra_client_cleanup_rnh(struct zserv *client) RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id) { zvrf = vrf->info; if (zvrf) { - zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP, client, - RNH_NEXTHOP_TYPE); - zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client, - RNH_NEXTHOP_TYPE); - zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP, client, - RNH_IMPORT_CHECK_TYPE); - zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, client, - RNH_IMPORT_CHECK_TYPE); + zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP, client); + zebra_cleanup_rnh_client(zvrf_id(zvrf), AFI_IP6, + client); } } diff --git a/zebra/zebra_rnh.h b/zebra/zebra_rnh.h index 24ee6d0bd9..27c016ebe6 100644 --- a/zebra/zebra_rnh.h +++ b/zebra/zebra_rnh.h @@ -31,36 +31,22 @@ extern "C" { extern void zebra_rnh_init(void); -static inline const char *rnh_type2str(enum rnh_type type) -{ - switch (type) { - case RNH_NEXTHOP_TYPE: - return "Nexthop"; - case RNH_IMPORT_CHECK_TYPE: - return "Import"; - } - - return "ERROR"; -} - extern struct rnh *zebra_add_rnh(struct prefix *p, vrf_id_t vrfid, - enum rnh_type type, bool *exists); + bool *exists); extern struct rnh *zebra_lookup_rnh(struct prefix *p, vrf_id_t vrfid, - enum rnh_type type); + safi_t safi); extern void zebra_free_rnh(struct rnh *rnh); extern void zebra_add_rnh_client(struct rnh *rnh, struct zserv *client, - enum rnh_type type, vrf_id_t vrfid); + vrf_id_t vrfid); extern int zebra_send_rnh_update(struct rnh *rnh, struct zserv *client, - enum rnh_type type, vrf_id_t vrf_id, - uint32_t srte_color); + vrf_id_t vrf_id, uint32_t srte_color); extern void zebra_register_rnh_pseudowire(vrf_id_t, struct zebra_pw *, bool *); extern void zebra_deregister_rnh_pseudowire(vrf_id_t, struct zebra_pw *); -extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client, - enum rnh_type type); +extern void zebra_remove_rnh_client(struct rnh *rnh, struct zserv *client); extern void zebra_evaluate_rnh(struct zebra_vrf *zvrf, afi_t afi, int force, - enum rnh_type type, struct prefix *p); + struct prefix *p, safi_t safi); extern void zebra_print_rnh_table(vrf_id_t vrfid, afi_t afi, struct vty *vty, - enum rnh_type type, struct prefix *p); + struct prefix *p); extern int rnh_resolve_via_default(struct zebra_vrf *zvrf, int family); diff --git a/zebra/zebra_routemap.c b/zebra/zebra_routemap.c index d07a49fb6e..908c13f3df 100644 --- a/zebra/zebra_routemap.c +++ b/zebra/zebra_routemap.c @@ -319,7 +319,7 @@ static int ip_nht_rm_add(struct zebra_vrf *zvrf, const char *rmap, int rtype, route_map_counter_increment(NHT_RM_MAP(zvrf, afi, rtype)); if (NHT_RM_MAP(zvrf, afi, rtype)) - zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP, 1, NULL, SAFI_UNICAST); return CMD_SUCCESS; } @@ -340,8 +340,7 @@ static int ip_nht_rm_del(struct zebra_vrf *zvrf, const char *rmap, int rtype, zvrf->vrf->vrf_id, rtype); NHT_RM_MAP(zvrf, afi, rtype) = NULL; - zebra_evaluate_rnh(zvrf, AFI_IP, 1, RNH_NEXTHOP_TYPE, - NULL); + zebra_evaluate_rnh(zvrf, AFI_IP, 1, NULL, SAFI_UNICAST); } XFREE(MTYPE_ROUTE_MAP_NAME, NHT_RM_NAME(zvrf, afi, rtype)); } @@ -1589,8 +1588,8 @@ static void zebra_nht_rm_update(const char *rmap) afi_ip = 1; zebra_evaluate_rnh( - zvrf, AFI_IP, 1, - RNH_NEXTHOP_TYPE, NULL); + zvrf, AFI_IP, 1, NULL, + SAFI_UNICAST); } } } @@ -1620,8 +1619,8 @@ static void zebra_nht_rm_update(const char *rmap) afi_ipv6 = 1; zebra_evaluate_rnh( - zvrf, AFI_IP, 1, - RNH_NEXTHOP_TYPE, NULL); + zvrf, AFI_IP, 1, NULL, + SAFI_UNICAST); } } } diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index d930f59866..92a3b9424b 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -30,6 +30,7 @@ #include "zebra_mlag.h" #include "zebra_nhg.h" #include "debug.h" +#include "zebra_script.h" DEFINE_MTYPE_STATIC(ZEBRA, RIB_TABLE_INFO, "RIB table info"); DEFINE_MTYPE_STATIC(ZEBRA, ZEBRA_RT_TABLE, "Zebra VRF table"); @@ -231,6 +232,8 @@ void zebra_router_terminate(void) { struct zebra_router_table *zrt, *tmp; + THREAD_OFF(zrouter.sweeper); + RB_FOREACH_SAFE (zrt, zebra_router_table_head, &zrouter.tables, tmp) zebra_router_free_table(zrt); @@ -255,6 +258,10 @@ void zebra_router_terminate(void) hash_free(zrouter.ipset_entry_hash); hash_clean(zrouter.iptable_hash, zebra_pbr_iptable_free); hash_free(zrouter.iptable_hash); + +#ifdef HAVE_SCRIPTING + zebra_script_destroy(); +#endif } bool zebra_router_notify_on_ack(void) @@ -296,4 +303,8 @@ void zebra_router_init(bool asic_offload, bool notify_on_ack) zrouter.asic_offloaded = asic_offload; zrouter.notify_on_ack = notify_on_ack; + +#ifdef HAVE_SCRIPTING + zebra_script_init(); +#endif } diff --git a/zebra/zebra_router.h b/zebra/zebra_router.h index 408f9cbee5..dd788216c7 100644 --- a/zebra/zebra_router.h +++ b/zebra/zebra_router.h @@ -196,6 +196,7 @@ struct zebra_router { * Time for when we sweep the rib from old routes */ time_t startup_time; + struct thread *sweeper; /* * The hash of nexthop groups associated with this router diff --git a/zebra/zebra_script.c b/zebra/zebra_script.c new file mode 100644 index 0000000000..0e19376abe --- /dev/null +++ b/zebra/zebra_script.c @@ -0,0 +1,420 @@ +/* + * frrscript encoders and decoders for data structures in Zebra + * Copyright (C) 2021 Donald Lee + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include "zebra_script.h" + +#ifdef HAVE_SCRIPTING + +void zebra_script_init(void) +{ + frrscript_names_add_function_name(ZEBRA_ON_RIB_PROCESS_HOOK_CALL); +} + +void zebra_script_destroy(void) +{ + frrscript_names_destroy(); +} + +void lua_pushnh_grp(lua_State *L, const struct nh_grp *nh_grp) +{ + lua_newtable(L); + lua_pushinteger(L, nh_grp->id); + lua_setfield(L, -2, "id"); + lua_pushinteger(L, nh_grp->weight); + lua_setfield(L, -2, "weight"); +} + +void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx) +{ + + lua_newtable(L); + lua_pushinteger(L, dplane_ctx_get_op(ctx)); + lua_setfield(L, -2, "zd_op"); + lua_pushinteger(L, dplane_ctx_get_status(ctx)); + lua_setfield(L, -2, "zd_status"); + lua_pushinteger(L, dplane_ctx_get_provider(ctx)); + lua_setfield(L, -2, "zd_provider"); + lua_pushinteger(L, dplane_ctx_get_vrf(ctx)); + lua_setfield(L, -2, "zd_vrf_id"); + lua_pushinteger(L, dplane_ctx_get_table(ctx)); + lua_setfield(L, -2, "zd_table_id"); + lua_pushstring(L, dplane_ctx_get_ifname(ctx)); + lua_setfield(L, -2, "zd_ifname"); + lua_pushinteger(L, dplane_ctx_get_ifindex(ctx)); + lua_setfield(L, -2, "zd_ifindex"); + + switch (dplane_ctx_get_op(ctx)) { + case DPLANE_OP_ROUTE_INSTALL: + case DPLANE_OP_ROUTE_UPDATE: + case DPLANE_OP_ROUTE_DELETE: + case DPLANE_OP_ROUTE_NOTIFY: + case DPLANE_OP_NH_INSTALL: + case DPLANE_OP_NH_UPDATE: + case DPLANE_OP_NH_DELETE: + /* rinfo */ + lua_newtable(L); + { + lua_pushprefix(L, dplane_ctx_get_dest(ctx)); + lua_setfield(L, -2, "zd_dest"); + const struct prefix *src_pfx = dplane_ctx_get_src(ctx); + + if (src_pfx) { + lua_pushprefix(L, src_pfx); + lua_setfield(L, -2, "zd_src"); + } + lua_pushinteger(L, dplane_ctx_get_afi(ctx)); + lua_setfield(L, -2, "zd_afi"); + lua_pushinteger(L, dplane_ctx_get_safi(ctx)); + lua_setfield(L, -2, "zd_safi"); + lua_pushinteger(L, dplane_ctx_get_type(ctx)); + lua_setfield(L, -2, "zd_type"); + lua_pushinteger(L, dplane_ctx_get_old_type(ctx)); + lua_setfield(L, -2, "zd_old_type"); + lua_pushinteger(L, dplane_ctx_get_tag(ctx)); + lua_setfield(L, -2, "zd_tag"); + lua_pushinteger(L, dplane_ctx_get_old_tag(ctx)); + lua_setfield(L, -2, "zd_old_tag"); + lua_pushinteger(L, dplane_ctx_get_metric(ctx)); + lua_setfield(L, -2, "zd_metric"); + lua_pushinteger(L, dplane_ctx_get_old_metric(ctx)); + lua_setfield(L, -2, "zd_old_metric"); + lua_pushinteger(L, dplane_ctx_get_instance(ctx)); + lua_setfield(L, -2, "zd_instance"); + lua_pushinteger(L, dplane_ctx_get_old_instance(ctx)); + lua_setfield(L, -2, "zd_old_instance"); + lua_pushinteger(L, dplane_ctx_get_distance(ctx)); + lua_setfield(L, -2, "zd_distance"); + lua_pushinteger(L, dplane_ctx_get_old_distance(ctx)); + lua_setfield(L, -2, "zd_old_distance"); + lua_pushinteger(L, dplane_ctx_get_mtu(ctx)); + lua_setfield(L, -2, "zd_mtu"); + lua_pushinteger(L, dplane_ctx_get_nh_mtu(ctx)); + lua_setfield(L, -2, "zd_nexthop_mtu"); + /* nhe */ + lua_newtable(L); + { + lua_pushinteger(L, dplane_ctx_get_nhe_id(ctx)); + lua_setfield(L, -2, "id"); + lua_pushinteger(L, + dplane_ctx_get_old_nhe_id(ctx)); + lua_setfield(L, -2, "old_id"); + lua_pushinteger(L, dplane_ctx_get_nhe_afi(ctx)); + lua_setfield(L, -2, "afi"); + lua_pushinteger(L, + dplane_ctx_get_nhe_vrf_id(ctx)); + lua_setfield(L, -2, "vrf_id"); + lua_pushinteger(L, + dplane_ctx_get_nhe_type(ctx)); + lua_setfield(L, -2, "type"); + lua_pushnexthop_group( + L, dplane_ctx_get_nhe_ng(ctx)); + lua_setfield(L, -2, "ng"); + lua_pushnh_grp(L, + dplane_ctx_get_nhe_nh_grp(ctx)); + lua_setfield(L, -2, "nh_grp"); + lua_pushinteger( + L, + dplane_ctx_get_nhe_nh_grp_count(ctx)); + lua_setfield(L, -2, "nh_grp_count"); + } + lua_setfield(L, -2, "nhe"); + lua_pushinteger(L, dplane_ctx_get_nhg_id(ctx)); + lua_setfield(L, -2, "zd_nhg_id"); + lua_pushnexthop_group(L, dplane_ctx_get_ng(ctx)); + lua_setfield(L, -2, "zd_ng"); + lua_pushnexthop_group(L, dplane_ctx_get_backup_ng(ctx)); + lua_setfield(L, -2, "backup_ng"); + lua_pushnexthop_group(L, dplane_ctx_get_old_ng(ctx)); + lua_setfield(L, -2, "zd_old_ng"); + lua_pushnexthop_group( + L, dplane_ctx_get_old_backup_ng(ctx)); + lua_setfield(L, -2, "old_backup_ng"); + } + lua_setfield(L, -2, "rinfo"); + break; + case DPLANE_OP_LSP_INSTALL: + case DPLANE_OP_LSP_UPDATE: + case DPLANE_OP_LSP_DELETE: + case DPLANE_OP_LSP_NOTIFY: + lua_pushinteger(L, (int)dplane_ctx_get_in_label(ctx)); + lua_setfield(L, -2, "label"); + break; + case DPLANE_OP_PW_INSTALL: + case DPLANE_OP_PW_UNINSTALL: + /* pw*/ + lua_newtable(L); + { + lua_pushinteger(L, dplane_ctx_get_pw_type(ctx)); + lua_setfield(L, -2, "type"); + lua_pushinteger(L, dplane_ctx_get_pw_af(ctx)); + lua_setfield(L, -2, "af"); + lua_pushinteger(L, dplane_ctx_get_pw_status(ctx)); + lua_setfield(L, -2, "status"); + lua_pushinteger(L, dplane_ctx_get_pw_flags(ctx)); + lua_setfield(L, -2, "flags"); + lua_pushinteger(L, dplane_ctx_get_pw_local_label(ctx)); + lua_setfield(L, -2, "local_label"); + lua_pushinteger(L, dplane_ctx_get_pw_remote_label(ctx)); + lua_setfield(L, -2, "remote_label"); + } + lua_setfield(L, -2, "pw"); + break; + case DPLANE_OP_SYS_ROUTE_ADD: + case DPLANE_OP_SYS_ROUTE_DELETE: + /* nothing to encode */ + break; + case DPLANE_OP_MAC_INSTALL: + case DPLANE_OP_MAC_DELETE: + /* macinfo */ + lua_newtable(L); + { + lua_pushinteger(L, dplane_ctx_mac_get_vlan(ctx)); + lua_setfield(L, -2, "vid"); + lua_pushinteger(L, dplane_ctx_mac_get_br_ifindex(ctx)); + lua_setfield(L, -2, "br_ifindex"); + lua_pushethaddr(L, dplane_ctx_mac_get_addr(ctx)); + lua_setfield(L, -2, "mac"); + lua_pushinaddr(L, dplane_ctx_mac_get_vtep_ip(ctx)); + lua_setfield(L, -2, "vtep_ip"); + lua_pushinteger(L, dplane_ctx_mac_is_sticky(ctx)); + lua_setfield(L, -2, "is_sticky"); + lua_pushinteger(L, dplane_ctx_mac_get_nhg_id(ctx)); + lua_setfield(L, -2, "nhg_id"); + lua_pushinteger(L, + dplane_ctx_mac_get_update_flags(ctx)); + lua_setfield(L, -2, "update_flags"); + } + lua_setfield(L, -2, "macinfo"); + break; + case DPLANE_OP_RULE_ADD: + case DPLANE_OP_RULE_DELETE: + case DPLANE_OP_RULE_UPDATE: + /* rule */ + lua_newtable(L); + { + lua_pushinteger(L, dplane_ctx_rule_get_sock(ctx)); + lua_setfield(L, -2, "sock"); + lua_pushinteger(L, dplane_ctx_rule_get_unique(ctx)); + lua_setfield(L, -2, "unique"); + lua_pushinteger(L, dplane_ctx_rule_get_seq(ctx)); + lua_setfield(L, -2, "seq"); + lua_pushstring(L, dplane_ctx_rule_get_ifname(ctx)); + lua_setfield(L, -2, "ifname"); + lua_pushinteger(L, dplane_ctx_rule_get_priority(ctx)); + lua_setfield(L, -2, "priority"); + lua_pushinteger(L, + dplane_ctx_rule_get_old_priority(ctx)); + lua_setfield(L, -2, "old_priority"); + lua_pushinteger(L, dplane_ctx_rule_get_table(ctx)); + lua_setfield(L, -2, "table"); + lua_pushinteger(L, dplane_ctx_rule_get_old_table(ctx)); + lua_setfield(L, -2, "old_table"); + lua_pushinteger(L, dplane_ctx_rule_get_filter_bm(ctx)); + lua_setfield(L, -2, "filter_bm"); + lua_pushinteger(L, + dplane_ctx_rule_get_old_filter_bm(ctx)); + lua_setfield(L, -2, "old_filter_bm"); + lua_pushinteger(L, dplane_ctx_rule_get_fwmark(ctx)); + lua_setfield(L, -2, "fwmark"); + lua_pushinteger(L, dplane_ctx_rule_get_old_fwmark(ctx)); + lua_setfield(L, -2, "old_fwmark"); + lua_pushinteger(L, dplane_ctx_rule_get_dsfield(ctx)); + lua_setfield(L, -2, "dsfield"); + lua_pushinteger(L, + dplane_ctx_rule_get_old_dsfield(ctx)); + lua_setfield(L, -2, "old_dsfield"); + lua_pushinteger(L, dplane_ctx_rule_get_ipproto(ctx)); + lua_setfield(L, -2, "ip_proto"); + lua_pushinteger(L, + dplane_ctx_rule_get_old_ipproto(ctx)); + lua_setfield(L, -2, "old_ip_proto"); + lua_pushprefix(L, dplane_ctx_rule_get_src_ip(ctx)); + lua_setfield(L, -2, "src_ip"); + lua_pushprefix(L, dplane_ctx_rule_get_old_src_ip(ctx)); + lua_setfield(L, -2, "old_src_ip"); + lua_pushprefix(L, dplane_ctx_rule_get_dst_ip(ctx)); + lua_setfield(L, -2, "dst_ip"); + lua_pushprefix(L, dplane_ctx_rule_get_old_dst_ip(ctx)); + lua_setfield(L, -2, "old_dst_ip"); + } + lua_setfield(L, -2, "rule"); + break; + case DPLANE_OP_IPTABLE_ADD: + case DPLANE_OP_IPTABLE_DELETE: { + struct zebra_pbr_iptable iptable; + + dplane_ctx_get_pbr_iptable(ctx, &iptable); + /* iptable */ + lua_newtable(L); + { + lua_pushinteger(L, iptable.sock); + lua_setfield(L, -2, "sock"); + lua_pushinteger(L, iptable.vrf_id); + lua_setfield(L, -2, "vrf_id"); + lua_pushinteger(L, iptable.unique); + lua_setfield(L, -2, "unique"); + lua_pushinteger(L, iptable.type); + lua_setfield(L, -2, "type"); + lua_pushinteger(L, iptable.filter_bm); + lua_setfield(L, -2, "filter_bm"); + lua_pushinteger(L, iptable.fwmark); + lua_setfield(L, -2, "fwmark"); + lua_pushinteger(L, iptable.action); + lua_setfield(L, -2, "action"); + lua_pushinteger(L, iptable.pkt_len_min); + lua_setfield(L, -2, "pkt_len_min"); + lua_pushinteger(L, iptable.pkt_len_max); + lua_setfield(L, -2, "pkt_len_max"); + lua_pushinteger(L, iptable.tcp_flags); + lua_setfield(L, -2, "tcp_flags"); + lua_pushinteger(L, iptable.dscp_value); + lua_setfield(L, -2, "dscp_value"); + lua_pushinteger(L, iptable.fragment); + lua_setfield(L, -2, "fragment"); + lua_pushinteger(L, iptable.protocol); + lua_setfield(L, -2, "protocol"); + lua_pushinteger(L, iptable.nb_interface); + lua_setfield(L, -2, "nb_interface"); + lua_pushinteger(L, iptable.flow_label); + lua_setfield(L, -2, "flow_label"); + lua_pushinteger(L, iptable.family); + lua_setfield(L, -2, "family"); + lua_pushstring(L, iptable.ipset_name); + lua_setfield(L, -2, "ipset_name"); + } + lua_setfield(L, -2, "iptable"); + break; + } + case DPLANE_OP_IPSET_ADD: + case DPLANE_OP_IPSET_DELETE: + case DPLANE_OP_IPSET_ENTRY_ADD: + case DPLANE_OP_IPSET_ENTRY_DELETE: { + struct zebra_pbr_ipset ipset; + + dplane_ctx_get_pbr_ipset(ctx, &ipset); + /* ipset */ + lua_newtable(L); + { + lua_pushinteger(L, ipset.sock); + lua_setfield(L, -2, "sock"); + lua_pushinteger(L, ipset.vrf_id); + lua_setfield(L, -2, "vrf_id"); + lua_pushinteger(L, ipset.unique); + lua_setfield(L, -2, "unique"); + lua_pushinteger(L, ipset.type); + lua_setfield(L, -2, "type"); + lua_pushinteger(L, ipset.family); + lua_setfield(L, -2, "family"); + lua_pushstring(L, ipset.ipset_name); + lua_setfield(L, -2, "ipset_name"); + } + lua_setfield(L, -2, "ipset"); + break; + } + case DPLANE_OP_ADDR_INSTALL: + case DPLANE_OP_ADDR_UNINSTALL: + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: + break; + case DPLANE_OP_NEIGH_INSTALL: + case DPLANE_OP_NEIGH_UPDATE: + case DPLANE_OP_NEIGH_DELETE: + case DPLANE_OP_NEIGH_DISCOVER: + case DPLANE_OP_NEIGH_IP_INSTALL: + case DPLANE_OP_NEIGH_IP_DELETE: + /* neigh */ + lua_newtable(L); + { + lua_pushipaddr(L, dplane_ctx_neigh_get_ipaddr(ctx)); + lua_setfield(L, -2, "ip_addr"); + /* link */ + lua_newtable(L); + { + lua_pushethaddr(L, + dplane_ctx_neigh_get_mac(ctx)); + lua_setfield(L, -2, "mac"); + lua_pushipaddr( + L, dplane_ctx_neigh_get_link_ip(ctx)); + lua_setfield(L, -2, "ip_addr"); + } + lua_setfield(L, -2, "link"); + lua_pushinteger(L, dplane_ctx_neigh_get_flags(ctx)); + lua_setfield(L, -2, "flags"); + lua_pushinteger(L, dplane_ctx_neigh_get_state(ctx)); + lua_setfield(L, -2, "state"); + lua_pushinteger(L, + dplane_ctx_neigh_get_update_flags(ctx)); + lua_setfield(L, -2, "update_flags"); + } + lua_setfield(L, -2, "neigh"); + break; + case DPLANE_OP_VTEP_ADD: + case DPLANE_OP_VTEP_DELETE: + break; + case DPLANE_OP_BR_PORT_UPDATE: + /* br_port */ + lua_newtable(L); + { + lua_pushinteger( + L, dplane_ctx_get_br_port_sph_filter_cnt(ctx)); + lua_setfield(L, -2, "sph_filter_cnt"); + lua_pushinteger(L, dplane_ctx_get_br_port_flags(ctx)); + lua_setfield(L, -2, "flags"); + lua_pushinteger( + L, dplane_ctx_get_br_port_backup_nhg_id(ctx)); + lua_setfield(L, -2, "backup_nhg_id"); + } + lua_setfield(L, -2, "br_port"); + break; + case DPLANE_OP_NEIGH_TABLE_UPDATE: + /* neightable */ + lua_newtable(L); + { + lua_pushinteger(L, + dplane_ctx_neightable_get_family(ctx)); + lua_setfield(L, -2, "family"); + lua_pushinteger( + L, dplane_ctx_neightable_get_app_probes(ctx)); + lua_setfield(L, -2, "app_probes"); + lua_pushinteger( + L, dplane_ctx_neightable_get_mcast_probes(ctx)); + lua_setfield(L, -2, "ucast_probes"); + lua_pushinteger( + L, dplane_ctx_neightable_get_ucast_probes(ctx)); + lua_setfield(L, -2, "mcast_probes"); + } + lua_setfield(L, -2, "neightable"); + break; + case DPLANE_OP_GRE_SET: + /* gre */ + lua_newtable(L); + { + lua_pushinteger(L, + dplane_ctx_gre_get_link_ifindex(ctx)); + lua_setfield(L, -2, "link_ifindex"); + lua_pushinteger(L, dplane_ctx_gre_get_mtu(ctx)); + lua_setfield(L, -2, "mtu"); + } + lua_setfield(L, -2, "gre"); + case DPLANE_OP_NONE: + break; + } /* Dispatch by op code */ +} + +#endif /* HAVE_SCRIPTING */ diff --git a/zebra/zebra_script.h b/zebra/zebra_script.h new file mode 100644 index 0000000000..5eb59753c6 --- /dev/null +++ b/zebra/zebra_script.h @@ -0,0 +1,41 @@ +/* + * frrscript encoders and decoders for data structures in Zebra + * Copyright (C) 2021 Donald Lee + * + * This program 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 2 of the License, or (at your option) + * any later version. + * + * This program 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 program; see the file COPYING; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef _ZEBRA_SCRIPT_H +#define _ZEBRA_SCRIPT_H + +#include "zebra.h" +#include "zebra/zebra_dplane.h" +#include "zebra/zebra_pbr.h" + +#ifdef HAVE_SCRIPTING + +#include "frrlua.h" + +void zebra_script_init(void); + +void zebra_script_destroy(void); + +void lua_pushnh_grp(lua_State *L, const struct nh_grp *nh_grp); + +void lua_pushzebra_dplane_ctx(lua_State *L, const struct zebra_dplane_ctx *ctx); + +#endif /* HAVE_SCRIPTING */ + +#endif /* _ZEBRA_SCRIPT_H */ diff --git a/zebra/zebra_srte.c b/zebra/zebra_srte.c index ba3727371c..7933ef66b1 100644 --- a/zebra/zebra_srte.c +++ b/zebra/zebra_srte.c @@ -116,6 +116,7 @@ static int zebra_sr_policy_notify_update_client(struct zebra_sr_policy *policy, SET_FLAG(message, ZAPI_MESSAGE_SRTE); stream_putl(s, message); + stream_putw(s, SAFI_UNICAST); switch (policy->endpoint.ipa_type) { case IPADDR_V4: stream_putw(s, AF_INET); @@ -196,7 +197,7 @@ static void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy) exit(1); } - rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), RNH_NEXTHOP_TYPE); + rnh = zebra_lookup_rnh(&p, zvrf_id(zvrf), SAFI_UNICAST); if (!rnh) return; @@ -205,8 +206,8 @@ static void zebra_sr_policy_notify_update(struct zebra_sr_policy *policy) zebra_sr_policy_notify_update_client(policy, client); else /* Fallback to the IGP shortest path. */ - zebra_send_rnh_update(rnh, client, RNH_NEXTHOP_TYPE, - zvrf_id(zvrf), policy->color); + zebra_send_rnh_update(rnh, client, zvrf_id(zvrf), + policy->color); } } diff --git a/zebra/zebra_srv6_vty.c b/zebra/zebra_srv6_vty.c index cb1e6c4228..ebe0fffcb2 100644 --- a/zebra/zebra_srv6_vty.c +++ b/zebra/zebra_srv6_vty.c @@ -108,9 +108,7 @@ DEFUN (show_srv6_locator, } - vty_out(vty, "%s\n", json_object_to_json_string_ext(json, - JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { vty_out(vty, "Locator:\n"); vty_out(vty, "Name ID Prefix Status\n"); @@ -147,10 +145,16 @@ DEFUN (show_srv6_locator_detail, struct listnode *node; char str[256]; const char *locator_name = argv[4]->arg; + json_object *json_locator = NULL; if (uj) { - vty_out(vty, "JSON format isn't supported\n"); - return CMD_WARNING; + locator = zebra_srv6_locator_lookup(locator_name); + if (!locator) + return CMD_WARNING; + + json_locator = srv6_locator_detailed_json(locator); + vty_json(vty, json_locator); + return CMD_SUCCESS; } for (ALL_LIST_ELEMENTS_RO(srv6->locators, node, locator)) { diff --git a/zebra/zebra_vrf.c b/zebra/zebra_vrf.c index e162347726..1cc7e8932b 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -20,6 +20,9 @@ */ #include <zebra.h> +/* for basename */ +#include <libgen.h> + #include "log.h" #include "linklist.h" #include "command.h" @@ -158,7 +161,7 @@ static int zebra_vrf_enable(struct vrf *vrf) table = route_table_init(); table->cleanup = zebra_rnhtable_node_cleanup; - zvrf->import_check_table[afi] = table; + zvrf->rnh_table_multicast[afi] = table; } /* Kick off any VxLAN-EVPN processing. */ @@ -181,8 +184,6 @@ static int zebra_vrf_disable(struct vrf *vrf) zlog_debug("VRF %s id %u is now inactive", zvrf_name(zvrf), zvrf_id(zvrf)); - table_manager_disable(zvrf); - /* Stop any VxLAN-EVPN processing. */ zebra_vxlan_vrf_disable(zvrf); @@ -203,8 +204,8 @@ static int zebra_vrf_disable(struct vrf *vrf) for (afi = AFI_IP; afi <= AFI_IP6; afi++) { route_table_finish(zvrf->rnh_table[afi]); zvrf->rnh_table[afi] = NULL; - route_table_finish(zvrf->import_check_table[afi]); - zvrf->import_check_table[afi] = NULL; + route_table_finish(zvrf->rnh_table_multicast[afi]); + zvrf->rnh_table_multicast[afi] = NULL; for (safi = SAFI_UNICAST; safi <= SAFI_MULTICAST; safi++) rib_close_table(zvrf->table[afi][safi]); @@ -271,6 +272,8 @@ static int zebra_vrf_delete(struct vrf *vrf) zlog_debug("VRF %s id %u deleted", zvrf_name(zvrf), zvrf_id(zvrf)); + table_manager_disable(zvrf); + /* clean-up work queues */ for (i = 0; i < MQ_SIZE; i++) { struct listnode *lnode, *nnode; @@ -305,8 +308,8 @@ static int zebra_vrf_delete(struct vrf *vrf) if (zvrf->rnh_table[afi]) route_table_finish(zvrf->rnh_table[afi]); - if (zvrf->import_check_table[afi]) - route_table_finish(zvrf->import_check_table[afi]); + if (zvrf->rnh_table_multicast[afi]) + route_table_finish(zvrf->rnh_table[afi]); } otable = otable_pop(&zvrf->other_tables); @@ -565,10 +568,8 @@ DEFPY (vrf_netns, return CMD_WARNING_CONFIG_FAILED; frr_with_privs(&zserv_privs) { - ret = vrf_netns_handler_create(vty, vrf, pathname, - NS_UNKNOWN, - NS_UNKNOWN, - NS_UNKNOWN); + ret = zebra_vrf_netns_handler_create( + vty, vrf, pathname, NS_UNKNOWN, NS_UNKNOWN, NS_UNKNOWN); } return ret; @@ -607,12 +608,105 @@ DEFUN (no_vrf_netns, return CMD_SUCCESS; } +/* if ns_id is different and not VRF_UNKNOWN, + * then update vrf identifier, and enable VRF + */ +static void vrf_update_vrf_id(ns_id_t ns_id, void *opaqueptr) +{ + ns_id_t vrf_id = (vrf_id_t)ns_id; + vrf_id_t old_vrf_id; + struct vrf *vrf = (struct vrf *)opaqueptr; + + if (!vrf) + return; + old_vrf_id = vrf->vrf_id; + if (vrf_id == vrf->vrf_id) + return; + if (vrf->vrf_id != VRF_UNKNOWN) + RB_REMOVE(vrf_id_head, &vrfs_by_id, vrf); + vrf->vrf_id = vrf_id; + RB_INSERT(vrf_id_head, &vrfs_by_id, vrf); + if (old_vrf_id == VRF_UNKNOWN) + vrf_enable(vrf); +} + +int zebra_vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, + char *pathname, ns_id_t ns_id, + ns_id_t internal_ns_id, + ns_id_t rel_def_ns_id) +{ + struct ns *ns = NULL; + + if (!vrf) + return CMD_WARNING_CONFIG_FAILED; + if (vrf->vrf_id != VRF_UNKNOWN && vrf->ns_ctxt == NULL) { + if (vty) + vty_out(vty, + "VRF %u is already configured with VRF %s\n", + vrf->vrf_id, vrf->name); + else + zlog_info("VRF %u is already configured with VRF %s", + vrf->vrf_id, vrf->name); + return CMD_WARNING_CONFIG_FAILED; + } + if (vrf->ns_ctxt != NULL) { + ns = (struct ns *)vrf->ns_ctxt; + if (!strcmp(ns->name, pathname)) { + if (vty) + vty_out(vty, + "VRF %u already configured with NETNS %s\n", + vrf->vrf_id, ns->name); + else + zlog_info( + "VRF %u already configured with NETNS %s", + vrf->vrf_id, ns->name); + return CMD_WARNING_CONFIG_FAILED; + } + } + ns = ns_lookup_name(pathname); + if (ns && ns->vrf_ctxt) { + struct vrf *vrf2 = (struct vrf *)ns->vrf_ctxt; + + if (vrf2 == vrf) + return CMD_SUCCESS; + if (vty) + vty_out(vty, + "NS %s is already configured with VRF %u(%s)\n", + ns->name, vrf2->vrf_id, vrf2->name); + else + zlog_info("NS %s is already configured with VRF %u(%s)", + ns->name, vrf2->vrf_id, vrf2->name); + return CMD_WARNING_CONFIG_FAILED; + } + ns = ns_get_created(ns, pathname, ns_id); + ns->internal_ns_id = internal_ns_id; + ns->relative_default_ns = rel_def_ns_id; + ns->vrf_ctxt = (void *)vrf; + vrf->ns_ctxt = (void *)ns; + /* update VRF netns NAME */ + strlcpy(vrf->data.l.netns_name, basename(pathname), NS_NAMSIZ); + + if (!ns_enable(ns, vrf_update_vrf_id)) { + if (vty) + vty_out(vty, "Can not associate NS %u with NETNS %s\n", + ns->ns_id, ns->name); + else + zlog_info("Can not associate NS %u with NETNS %s", + ns->ns_id, ns->name); + return CMD_WARNING_CONFIG_FAILED; + } + + return CMD_SUCCESS; +} + /* Zebra VRF initialization. */ void zebra_vrf_init(void) { vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable, zebra_vrf_delete, zebra_vrf_update); + hook_register(zserv_client_close, release_daemon_table_chunks); + vrf_cmd_init(vrf_config_write); if (vrf_is_backend_netns() && ns_have_netns()) { diff --git a/zebra/zebra_vrf.h b/zebra/zebra_vrf.h index 27342908c4..a24a008b76 100644 --- a/zebra/zebra_vrf.h +++ b/zebra/zebra_vrf.h @@ -78,9 +78,7 @@ struct zebra_vrf { /* Recursive Nexthop table */ struct route_table *rnh_table[AFI_MAX]; - - /* Import check table (used mostly by BGP */ - struct route_table *import_check_table[AFI_MAX]; + struct route_table *rnh_table_multicast[AFI_MAX]; struct otable_head other_tables; @@ -183,8 +181,8 @@ struct zebra_vrf { struct rtadv rtadv; #endif /* HAVE_RTADV */ - int zebra_rnh_ip_default_route; - int zebra_rnh_ipv6_default_route; + bool zebra_rnh_ip_default_route; + bool zebra_rnh_ipv6_default_route; }; #define PROTO_RM_NAME(zvrf, afi, rtype) zvrf->proto_rm[afi][rtype].name #define NHT_RM_NAME(zvrf, afi, rtype) zvrf->nht_rm[afi][rtype].name @@ -262,6 +260,14 @@ extern struct zebra_vrf *zebra_vrf_lookup_by_name(const char *); extern struct zebra_vrf *zebra_vrf_alloc(struct vrf *vrf); extern struct route_table *zebra_vrf_table(afi_t, safi_t, vrf_id_t); +/* + * API to associate a VRF with a NETNS. + * Called either from vty or through discovery. + */ +extern int zebra_vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, + char *pathname, ns_id_t ext_ns_id, + ns_id_t ns_id, ns_id_t rel_def_ns_id); + extern void zebra_vrf_init(void); extern void zebra_rtable_node_cleanup(struct route_table *table, diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index c6b3eb48a0..04f2e91e69 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -60,6 +60,7 @@ #include "zebra/zebra_nb.h" #include "zebra/kernel_netlink.h" #include "zebra/table_manager.h" +#include "zebra/zebra_script.h" extern int allow_delete; @@ -75,7 +76,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, const struct prefix *longer_prefix_p, bool supernets_only, int type, unsigned short ospf_instance_id, uint32_t tableid, - struct route_show_ctx *ctx); + bool show_ng, struct route_show_ctx *ctx); static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast, bool use_fib, bool show_ng); static void vty_show_ip_route_summary(struct vty *vty, @@ -157,7 +158,8 @@ DEFUN (show_ip_rpf, }; return do_show_ip_route(vty, VRF_DEFAULT_NAME, AFI_IP, SAFI_MULTICAST, - false, uj, 0, NULL, false, 0, 0, 0, &ctx); + false, uj, 0, NULL, false, 0, 0, 0, false, + &ctx); } DEFUN (show_ip_rpf_addr, @@ -449,6 +451,8 @@ static void zebra_show_ip_route_opaque(struct vty *vty, struct route_entry *re, bzo.community); json_object_string_add(json, "largeCommunities", bzo.lcommunity); + json_object_string_add(json, "selectionReason", + bzo.selection_reason); } else { vty_out(vty, " AS-Path : %s\n", bzo.aspath); @@ -459,6 +463,9 @@ static void zebra_show_ip_route_opaque(struct vty *vty, struct route_entry *re, if (bzo.lcommunity[0] != '\0') vty_out(vty, " Large-Communities: %s\n", bzo.lcommunity); + + vty_out(vty, " Selection reason : %s\n", + bzo.selection_reason); } } default: @@ -534,8 +541,14 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, vty_out(vty, " Last update %s ago\n", buf); - if (show_ng) + if (show_ng) { vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); + if (re->nhe_installed_id != 0 + && re->nhe_id != re->nhe_installed_id) + vty_out(vty, + " Installed Nexthop Group ID: %u\n", + re->nhe_installed_id); + } for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { /* Use helper to format each nexthop */ @@ -703,10 +716,8 @@ static void show_nexthop_json_helper(json_object *json_nexthop, switch (nexthop->type) { case NEXTHOP_TYPE_IPV4: case NEXTHOP_TYPE_IPV4_IFINDEX: - json_object_string_add( - json_nexthop, "ip", - inet_ntop(AF_INET, &nexthop->gate.ipv4, - buf, sizeof(buf))); + json_object_string_addf(json_nexthop, "ip", "%pI4", + &nexthop->gate.ipv4); json_object_string_add(json_nexthop, "afi", "ipv4"); @@ -723,10 +734,8 @@ static void show_nexthop_json_helper(json_object *json_nexthop, break; case NEXTHOP_TYPE_IPV6: case NEXTHOP_TYPE_IPV6_IFINDEX: - json_object_string_add( - json_nexthop, "ip", - inet_ntop(AF_INET6, &nexthop->gate.ipv6, - buf, sizeof(buf))); + json_object_string_addf(json_nexthop, "ip", "%pI6", + &nexthop->gate.ipv6); json_object_string_add(json_nexthop, "afi", "ipv6"); @@ -776,6 +785,13 @@ static void show_nexthop_json_helper(json_object *json_nexthop, break; } + /* This nexthop is a resolver for the parent nexthop. + * Set resolver flag for better clarity and delimiter + * in flat list of nexthops in json. + */ + if (nexthop->rparent) + json_object_boolean_true_add(json_nexthop, "resolver"); + if (nexthop->vrf_id != re->vrf_id) json_object_string_add(json_nexthop, "vrf", vrf_id_to_name(nexthop->vrf_id)); @@ -880,7 +896,7 @@ static void show_nexthop_json_helper(json_object *json_nexthop, static void vty_show_ip_route(struct vty *vty, struct route_node *rn, struct route_entry *re, json_object *json, - bool is_fib) + bool is_fib, bool show_ng) { const struct nexthop *nexthop; int len = 0; @@ -968,6 +984,11 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, &(re->nhe->nhg))); json_object_int_add(json_route, "nexthopGroupId", re->nhe_id); + if (re->nhe_installed_id != 0) + json_object_int_add(json_route, + "installedNexthopGroupId", + re->nhe_installed_id); + json_object_string_add(json_route, "uptime", up_str); for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { @@ -1041,6 +1062,9 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, len += vty_out(vty, " [%u/%u]", re->distance, re->metric); + if (show_ng) + len += vty_out(vty, " (%u)", re->nhe_id); + /* Nexthop information. */ for (ALL_NEXTHOPS_PTR(nhg, nexthop)) { if (first_p) { @@ -1113,16 +1137,12 @@ static void vty_show_ip_route_detail_json(struct vty *vty, */ if (use_fib && re != dest->selected_fib) continue; - vty_show_ip_route(vty, rn, re, json_prefix, use_fib); + vty_show_ip_route(vty, rn, re, json_prefix, use_fib, false); } prefix2str(&rn->p, buf, sizeof(buf)); json_object_object_add(json, buf, json_prefix); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY - | JSON_C_TO_STRING_NOSLASHESCAPE)); - json_object_free(json); + vty_json(vty, json); } static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, @@ -1131,7 +1151,8 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, const struct prefix *longer_prefix_p, bool supernets_only, int type, unsigned short ospf_instance_id, bool use_json, - uint32_t tableid, struct route_show_ctx *ctx) + uint32_t tableid, bool show_ng, + struct route_show_ctx *ctx) { struct route_node *rn; struct route_entry *re; @@ -1222,7 +1243,8 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, first = 0; } - vty_show_ip_route(vty, rn, re, json_prefix, use_fib); + vty_show_ip_route(vty, rn, re, json_prefix, use_fib, + show_ng); } if (json_prefix) { @@ -1232,14 +1254,8 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, } } - if (use_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, - JSON_C_TO_STRING_PRETTY - | JSON_C_TO_STRING_NOSLASHESCAPE)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, @@ -1247,7 +1263,7 @@ static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, - unsigned short ospf_instance_id, + unsigned short ospf_instance_id, bool show_ng, struct route_show_ctx *ctx) { struct zebra_router_table *zrt; @@ -1266,7 +1282,7 @@ static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, do_show_ip_route(vty, zvrf_name(zvrf), afi, SAFI_UNICAST, use_fib, use_json, tag, longer_prefix_p, supernets_only, type, ospf_instance_id, - zrt->tableid, ctx); + zrt->tableid, show_ng, ctx); } } @@ -1276,7 +1292,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, const struct prefix *longer_prefix_p, bool supernets_only, int type, unsigned short ospf_instance_id, uint32_t tableid, - struct route_show_ctx *ctx) + bool show_ng, struct route_show_ctx *ctx) { struct route_table *table; struct zebra_vrf *zvrf = NULL; @@ -1309,7 +1325,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, do_show_route_helper(vty, zvrf, table, afi, use_fib, tag, longer_prefix_p, supernets_only, type, - ospf_instance_id, use_json, tableid, ctx); + ospf_instance_id, use_json, tableid, show_ng, ctx); return CMD_SUCCESS; } @@ -1332,12 +1348,6 @@ DEFPY (show_ip_nht, afi_t afi = ipv4 ? AFI_IP : AFI_IP6; vrf_id_t vrf_id = VRF_DEFAULT; struct prefix prefix, *p = NULL; - enum rnh_type rtype; - - if (strcmp(type, "nht") == 0) - rtype = RNH_NEXTHOP_TYPE; - else - rtype = RNH_IMPORT_CHECK_TYPE; if (vrf_all) { struct vrf *vrf; @@ -1347,7 +1357,7 @@ DEFPY (show_ip_nht, if ((zvrf = vrf->info) != NULL) { vty_out(vty, "\nVRF %s:\n", zvrf_name(zvrf)); zebra_print_rnh_table(zvrf_id(zvrf), afi, vty, - rtype, NULL); + NULL); } return CMD_SUCCESS; } @@ -1361,7 +1371,7 @@ DEFPY (show_ip_nht, return CMD_WARNING; } - zebra_print_rnh_table(vrf_id, afi, vty, rtype, p); + zebra_print_rnh_table(vrf_id, afi, vty, p); return CMD_SUCCESS; } @@ -1380,9 +1390,9 @@ DEFUN (ip_nht_default_route, if (zvrf->zebra_rnh_ip_default_route) return CMD_SUCCESS; - zvrf->zebra_rnh_ip_default_route = 1; + zvrf->zebra_rnh_ip_default_route = true; - zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL); + zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); return CMD_SUCCESS; } @@ -1719,8 +1729,8 @@ DEFUN (no_ip_nht_default_route, if (!zvrf->zebra_rnh_ip_default_route) return CMD_SUCCESS; - zvrf->zebra_rnh_ip_default_route = 0; - zebra_evaluate_rnh(zvrf, AFI_IP, 0, RNH_NEXTHOP_TYPE, NULL); + zvrf->zebra_rnh_ip_default_route = false; + zebra_evaluate_rnh(zvrf, AFI_IP, 0, NULL, SAFI_UNICAST); return CMD_SUCCESS; } @@ -1739,8 +1749,8 @@ DEFUN (ipv6_nht_default_route, if (zvrf->zebra_rnh_ipv6_default_route) return CMD_SUCCESS; - zvrf->zebra_rnh_ipv6_default_route = 1; - zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL); + zvrf->zebra_rnh_ipv6_default_route = true; + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); return CMD_SUCCESS; } @@ -1760,8 +1770,8 @@ DEFUN (no_ipv6_nht_default_route, if (!zvrf->zebra_rnh_ipv6_default_route) return CMD_SUCCESS; - zvrf->zebra_rnh_ipv6_default_route = 0; - zebra_evaluate_rnh(zvrf, AFI_IP6, 0, RNH_NEXTHOP_TYPE, NULL); + zvrf->zebra_rnh_ipv6_default_route = false; + zebra_evaluate_rnh(zvrf, AFI_IP6, 0, NULL, SAFI_UNICAST); return CMD_SUCCESS; } @@ -1799,7 +1809,7 @@ DEFPY (show_route, }]\ [" FRR_IP6_REDIST_STR_ZEBRA "$type_str]\ >\ - [json$json]", + [<json$json|nexthop-group$ng>]", SHOW_STR IP_STR "IP forwarding table\n" @@ -1828,7 +1838,8 @@ DEFPY (show_route, "IPv6 prefix\n" "Show route matching the specified Network/Mask pair only\n" FRR_IP6_REDIST_HELP_STR_ZEBRA - JSON_STR) + JSON_STR + "Nexthop Group Information\n") { afi_t afi = ipv4 ? AFI_IP : AFI_IP6; struct vrf *vrf; @@ -1864,18 +1875,18 @@ DEFPY (show_route, continue; if (table_all) - do_show_ip_route_all(vty, zvrf, afi, !!fib, - !!json, tag, - prefix_str ? prefix : NULL, - !!supernets_only, type, - ospf_instance_id, &ctx); + do_show_ip_route_all( + vty, zvrf, afi, !!fib, !!json, tag, + prefix_str ? prefix : NULL, + !!supernets_only, type, + ospf_instance_id, !!ng, &ctx); else - do_show_ip_route(vty, zvrf_name(zvrf), afi, - SAFI_UNICAST, !!fib, !!json, - tag, - prefix_str ? prefix : NULL, - !!supernets_only, type, - ospf_instance_id, table, &ctx); + do_show_ip_route( + vty, zvrf_name(zvrf), afi, SAFI_UNICAST, + !!fib, !!json, tag, + prefix_str ? prefix : NULL, + !!supernets_only, type, + ospf_instance_id, table, !!ng, &ctx); } } else { vrf_id_t vrf_id = VRF_DEFAULT; @@ -1894,13 +1905,13 @@ DEFPY (show_route, do_show_ip_route_all(vty, zvrf, afi, !!fib, !!json, tag, prefix_str ? prefix : NULL, !!supernets_only, type, - ospf_instance_id, &ctx); + ospf_instance_id, !!ng, &ctx); else do_show_ip_route(vty, vrf->name, afi, SAFI_UNICAST, !!fib, !!json, tag, prefix_str ? prefix : NULL, !!supernets_only, type, - ospf_instance_id, table, &ctx); + ospf_instance_id, table, !!ng, &ctx); } return CMD_SUCCESS; @@ -2477,10 +2488,7 @@ static void vty_show_ip_route_summary(struct vty *vty, json_object_int_add(json_route_summary, "routesTotalFib", fib_cnt[ZEBRA_ROUTE_TOTAL]); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_route_summary, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_route_summary); + vty_json(vty, json_route_summary); } else { vty_out(vty, "------\n"); vty_out(vty, "%-20s %-20d %-20d \n", "Totals", @@ -2628,10 +2636,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, json_object_int_add(json_route_summary, "prefixRoutesTotalFib", fib_cnt[ZEBRA_ROUTE_TOTAL]); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_route_summary, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_route_summary); + vty_json(vty, json_route_summary); } else { vty_out(vty, "------\n"); vty_out(vty, "%-20s %-20d %-20d \n", "Totals", @@ -2672,7 +2677,7 @@ DEFUN (show_ipv6_mroute, vty_out(vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route(vty, rn, re, NULL, false); + vty_show_ip_route(vty, rn, re, NULL, false, false); } return CMD_SUCCESS; } @@ -2704,7 +2709,8 @@ DEFUN (show_ipv6_mroute_vrf_all, vty_out(vty, SHOW_ROUTE_V6_HEADER); first = 0; } - vty_show_ip_route(vty, rn, re, NULL, false); + vty_show_ip_route(vty, rn, re, NULL, false, + false); } } return CMD_SUCCESS; @@ -3003,9 +3009,7 @@ DEFUN (show_vrf_vni, if (uj) { json_object_object_add(json, "vrfs", json_vrfs); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } return CMD_SUCCESS; @@ -4317,6 +4321,30 @@ DEFUN(ip_table_range, ip_table_range_cmd, return table_manager_range(vty, true, zvrf, argv[3]->arg, argv[4]->arg); } +#ifdef HAVE_SCRIPTING + +DEFUN(zebra_on_rib_process_script, zebra_on_rib_process_script_cmd, + "zebra on-rib-process script SCRIPT", + ZEBRA_STR + "on_rib_process_dplane_results hook call\n" + "Set a script\n" + "Script name (same as filename in /etc/frr/scripts/, without .lua)\n") +{ + + if (frrscript_names_set_script_name(ZEBRA_ON_RIB_PROCESS_HOOK_CALL, + argv[3]->arg) + == 0) { + vty_out(vty, "Successfully added script %s for hook call %s\n", + argv[3]->arg, ZEBRA_ON_RIB_PROCESS_HOOK_CALL); + } else { + vty_out(vty, "Failed to add script %s for hook call %s\n", + argv[3]->arg, ZEBRA_ON_RIB_PROCESS_HOOK_CALL); + } + return CMD_SUCCESS; +} + +#endif /* HAVE_SCRIPTING */ + /* IP node for static routes. */ static int zebra_ip_config(struct vty *vty); static struct cmd_node ip_node = { @@ -4473,5 +4501,9 @@ void zebra_vty_init(void) install_element(CONFIG_NODE, &no_zebra_kernel_netlink_batch_tx_buf_cmd); #endif /* HAVE_NETLINK */ +#ifdef HAVE_SCRIPTING + install_element(CONFIG_NODE, &zebra_on_rib_process_script_cmd); +#endif /* HAVE_SCRIPTING */ + install_element(VIEW_NODE, &zebra_show_routing_tables_summary_cmd); } diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index c13c867d2a..b6da445e38 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -385,10 +385,8 @@ static void zl3vni_print_rmac(struct zebra_mac *zrmac, struct vty *vty, json_object_string_add( json, "routerMac", prefix_mac2str(&zrmac->macaddr, buf1, sizeof(buf1))); - json_object_string_add(json, "vtepIp", - inet_ntop(AF_INET, - &zrmac->fwd_info.r_vtep_ip, - buf1, sizeof(buf1))); + json_object_string_addf(json, "vtepIp", "%pI4", + &zrmac->fwd_info.r_vtep_ip); json_object_int_add(json, "refCount", rb_host_count(&zrmac->host_rb)); RB_FOREACH (hle, host_rb_tree_entry, &zrmac->host_rb) @@ -680,10 +678,8 @@ static void zl3vni_print_rmac_hash(struct hash_bucket *bucket, void *ctx) json_object_string_add( json_rmac, "routerMac", prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf))); - json_object_string_add(json_rmac, "vtepIp", - inet_ntop(AF_INET, - &zrmac->fwd_info.r_vtep_ip, - buf, sizeof(buf))); + json_object_string_addf(json_rmac, "vtepIp", "%pI4", + &zrmac->fwd_info.r_vtep_ip); json_object_object_add( json, prefix_mac2str(&zrmac->macaddr, buf, sizeof(buf)), json_rmac); @@ -729,10 +725,8 @@ static void zl3vni_print(struct zebra_l3vni *zl3vni, void **ctx) json_evpn_list = json_object_new_array(); json_object_int_add(json, "vni", zl3vni->vni); json_object_string_add(json, "type", "L3"); - json_object_string_add( - json, "localVtepIp", - inet_ntop(AF_INET, &zl3vni->local_vtep_ip, buf, - sizeof(buf))); + json_object_string_addf(json, "localVtepIp", "%pI4", + &zl3vni->local_vtep_ip); json_object_string_add(json, "vxlanIntf", zl3vni_vxlan_if_name(zl3vni)); json_object_string_add(json, "sviIntf", @@ -1036,9 +1030,9 @@ static int zevpn_build_hash_table_zns(struct ns *ns, zif->brslave_info.br_if); if (vlan_if) { zevpn->svi_if = vlan_if; - zevpn->vrf_id = vlan_if->vrf_id; + zevpn->vrf_id = vlan_if->vrf->vrf_id; zl3vni = zl3vni_from_vrf( - vlan_if->vrf_id); + vlan_if->vrf->vrf_id); if (zl3vni) listnode_add_sort( zl3vni->l2vnis, zevpn); @@ -2142,7 +2136,7 @@ static int zebra_vxlan_handle_vni_transition(struct zebra_vrf *zvrf, vni_t vni, vlan_if = zvni_map_to_svi(vxl->access_vlan, zif->brslave_info.br_if); if (vlan_if) - zevpn->vrf_id = vlan_if->vrf_id; + zevpn->vrf_id = vlan_if->vrf->vrf_id; zevpn->vxlan_if = ifp; zevpn->local_vtep_ip = vxl->vtep_ip; @@ -2321,11 +2315,8 @@ void zebra_vxlan_print_specific_rmac_l3vni(struct vty *vty, vni_t l3vni, zl3vni_print_rmac(zrmac, vty, json); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t l3vni, bool use_json) @@ -2365,11 +2356,8 @@ void zebra_vxlan_print_rmacs_l3vni(struct vty *vty, vni_t l3vni, bool use_json) hash_iterate(zl3vni->rmac_table, zl3vni_print_rmac_hash, &wctx); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json) @@ -2393,11 +2381,8 @@ void zebra_vxlan_print_rmacs_all_l3vni(struct vty *vty, bool use_json) void *))zl3vni_print_rmac_hash_all_vni, args); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, @@ -2438,11 +2423,8 @@ void zebra_vxlan_print_specific_nh_l3vni(struct vty *vty, vni_t l3vni, zl3vni_print_nh(n, vty, json); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json) @@ -2482,11 +2464,8 @@ void zebra_vxlan_print_nh_l3vni(struct vty *vty, vni_t l3vni, bool use_json) hash_iterate(zl3vni->nh_table, zl3vni_print_nh_hash, &wctx); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json) @@ -2510,11 +2489,8 @@ void zebra_vxlan_print_nh_all_l3vni(struct vty *vty, bool use_json) void *))zl3vni_print_nh_hash_all_vni, args); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -2548,11 +2524,8 @@ void zebra_vxlan_print_l3vni(struct vty *vty, vni_t vni, bool use_json) args[1] = json; zl3vni_print(zl3vni, (void *)args); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } void zebra_vxlan_print_vrf_vni(struct vty *vty, struct zebra_vrf *zvrf, @@ -2639,11 +2612,8 @@ void zebra_vxlan_print_neigh_vni(struct vty *vty, struct zebra_vrf *zvrf, json_object_int_add(json, "numArpNd", num_neigh); hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash, &wctx); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -2669,11 +2639,8 @@ void zebra_vxlan_print_neigh_all_vni(struct vty *vty, struct zebra_vrf *zvrf, (void (*)(struct hash_bucket *, void *))zevpn_print_neigh_hash_all_evpn, args); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -2700,11 +2667,8 @@ void zebra_vxlan_print_neigh_all_vni_detail(struct vty *vty, (void (*)(struct hash_bucket *, void *))zevpn_print_neigh_hash_all_evpn_detail, args); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -2741,11 +2705,8 @@ void zebra_vxlan_print_specific_neigh_vni(struct vty *vty, zebra_evpn_print_neigh(n, vty, json); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -2789,11 +2750,8 @@ void zebra_vxlan_print_neigh_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, &wctx); hash_iterate(zevpn->neigh_table, zebra_evpn_print_neigh_hash, &wctx); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -2855,11 +2813,8 @@ void zebra_vxlan_print_neigh_vni_dad(struct vty *vty, hash_iterate(zevpn->neigh_table, zebra_evpn_print_dad_neigh_hash, &wctx); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -2913,9 +2868,7 @@ void zebra_vxlan_print_macs_vni(struct vty *vty, struct zebra_vrf *zvrf, if (use_json) { json_object_object_add(json, "macs", json_mac); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } } @@ -2942,11 +2895,8 @@ void zebra_vxlan_print_macs_all_vni(struct vty *vty, struct zebra_vrf *zvrf, wctx.print_dup = print_dup; hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn, &wctx); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -2974,11 +2924,8 @@ void zebra_vxlan_print_macs_all_vni_detail(struct vty *vty, hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn_detail, &wctx); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -3004,11 +2951,8 @@ void zebra_vxlan_print_macs_all_vni_vtep(struct vty *vty, wctx.json = json; hash_iterate(zvrf->evpn_table, zevpn_print_mac_hash_all_evpn, &wctx); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* @@ -3048,11 +2992,8 @@ void zebra_vxlan_print_specific_mac_vni(struct vty *vty, struct zebra_vrf *zvrf, json = json_object_new_object(); zebra_evpn_print_mac(mac, vty, json); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } /* Print Duplicate MACs per VNI */ @@ -3106,9 +3047,7 @@ void zebra_vxlan_print_macs_vni_dad(struct vty *vty, if (use_json) { json_object_object_add(json, "macs", json_mac); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } } @@ -3448,9 +3387,7 @@ void zebra_vxlan_print_macs_vni_vtep(struct vty *vty, struct zebra_vrf *zvrf, json_object_int_add(json, "numMacs", wctx.count); if (wctx.count) json_object_object_add(json, "macs", json_mac); - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } } @@ -3499,11 +3436,8 @@ void zebra_vxlan_print_vni(struct vty *vty, struct zebra_vrf *zvrf, vni_t vni, */ if (json_array) json_object_array_add(json_array, json); - else { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + else + vty_json(vty, json); } } @@ -3570,11 +3504,8 @@ void zebra_vxlan_print_evpn(struct vty *vty, bool uj) zebra_evpn_mh_print(vty); } - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); } /* @@ -3610,11 +3541,8 @@ void zebra_vxlan_print_vnis(struct vty *vty, struct zebra_vrf *zvrf, (void (*)(struct hash_bucket *, void *))zl3vni_print_hash, args); - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (use_json) + vty_json(vty, json); } void zebra_vxlan_dup_addr_detection(ZAPI_HANDLER_ARGS) @@ -3699,12 +3627,8 @@ void zebra_vxlan_print_vnis_detail(struct vty *vty, struct zebra_vrf *zvrf, void *))zl3vni_print_hash_detail, &zes); - if (use_json) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json_array, JSON_C_TO_STRING_PRETTY)); - json_object_free(json_array); - } + if (use_json) + vty_json(vty, json_array); } /* @@ -3981,7 +3905,7 @@ int zebra_vxlan_check_readd_vtep(struct interface *ifp, return 0; /* Locate VRF corresponding to interface. */ - zvrf = vrf_info_lookup(ifp->vrf_id); + zvrf = ifp->vrf->info; if (!zvrf) return -1; @@ -4645,6 +4569,11 @@ int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if) zevpn = zebra_evpn_from_svi(ifp, link_if); if (zevpn) { + /* remove from l3-vni list */ + zl3vni = zl3vni_from_vrf(zevpn->vrf_id); + if (zl3vni) + listnode_delete(zl3vni->l2vnis, zevpn); + zevpn->svi_if = NULL; zevpn->vrf_id = VRF_DEFAULT; @@ -4661,7 +4590,7 @@ int zebra_vxlan_svi_down(struct interface *ifp, struct interface *link_if) * SVI can be associated to L3-VNI (l3vni vxlan interface) or L2-VNI (l2-vni * vxlan intf). * For L2-VNI: we need to install any remote neighbors entried (used for - * apr-suppression) + * arp-suppression) * For L3-VNI: SVI will be used to get the rmac to be used with L3-VNI */ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) @@ -4698,11 +4627,15 @@ int zebra_vxlan_svi_up(struct interface *ifp, struct interface *link_if) zlog_debug( "SVI %s(%u) VNI %u VRF %s is UP, installing neighbors", ifp->name, ifp->ifindex, zevpn->vni, - vrf_id_to_name(ifp->vrf_id)); + ifp->vrf->name); /* update the vrf information for l2-vni and inform bgp */ zevpn->svi_if = ifp; - zevpn->vrf_id = ifp->vrf_id; + zevpn->vrf_id = ifp->vrf->vrf_id; + + zl3vni = zl3vni_from_vrf(zevpn->vrf_id); + if (zl3vni) + listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); if (if_is_operative(zevpn->vxlan_if)) zebra_evpn_send_add_to_client(zevpn); @@ -4736,13 +4669,12 @@ void zebra_vxlan_macvlan_down(struct interface *ifp) assert(zif); link_ifp = zif->link; if (!link_ifp) { - if (IS_ZEBRA_DEBUG_VXLAN) { - struct interface *ifp; - - ifp = if_lookup_by_index_all_vrf(zif->link_ifindex); - zlog_debug("macvlan parent link is not found. Parent index %d ifp %s", - zif->link_ifindex, ifp ? ifp->name : " "); - } + if (IS_ZEBRA_DEBUG_VXLAN) + zlog_debug( + "macvlan parent link is not found. Parent index %d ifp %s", + zif->link_ifindex, + ifindex2ifname(zif->link_ifindex, + ifp->vrf->vrf_id)); return; } link_zif = link_ifp->info; @@ -4913,8 +4845,8 @@ int zebra_vxlan_if_up(struct interface *ifp) zif->brslave_info.br_if); if (vlan_if) { zevpn->svi_if = vlan_if; - zevpn->vrf_id = vlan_if->vrf_id; - zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); + zevpn->vrf_id = vlan_if->vrf->vrf_id; + zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); if (zl3vni) listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); } @@ -5267,8 +5199,8 @@ int zebra_vxlan_if_add(struct interface *ifp) zif->brslave_info.br_if); if (vlan_if) { zevpn->svi_if = vlan_if; - zevpn->vrf_id = vlan_if->vrf_id; - zl3vni = zl3vni_from_vrf(vlan_if->vrf_id); + zevpn->vrf_id = vlan_if->vrf->vrf_id; + zl3vni = zl3vni_from_vrf(vlan_if->vrf->vrf_id); if (zl3vni) listnode_add_sort_nodup(zl3vni->l2vnis, zevpn); } @@ -5277,8 +5209,7 @@ int zebra_vxlan_if_add(struct interface *ifp) zlog_debug( "Add L2-VNI %u VRF %s intf %s(%u) VLAN %u local IP %pI4 mcast_grp %pI4 master %u", vni, - vlan_if ? vrf_id_to_name(vlan_if->vrf_id) - : VRF_DEFAULT_NAME, + vlan_if ? vlan_if->vrf->name : VRF_DEFAULT_NAME, ifp->name, ifp->ifindex, vxl->access_vlan, &vxl->vtep_ip, &vxl->mcast_grp, zif->brslave_info.bridge_ifindex); diff --git a/zebra/zserv.c b/zebra/zserv.c index e4a48093f7..f3f69661c4 100644 --- a/zebra/zserv.c +++ b/zebra/zserv.c @@ -1007,7 +1007,6 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) char wbuf[ZEBRA_TIME_BUF], nhbuf[ZEBRA_TIME_BUF], mbuf[ZEBRA_TIME_BUF]; time_t connect_time, last_read_time, last_write_time; uint32_t last_read_cmd, last_write_cmd; - struct client_gr_info *info = NULL; vty_out(vty, "Client: %s", zebra_route_string(client->proto)); if (client->instance) @@ -1100,22 +1099,6 @@ static void zebra_show_client_detail(struct vty *vty, struct zserv *client) 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) { - 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; - } - } - #if defined DEV_BUILD vty_out(vty, "Input Fifo: %zu:%zu Output Fifo: %zu:%zu\n", client->ibuf_fifo->count, client->ibuf_fifo->max_count, @@ -1151,7 +1134,8 @@ static void zebra_show_stale_client_detail(struct vty *vty, vty_out(vty, "Capabilities : "); switch (info->capabilities) { case ZEBRA_CLIENT_GR_CAPABILITIES: - vty_out(vty, "Graceful Restart\n"); + vty_out(vty, "Graceful Restart(%u seconds)\n", + info->stale_removal_time); break; case ZEBRA_CLIENT_ROUTE_UPDATE_COMPLETE: case ZEBRA_CLIENT_ROUTE_UPDATE_PENDING: @@ -1213,7 +1197,8 @@ static void zebra_show_client_brief(struct vty *vty, struct zserv *client) snprintfrr(client_string, sizeof(client_string), "%s", zebra_route_string(client->proto)); - vty_out(vty, "%-10s%12s %12s%12s%8d/%-8d%8d/%-8d\n", client_string, + vty_out(vty, "%-10s%12s %12s%12s %10d/%-10d %10d/%-10d\n", + client_string, zserv_time_buf(&connect_time, cbuf, ZEBRA_TIME_BUF), zserv_time_buf(&last_read_time, rbuf, ZEBRA_TIME_BUF), zserv_time_buf(&last_write_time, wbuf, ZEBRA_TIME_BUF), @@ -1307,9 +1292,9 @@ DEFUN (show_zebra_client_summary, struct zserv *client; vty_out(vty, - "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes \n"); + "Name Connect Time Last Read Last Write IPv4 Routes IPv6 Routes\n"); vty_out(vty, - "--------------------------------------------------------------------------------\n"); + "------------------------------------------------------------------------------------------\n"); for (ALL_LIST_ELEMENTS_RO(zrouter.client_list, node, client)) zebra_show_client_brief(vty, client); |
