diff options
347 files changed, 21668 insertions, 11998 deletions
diff --git a/.clang-format b/.clang-format index e1897bfa99..a620b5c2c0 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: @@ -69,6 +69,7 @@ ForEachMacros: - SUBGRP_FOREACH_ADJ_SAFE - AF_FOREACH - FOREACH_AFI_SAFI + - FOREACH_AFI_SAFI_NSF - FOREACH_SAFI # ospfd - LSDB_LOOP 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/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/bfdd/bfd.c b/bfdd/bfd.c index f497480457..c9a327490c 100644 --- a/bfdd/bfd.c +++ b/bfdd/bfd.c @@ -639,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; } @@ -1226,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); } @@ -1975,19 +1946,6 @@ static int bfd_vrf_delete(struct vrf *vrf) return 0; } -static int bfd_vrf_update(struct vrf *vrf) -{ - if (!vrf_is_enabled(vrf)) - return 0; - - if (bglobal.debug_zebra) - zlog_debug("VRF update: %s(%u)", vrf->name, vrf->vrf_id); - - /* a different name is given; update bfd list */ - bfdd_sessions_enable_vrf(vrf); - return 0; -} - static int bfd_vrf_enable(struct vrf *vrf) { struct bfd_vrf_global *bvrf; @@ -2099,8 +2057,7 @@ static int bfd_vrf_disable(struct vrf *vrf) void bfd_vrf_init(void) { - vrf_init(bfd_vrf_new, bfd_vrf_enable, bfd_vrf_disable, - bfd_vrf_delete, bfd_vrf_update); + vrf_init(bfd_vrf_new, bfd_vrf_enable, bfd_vrf_disable, bfd_vrf_delete); } void bfd_vrf_terminate(void) @@ -2125,63 +2082,6 @@ struct bfd_vrf_global *bfd_vrf_look_by_session(struct bfd_session *bfd) return bfd->vrf->info; } -void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf) -{ - if (!vrf || !bs) - return; - /* update key */ - hash_release(bfd_key_hash, bs); - /* - * HACK: Change the BFD VRF in the running configuration directly, - * bypassing the northbound layer. This is necessary to avoid deleting - * the BFD and readding it in the new VRF, which would have - * several implications. - */ - if (yang_module_find("frr-bfdd") && bs->key.vrfname[0]) { - struct lyd_node *bfd_dnode; - char xpath[XPATH_MAXLEN], xpath_srcaddr[XPATH_MAXLEN + 32]; - char oldpath[XPATH_MAXLEN], newpath[XPATH_MAXLEN]; - char addr_buf[INET6_ADDRSTRLEN]; - int slen; - - /* build xpath */ - if (bs->key.mhop) { - inet_ntop(bs->key.family, &bs->key.local, addr_buf, sizeof(addr_buf)); - snprintf(xpath_srcaddr, sizeof(xpath_srcaddr), "[source-addr='%s']", - addr_buf); - } else - xpath_srcaddr[0] = 0; - inet_ntop(bs->key.family, &bs->key.peer, addr_buf, sizeof(addr_buf)); - slen = snprintf(xpath, sizeof(xpath), - "/frr-bfdd:bfdd/bfd/sessions/%s%s[dest-addr='%s']", - bs->key.mhop ? "multi-hop" : "single-hop", xpath_srcaddr, - addr_buf); - if (bs->key.ifname[0]) - slen += snprintf(xpath + slen, sizeof(xpath) - slen, - "[interface='%s']", bs->key.ifname); - else - slen += snprintf(xpath + slen, sizeof(xpath) - slen, - "[interface='*']"); - snprintf(xpath + slen, sizeof(xpath) - slen, "[vrf='%s']/vrf", - bs->key.vrfname); - - bfd_dnode = yang_dnode_getf(running_config->dnode, xpath, - bs->key.vrfname); - if (bfd_dnode) { - yang_dnode_get_path(lyd_parent(bfd_dnode), oldpath, - sizeof(oldpath)); - yang_dnode_change_leaf(bfd_dnode, vrf->name); - yang_dnode_get_path(lyd_parent(bfd_dnode), newpath, - sizeof(newpath)); - nb_running_move_tree(oldpath, newpath); - running_config->version++; - } - } - memset(bs->key.vrfname, 0, sizeof(bs->key.vrfname)); - strlcpy(bs->key.vrfname, vrf->name, sizeof(bs->key.vrfname)); - hash_get(bfd_key_hash, bs, hash_alloc_intern); -} - unsigned long bfd_get_session_count(void) { return bfd_key_hash->count; diff --git a/bfdd/bfd.h b/bfdd/bfd.h index dfe1a20303..473886901c 100644 --- a/bfdd/bfd.h +++ b/bfdd/bfd.h @@ -774,7 +774,6 @@ void bfdd_zclient_unregister(vrf_id_t vrf_id); void bfdd_zclient_register(vrf_id_t vrf_id); void bfdd_sessions_enable_vrf(struct vrf *vrf); void bfdd_sessions_disable_vrf(struct vrf *vrf); -void bfd_session_update_vrf_name(struct bfd_session *bs, struct vrf *vrf); int ptm_bfd_notify(struct bfd_session *bs, uint8_t notify_state); diff --git a/bfdd/bfd_packet.c b/bfdd/bfd_packet.c index 5b1329fa37..652b914118 100644 --- a/bfdd/bfd_packet.c +++ b/bfdd/bfd_packet.c @@ -697,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_vty.c b/bfdd/bfdd_vty.c index 4091ab9caa..dc0958fb33 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,11 +469,10 @@ 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) +static void _clear_peer_counter(struct bfd_session *bs) { /* Clear only pkt stats, intention is not to loose system events counters */ @@ -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 * @@ -748,7 +743,7 @@ DEFPY(bfd_clear_peer_counters, bfd_clear_peer_counters_cmd, ifname, vrfname); if (bs == NULL) return CMD_WARNING_CONFIG_FAILED; - + _clear_peer_counter(bs); return CMD_SUCCESS; diff --git a/bfdd/ptm_adapter.c b/bfdd/ptm_adapter.c index bf8f731d50..b0eb85e5f8 100644 --- a/bfdd/ptm_adapter.c +++ b/bfdd/ptm_adapter.c @@ -721,11 +721,6 @@ void bfdd_sessions_enable_vrf(struct vrf *vrf) /* it may affect configs without interfaces */ TAILQ_FOREACH(bso, &bglobal.bg_obslist, bso_entry) { bs = bso->bso_bs; - /* update name */ - if (bs->vrf && bs->vrf == vrf) { - if (!strmatch(bs->key.vrfname, vrf->name)) - bfd_session_update_vrf_name(bs, vrf); - } if (bs->vrf) continue; if (bs->key.vrfname[0] && diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index 7de7a6628f..632cae8c7d 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"}, @@ -834,10 +831,6 @@ static void *bgp_attr_hash_alloc(void *p) if (vnc_subtlvs) bgp_attr_set_vnc_subtlvs(val, NULL); #endif - if (val->srv6_l3vpn) - val->srv6_l3vpn = NULL; - if (val->srv6_vpn) - val->srv6_vpn = NULL; attr->refcnt = 0; return attr; @@ -1073,7 +1066,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_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..91e983e5d5 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -653,21 +653,39 @@ 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_json(vty, 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 +696,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 +706,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 +718,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 +731,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_evpn_mh.c b/bgpd/bgp_evpn_mh.c index d35f86caf5..2254bc6ba7 100644 --- a/bgpd/bgp_evpn_mh.c +++ b/bgpd/bgp_evpn_mh.c @@ -2451,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 */ @@ -2475,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); } /*****************************************************************************/ @@ -3030,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 */ @@ -3884,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 */ @@ -3922,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); } /***************************************************************************** @@ -4654,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 89ed9551ce..f377c8352b 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -1345,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); @@ -1368,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", @@ -4389,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; } @@ -4674,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; } @@ -4738,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; } @@ -4824,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; } @@ -4868,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; } @@ -4938,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; } @@ -5008,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; } @@ -5066,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; } @@ -5129,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; } @@ -5165,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; } @@ -5202,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; } @@ -5239,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; } @@ -5275,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; } @@ -5861,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 7dda4f0180..fc9fc1e523 100644 --- a/bgpd/bgp_filter.c +++ b/bgpd/bgp_filter.c @@ -672,12 +672,8 @@ 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; } @@ -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; } 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 91265ed358..45e9aad1ba 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; } @@ -683,10 +848,9 @@ static int bgp_graceful_stale_timer_expire(struct thread *thread) peer->host); /* 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_NSF (afi, safi) + if (peer->nsf[afi][safi]) + bgp_clear_stale_route(peer, afi, safi); return 0; } @@ -830,8 +994,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 @@ -1277,10 +1440,8 @@ int bgp_stop(struct peer *peer) } else { UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; - safi++) - peer->nsf[afi][safi] = 0; + FOREACH_AFI_SAFI_NSF (afi, safi) + peer->nsf[afi][safi] = 0; } /* Stop route-refresh stalepath timer */ @@ -1961,48 +2122,43 @@ static int bgp_establish(struct peer *peer) else if (BGP_PEER_HELPER_MODE(peer)) zlog_debug("peer %s BGP_HELPER_MODE", peer->host); } - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) { - if (peer->afc_nego[afi][safi] - && CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) - && CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_RESTART_AF_RCV)) { - if (peer->nsf[afi][safi] - && !CHECK_FLAG( - peer->af_cap[afi][safi], - PEER_CAP_RESTART_AF_PRESERVE_RCV)) - bgp_clear_stale_route(peer, afi, safi); - - peer->nsf[afi][safi] = 1; - nsf_af_count++; + + FOREACH_AFI_SAFI_NSF (afi, safi) { + if (peer->afc_nego[afi][safi] && + CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) && + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_RCV)) { + if (peer->nsf[afi][safi] && + !CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV)) + bgp_clear_stale_route(peer, afi, safi); + + peer->nsf[afi][safi] = 1; + nsf_af_count++; + } else { + if (peer->nsf[afi][safi]) + bgp_clear_stale_route(peer, afi, safi); + peer->nsf[afi][safi] = 0; + } + /* Update the graceful restart information */ + if (peer->afc_nego[afi][safi]) { + if (!BGP_SELECT_DEFER_DISABLE(peer->bgp)) { + status = bgp_update_gr_info(peer, afi, safi); + if (status < 0) + zlog_err( + "Error in updating graceful restart for %s", + get_afi_safi_str(afi, safi, + false)); } else { - if (peer->nsf[afi][safi]) - bgp_clear_stale_route(peer, afi, safi); - peer->nsf[afi][safi] = 0; - } - /* Update the graceful restart information */ - if (peer->afc_nego[afi][safi]) { - if (!BGP_SELECT_DEFER_DISABLE(peer->bgp)) { - status = bgp_update_gr_info(peer, afi, - safi); - if (status < 0) - zlog_err( - "Error in updating graceful restart for %s", - get_afi_safi_str( - afi, safi, - false)); - } else { - if (BGP_PEER_GRACEFUL_RESTART_CAPABLE( - peer) - && BGP_PEER_RESTARTING_MODE(peer) - && CHECK_FLAG( - peer->bgp->flags, - BGP_FLAG_GR_PRESERVE_FWD)) - peer->bgp->gr_info[afi][safi] - .eor_required++; - } + if (BGP_PEER_GRACEFUL_RESTART_CAPABLE(peer) && + BGP_PEER_RESTARTING_MODE(peer) && + CHECK_FLAG(peer->bgp->flags, + BGP_FLAG_GR_PRESERVE_FWD)) + peer->bgp->gr_info[afi][safi] + .eor_required++; } } + } if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) { if ((bgp_peer_gr_mode_get(peer) == PEER_GR) diff --git a/bgpd/bgp_label.c b/bgpd/bgp_label.c index fa2a445165..c101cf917b 100644 --- a/bgpd/bgp_label.c +++ b/bgpd/bgp_label.c @@ -444,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_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 6a01a6137c..d9b0fab518 100644 --- a/bgpd/bgp_main.c +++ b/bgpd/bgp_main.c @@ -294,19 +294,6 @@ static int bgp_vrf_enable(struct vrf *vrf) bgp = bgp_lookup_by_name(vrf->name); if (bgp && bgp->vrf_id != vrf->vrf_id) { - if (bgp->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) { - XFREE(MTYPE_BGP, bgp->name); - XFREE(MTYPE_BGP, bgp->name_pretty); - bgp->name_pretty = XSTRDUP(MTYPE_BGP, "VRF default"); - bgp->inst_type = BGP_INSTANCE_TYPE_DEFAULT; -#ifdef ENABLE_BGP_VNC - if (!bgp->rfapi) { - bgp->rfapi = bgp_rfapi_new(bgp); - assert(bgp->rfapi); - assert(bgp->rfapi_cfg); - } -#endif /* ENABLE_BGP_VNC */ - } old_vrf_id = bgp->vrf_id; /* We have instance configured, link to VRF and make it "up". */ bgp_vrf_link(bgp, vrf); @@ -367,8 +354,7 @@ static int bgp_vrf_disable(struct vrf *vrf) static void bgp_vrf_init(void) { - vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, - bgp_vrf_delete, bgp_vrf_enable); + vrf_init(bgp_vrf_new, bgp_vrf_enable, bgp_vrf_disable, bgp_vrf_delete); } static void bgp_vrf_terminate(void) diff --git a/bgpd/bgp_mpath.c b/bgpd/bgp_mpath.c index 42077d4e8e..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; } 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 424ff3d97b..19ae137208 100644 --- a/bgpd/bgp_nht.c +++ b/bgpd/bgp_nht.c @@ -895,10 +895,11 @@ static void sendmsg_zebra_rnh(struct bgp_nexthop_cache *bnc, int command) ret = zclient_send_rnh(zclient, command, &bnc->prefix, exact_match, resolve_via_default, bnc->bgp->vrf_id); - /* TBD: handle the failure */ - if (ret == ZCLIENT_SEND_FAILURE) + if (ret == ZCLIENT_SEND_FAILURE) { flog_warn(EC_BGP_ZEBRA_SEND, "sendmsg_nexthop: zclient_send_message() failed"); + return; + } if (command == ZEBRA_NEXTHOP_REGISTER) SET_FLAG(bnc->flags, BGP_NEXTHOP_REGISTERED); diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c index e15690835a..6bdefd0e9b 100644 --- a/bgpd/bgp_open.c +++ b/bgpd/bgp_open.c @@ -57,6 +57,7 @@ static const struct message capcode_str[] = { {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) */ @@ -75,6 +76,7 @@ static const size_t cap_minsizes[] = { [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. @@ -97,6 +99,7 @@ static const size_t cap_modsizes[] = { [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 @@ -603,8 +606,15 @@ static int bgp_capability_llgr(struct peer *peer, 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 = stale_time; + 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); } } @@ -1088,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); @@ -1104,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) @@ -1112,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) @@ -1160,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; @@ -1179,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) { @@ -1191,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; @@ -1299,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; @@ -1315,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 */ @@ -1363,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; @@ -1389,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); @@ -1444,11 +1464,12 @@ 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, - unsigned long cp) + bool ext_opt_params) { int len; iana_afi_t pkt_afi; @@ -1465,7 +1486,8 @@ static void bgp_peer_send_llgr_capability(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, CAPABILITY_CODE_LLGR); rcapp = stream_get_endp(s); @@ -1491,14 +1513,16 @@ static void bgp_peer_send_llgr_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); } /* 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; @@ -1507,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) { @@ -1527,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); @@ -1547,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); @@ -1568,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) @@ -1598,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); @@ -1617,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); @@ -1664,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); } } @@ -1674,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); } @@ -1688,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 */ @@ -1710,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); @@ -1721,10 +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_llgr_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 0d616926a2..c04816c006 100644 --- a/bgpd/bgp_open.h +++ b/bgpd/bgp_open.h @@ -93,10 +93,19 @@ struct graceful_restart_af { /* Long-lived Graceful Restart */ #define LLGR_F_BIT 0x80 -extern int bgp_open_option_parse(struct peer *, uint8_t, int *); -extern void bgp_open_capability(struct stream *, struct peer *); +/* 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 b79fe778ae..8569cbc102 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -307,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; } @@ -548,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, @@ -587,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; @@ -598,9 +606,11 @@ 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; @@ -611,7 +621,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, } 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(%s): Comparing %s flags 0x%x with %s flags 0x%x", pfx_buf, bgp->name_pretty, new_buf, new->flags, @@ -621,6 +632,33 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, 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 @@ -859,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); @@ -1689,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; @@ -1727,27 +1803,18 @@ void bgp_attr_add_gshut_community(struct attr *attr) /* Notify BGP Conditional advertisement scanner process. */ void bgp_notify_conditional_adv_scanner(struct update_subgroup *subgrp) { - struct peer *temp_peer; struct peer *peer = SUBGRP_PEER(subgrp); - struct listnode *temp_node, *temp_nnode = NULL; afi_t afi = SUBGRP_AFI(subgrp); safi_t safi = SUBGRP_SAFI(subgrp); - struct bgp *bgp = SUBGRP_INST(subgrp); struct bgp_filter *filter = &peer->filter[afi][safi]; if (!ADVERTISE_MAP_NAME(filter)) return; - for (ALL_LIST_ELEMENTS(bgp->peer, temp_node, temp_nnode, temp_peer)) { - if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) - continue; - - if (peer != temp_peer) - continue; + if (!CHECK_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE)) + return; - temp_peer->advmap_table_change = true; - break; - } + peer->advmap_table_change = true; } @@ -2164,6 +2231,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 @@ -2596,9 +2677,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); @@ -2877,6 +2963,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 @@ -2976,11 +3067,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. @@ -3629,6 +3725,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]; @@ -3643,6 +3740,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; @@ -3730,7 +3831,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; @@ -3773,7 +3874,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++; @@ -5230,6 +5331,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; @@ -5252,10 +5358,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; } @@ -5267,8 +5392,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; } @@ -7412,15 +7552,14 @@ void bgp_aggregate_delete(struct bgp *bgp, const struct prefix *p, afi_t afi, if (pi->sub_type == BGP_ROUTE_AGGREGATE) continue; - if (aggregate->summary_only && pi->extra - && AGGREGATE_MED_VALID(aggregate)) { - if (aggr_unsuppress_path(aggregate, pi)) - match++; - } - - if (aggregate->suppress_map_name - && AGGREGATE_MED_VALID(aggregate) - && aggr_suppress_map_test(bgp, aggregate, pi)) { + /* + * This route is suppressed: attempt to unsuppress it. + * + * `aggr_unsuppress_path` will fail if this particular + * aggregate route was not the suppressor. + */ + if (pi->extra && pi->extra->aggr_suppressors && + listcount(pi->extra->aggr_suppressors)) { if (aggr_unsuppress_path(aggregate, pi)) match++; } @@ -8300,6 +8439,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) @@ -8384,7 +8524,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) { @@ -8395,8 +8534,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) { @@ -8420,8 +8558,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); } } @@ -9100,8 +9237,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); @@ -10589,6 +10725,19 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, str, label2vni(&attr->label)); } + if (path->peer->t_llgr_stale[afi][safi] && attr->community && + community_include(attr->community, COMMUNITY_LLGR_STALE)) { + unsigned long llgr_remaining = thread_timer_remain_second( + path->peer->t_llgr_stale[afi][safi]); + if (json_paths) { + json_object_int_add(json_path, "llgrSecondsRemaining", + llgr_remaining); + } else + vty_out(vty, + " Time until Long-lived stale route deleted: %lu\n", + llgr_remaining); + } + /* Output some debug about internal state of the dest flags */ if (json_paths) { if (CHECK_FLAG(bn->flags, BGP_NODE_PROCESS_SCHEDULED)) @@ -10605,12 +10754,7 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn, json_object_boolean_true_add(json_path, "fibInstalled"); if (CHECK_FLAG(bn->flags, BGP_NODE_FIB_INSTALL_PENDING)) json_object_boolean_true_add(json_path, "fibPending"); - } - /* We've constructed the json object for this path, add it to the json - * array of paths - */ - if (json_paths) { if (json_nexthop_global || json_nexthop_ll) { json_nexthops = json_object_new_array(); @@ -10635,21 +10779,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); @@ -11247,7 +11376,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; @@ -11301,8 +11429,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); } @@ -11393,7 +11520,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"); @@ -11674,10 +11801,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"); @@ -12012,45 +12136,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 AS_PATH_FILTER_NAME\ - |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) { @@ -12067,43 +12174,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 "]]\ @@ -12115,9 +12190,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 @@ -12142,6 +12223,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" @@ -12149,19 +12240,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; @@ -12224,6 +12319,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)) @@ -12235,13 +12399,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) { @@ -12250,17 +12429,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 */ @@ -12295,19 +12467,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"); @@ -12337,14 +12499,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"); @@ -12532,59 +12689,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) @@ -12607,47 +12711,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, @@ -13203,9 +13266,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 @@ -13760,15 +13821,15 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, &output_count, &filtered_count); if (use_json) { - json_object_object_add(json, "advertisedRoutes", json_ar); + if (type == bgp_show_adj_route_advertised) + json_object_object_add(json, "advertisedRoutes", + json_ar); + else + json_object_object_add(json, "receivedRoutes", json_ar); json_object_int_add(json, "totalPrefixCounter", output_count); 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)); - /* * These fields only give up ownership to `json` when `header1` * is used (set to zero). See code in `show_adj_route` and @@ -13779,7 +13840,7 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, json_object_free(json_ocode); } - json_object_free(json); + vty_json(vty, json); } else if (output_count > 0) { if (filtered_count > 0) vty_out(vty, @@ -14568,7 +14629,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" @@ -14614,7 +14675,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" @@ -15102,10 +15163,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 2fd80495d9..741690a028 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -587,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, @@ -633,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); @@ -773,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, diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b2eb70a9cc..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), @@ -6189,6 +6240,45 @@ ALIAS_HIDDEN (no_match_ipv6_next_hop_address, "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", @@ -6566,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); @@ -6749,6 +6842,7 @@ 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); @@ -6759,8 +6853,10 @@ void bgp_route_map_init(void) 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); diff --git a/bgpd/bgp_table.c b/bgpd/bgp_table.c index 4ed8c7c59b..0ca78d0bb6 100644 --- a/bgpd/bgp_table.c +++ b/bgpd/bgp_table.c @@ -237,7 +237,7 @@ struct bgp_node *bgp_table_subtree_lookup(const struct bgp_table *table, return matched; } -printfrr_ext_autoreg_p("BD", printfrr_bd) +printfrr_ext_autoreg_p("BD", printfrr_bd); static ssize_t printfrr_bd(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { diff --git a/bgpd/bgp_updgrp_adv.c b/bgpd/bgp_updgrp_adv.c index e43ae5c13f..c6ddb1c1a7 100644 --- a/bgpd/bgp_updgrp_adv.c +++ b/bgpd/bgp_updgrp_adv.c @@ -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 diff --git a/bgpd/bgp_vpn.c b/bgpd/bgp_vpn.c index bf630c1d89..6308936aa8 100644 --- a/bgpd/bgp_vpn.c +++ b/bgpd/bgp_vpn.c @@ -239,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 88d84a3c50..e07883865a 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" @@ -3169,7 +3167,8 @@ DEFUN (no_bgp_graceful_restart_rib_stale_time, } DEFUN(bgp_llgr_stalepath_time, bgp_llgr_stalepath_time_cmd, - "bgp long-lived-graceful-restart stale-time (0-4294967295)", BGP_STR + "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") @@ -3185,7 +3184,7 @@ DEFUN(bgp_llgr_stalepath_time, bgp_llgr_stalepath_time_cmd, } DEFUN(no_bgp_llgr_stalepath_time, no_bgp_llgr_stalepath_time_cmd, - "no bgp long-lived-graceful-restart stale-time [(0-4294967295)]", + "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" @@ -4235,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); @@ -6308,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, @@ -9724,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, @@ -10258,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"); } @@ -10829,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) @@ -11299,185 +11322,167 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( json_object *json_endofrib_status = NULL; bool eor_flag = false; - for (afi = AFI_IP; afi < AFI_MAX; afi++) { - for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) { - if (!peer->afc[afi][safi]) - continue; + FOREACH_AFI_SAFI_NSF (afi, safi) { + if (!peer->afc[afi][safi]) + continue; - if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) - || !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) - continue; + if (!CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) || + !CHECK_FLAG(peer->cap, PEER_CAP_RESTART_RCV)) + continue; - if (use_json) { - json_afi_safi = json_object_new_object(); - json_endofrib_status = json_object_new_object(); - json_timer = json_object_new_object(); - } + if (use_json) { + json_afi_safi = json_object_new_object(); + json_endofrib_status = json_object_new_object(); + json_timer = json_object_new_object(); + } - if (peer->eor_stime[afi][safi] - >= peer->pkt_stime[afi][safi]) - eor_flag = true; - else - eor_flag = false; + if (peer->eor_stime[afi][safi] >= peer->pkt_stime[afi][safi]) + eor_flag = true; + else + eor_flag = false; - if (!use_json) { - vty_out(vty, " %s:\n", - get_afi_safi_str(afi, safi, false)); + if (!use_json) { + vty_out(vty, " %s:\n", + get_afi_safi_str(afi, safi, false)); - vty_out(vty, " F bit: "); - } + vty_out(vty, " F bit: "); + } - if (peer->nsf[afi][safi] - && CHECK_FLAG(peer->af_cap[afi][safi], - PEER_CAP_RESTART_AF_PRESERVE_RCV)) { + if (peer->nsf[afi][safi] && + CHECK_FLAG(peer->af_cap[afi][safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV)) { - if (use_json) { - json_object_boolean_true_add( - json_afi_safi, "fBit"); - } else - vty_out(vty, "True\n"); - } else { - if (use_json) - json_object_boolean_false_add( - json_afi_safi, "fBit"); - else - vty_out(vty, "False\n"); - } + if (use_json) { + json_object_boolean_true_add(json_afi_safi, + "fBit"); + } else + vty_out(vty, "True\n"); + } else { + if (use_json) + json_object_boolean_false_add(json_afi_safi, + "fBit"); + else + vty_out(vty, "False\n"); + } - if (!use_json) - vty_out(vty, " End-of-RIB sent: "); + if (!use_json) + vty_out(vty, " End-of-RIB sent: "); - if (CHECK_FLAG(peer->af_sflags[afi][safi], - PEER_STATUS_EOR_SEND)) { - if (use_json) { - json_object_boolean_true_add( - json_endofrib_status, - "endOfRibSend"); + if (CHECK_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_EOR_SEND)) { + if (use_json) { + json_object_boolean_true_add( + json_endofrib_status, "endOfRibSend"); - PRINT_EOR_JSON(eor_flag); - } else { - vty_out(vty, "Yes\n"); - vty_out(vty, - " End-of-RIB sent after update: "); + PRINT_EOR_JSON(eor_flag); + } else { + vty_out(vty, "Yes\n"); + vty_out(vty, + " End-of-RIB sent after update: "); - PRINT_EOR(eor_flag); - } + PRINT_EOR(eor_flag); + } + } else { + if (use_json) { + json_object_boolean_false_add( + json_endofrib_status, "endOfRibSend"); + json_object_boolean_false_add( + json_endofrib_status, + "endOfRibSentAfterUpdate"); } else { - if (use_json) { - json_object_boolean_false_add( - json_endofrib_status, - "endOfRibSend"); - json_object_boolean_false_add( - json_endofrib_status, - "endOfRibSentAfterUpdate"); - } else { - vty_out(vty, "No\n"); - vty_out(vty, - " End-of-RIB sent after update: "); - vty_out(vty, "No\n"); - } + vty_out(vty, "No\n"); + vty_out(vty, + " End-of-RIB sent after update: "); + vty_out(vty, "No\n"); } + } - if (!use_json) - vty_out(vty, " End-of-RIB received: "); + if (!use_json) + vty_out(vty, " End-of-RIB received: "); - if (CHECK_FLAG(peer->af_sflags[afi][safi], - PEER_STATUS_EOR_RECEIVED)) { - if (use_json) - json_object_boolean_true_add( - json_endofrib_status, - "endOfRibRecv"); - else - vty_out(vty, "Yes\n"); - } else { - if (use_json) - json_object_boolean_false_add( - json_endofrib_status, - "endOfRibRecv"); - else - vty_out(vty, "No\n"); + if (CHECK_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_EOR_RECEIVED)) { + if (use_json) + json_object_boolean_true_add( + json_endofrib_status, "endOfRibRecv"); + else + vty_out(vty, "Yes\n"); + } else { + if (use_json) + json_object_boolean_false_add( + json_endofrib_status, "endOfRibRecv"); + else + vty_out(vty, "No\n"); + } + + if (use_json) { + json_object_int_add(json_timer, "stalePathTimer", + peer->bgp->stalepath_time); + + if (peer->t_gr_stale != NULL) { + json_object_int_add(json_timer, + "stalePathTimerRemaining", + thread_timer_remain_second( + peer->t_gr_stale)); } - if (use_json) { + /* Display Configured Selection + * Deferral only when when + * Gr mode is enabled. + */ + if (CHECK_FLAG(peer->flags, + PEER_FLAG_GRACEFUL_RESTART)) { json_object_int_add(json_timer, - "stalePathTimer", + "selectionDeferralTimer", peer->bgp->stalepath_time); + } - if (peer->t_gr_stale != NULL) { - json_object_int_add( - json_timer, - "stalePathTimerRemaining", - thread_timer_remain_second( - peer->t_gr_stale)); - } - - /* Display Configured Selection - * Deferral only when when - * Gr mode is enabled. - */ - if (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART)) { - json_object_int_add( - json_timer, - "selectionDeferralTimer", - peer->bgp->stalepath_time); - } + if (peer->bgp->gr_info[afi][safi].t_select_deferral != + NULL) { - if (peer->bgp->gr_info[afi][safi] - .t_select_deferral - != NULL) { + json_object_int_add( + json_timer, + "selectionDeferralTimerRemaining", + thread_timer_remain_second( + peer->bgp->gr_info[afi][safi] + .t_select_deferral)); + } + } else { + vty_out(vty, " Timers:\n"); + vty_out(vty, + " Configured Stale Path Time(sec): %u\n", + peer->bgp->stalepath_time); - json_object_int_add( - json_timer, - "selectionDeferralTimerRemaining", - thread_timer_remain_second( - peer->bgp - ->gr_info[afi] - [safi] - .t_select_deferral)); - } - } else { - vty_out(vty, " Timers:\n"); + if (peer->t_gr_stale != NULL) vty_out(vty, - " Configured Stale Path Time(sec): %u\n", - peer->bgp->stalepath_time); - - if (peer->t_gr_stale != NULL) - vty_out(vty, - " Stale Path Remaining(sec): %ld\n", - thread_timer_remain_second( - peer->t_gr_stale)); - /* Display Configured Selection - * Deferral only when when - * Gr mode is enabled. - */ - if (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART)) - vty_out(vty, - " Configured Selection Deferral Time(sec): %u\n", - peer->bgp->select_defer_time); + " Stale Path Remaining(sec): %ld\n", + thread_timer_remain_second( + peer->t_gr_stale)); + /* Display Configured Selection + * Deferral only when when + * Gr mode is enabled. + */ + if (CHECK_FLAG(peer->flags, PEER_FLAG_GRACEFUL_RESTART)) + vty_out(vty, + " Configured Selection Deferral Time(sec): %u\n", + peer->bgp->select_defer_time); - if (peer->bgp->gr_info[afi][safi] - .t_select_deferral - != NULL) - vty_out(vty, - " Selection Deferral Time Remaining(sec): %ld\n", - thread_timer_remain_second( - peer->bgp - ->gr_info[afi] - [safi] - .t_select_deferral)); - } - if (use_json) { - json_object_object_add(json_afi_safi, - "endOfRibStatus", - json_endofrib_status); - json_object_object_add(json_afi_safi, "timers", - json_timer); - json_object_object_add( - json, get_afi_safi_str(afi, safi, true), - json_afi_safi); - } + if (peer->bgp->gr_info[afi][safi].t_select_deferral != + NULL) + vty_out(vty, + " Selection Deferral Time Remaining(sec): %ld\n", + thread_timer_remain_second( + peer->bgp->gr_info[afi][safi] + .t_select_deferral)); + } + if (use_json) { + json_object_object_add(json_afi_safi, "endOfRibStatus", + json_endofrib_status); + json_object_object_add(json_afi_safi, "timers", + json_timer); + json_object_object_add( + json, get_afi_safi_str(afi, safi, true), + json_afi_safi); } } } @@ -12363,10 +12368,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 { @@ -12509,6 +12514,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) @@ -12581,1107 +12594,932 @@ 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)) { - if (p->cap || p->afc_adv[AFI_IP][SAFI_UNICAST] - || p->afc_recv[AFI_IP][SAFI_UNICAST] - || p->afc_adv[AFI_IP][SAFI_MULTICAST] - || p->afc_recv[AFI_IP][SAFI_MULTICAST] - || p->afc_adv[AFI_IP6][SAFI_UNICAST] - || p->afc_recv[AFI_IP6][SAFI_UNICAST] - || p->afc_adv[AFI_IP6][SAFI_MULTICAST] - || p->afc_recv[AFI_IP6][SAFI_MULTICAST] - || p->afc_adv[AFI_IP6][SAFI_MPLS_VPN] - || p->afc_recv[AFI_IP6][SAFI_MPLS_VPN] - || p->afc_adv[AFI_IP6][SAFI_ENCAP] - || p->afc_recv[AFI_IP6][SAFI_ENCAP] - || p->afc_adv[AFI_IP6][SAFI_FLOWSPEC] - || p->afc_recv[AFI_IP6][SAFI_FLOWSPEC] - || p->afc_adv[AFI_IP][SAFI_ENCAP] - || p->afc_recv[AFI_IP][SAFI_ENCAP] - || p->afc_adv[AFI_IP][SAFI_FLOWSPEC] - || p->afc_recv[AFI_IP][SAFI_FLOWSPEC] - || p->afc_adv[AFI_IP][SAFI_MPLS_VPN] - || p->afc_recv[AFI_IP][SAFI_MPLS_VPN]) { - if (use_json) { - json_object *json_cap = NULL; + if (peer_established(p) && + (p->cap || peer_afc_advertised(p) || peer_afc_received(p))) { + if (use_json) { + json_object *json_cap = NULL; - json_cap = json_object_new_object(); + json_cap = json_object_new_object(); - /* AS4 */ - if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV) - || CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) { - if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV) - && CHECK_FLAG(p->cap, - PEER_CAP_AS4_RCV)) - json_object_string_add( - json_cap, "4byteAs", - "advertisedAndReceived"); - else if (CHECK_FLAG(p->cap, - PEER_CAP_AS4_ADV)) - json_object_string_add( - json_cap, "4byteAs", - "advertised"); - else if (CHECK_FLAG(p->cap, - PEER_CAP_AS4_RCV)) - json_object_string_add( - json_cap, "4byteAs", - "received"); - } - - /* Extended Message Support */ - if (CHECK_FLAG(p->cap, - PEER_CAP_EXTENDED_MESSAGE_ADV) - && CHECK_FLAG( - p->cap, - PEER_CAP_EXTENDED_MESSAGE_RCV)) + /* AS4 */ + if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) { + if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV) && + CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV)) json_object_string_add( - json_cap, "extendedMessage", + json_cap, "4byteAs", "advertisedAndReceived"); - else if (CHECK_FLAG( - p->cap, - PEER_CAP_EXTENDED_MESSAGE_ADV)) - json_object_string_add( - json_cap, "extendedMessage", - "advertised"); - else if (CHECK_FLAG( - p->cap, - PEER_CAP_EXTENDED_MESSAGE_RCV)) - json_object_string_add( - json_cap, "extendedMessage", - "received"); + else if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) + json_object_string_add(json_cap, + "4byteAs", + "advertised"); + else if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV)) + json_object_string_add(json_cap, + "4byteAs", + "received"); + } - /* AddPath */ - if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) - || CHECK_FLAG(p->cap, - PEER_CAP_ADDPATH_ADV)) { - json_object *json_add = NULL; - const char *print_store; + /* Extended Message Support */ + if (CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_ADV) && + CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_RCV)) + json_object_string_add(json_cap, + "extendedMessage", + "advertisedAndReceived"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_EXTENDED_MESSAGE_ADV)) + json_object_string_add(json_cap, + "extendedMessage", + "advertised"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_EXTENDED_MESSAGE_RCV)) + json_object_string_add(json_cap, + "extendedMessage", + "received"); - json_add = json_object_new_object(); + /* AddPath */ + if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_ADV)) { + json_object *json_add = NULL; + const char *print_store; - FOREACH_AFI_SAFI (afi, safi) { - json_object *json_sub = NULL; - json_sub = - json_object_new_object(); - print_store = get_afi_safi_str( - afi, safi, true); + json_add = json_object_new_object(); + + FOREACH_AFI_SAFI (afi, safi) { + json_object *json_sub = NULL; + json_sub = json_object_new_object(); + print_store = get_afi_safi_str( + afi, safi, true); + if (CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_ADV) || + CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV)) { if (CHECK_FLAG( p->af_cap[afi] [safi], - PEER_CAP_ADDPATH_AF_TX_ADV) - || CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV)) { - if (CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_ADV) - && CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV)) - json_object_boolean_true_add( - json_sub, - "txAdvertisedAndReceived"); - else if ( - CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_ADV)) - json_object_boolean_true_add( - json_sub, - "txAdvertised"); - else if ( - CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV)) - json_object_boolean_true_add( - json_sub, - "txReceived"); - } - - if (CHECK_FLAG( + PEER_CAP_ADDPATH_AF_TX_ADV) && + CHECK_FLAG( p->af_cap[afi] [safi], - PEER_CAP_ADDPATH_AF_RX_ADV) - || CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) { - if (CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_ADV) - && CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) - json_object_boolean_true_add( - json_sub, - "rxAdvertisedAndReceived"); - else if ( - CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_ADV)) - json_object_boolean_true_add( - json_sub, - "rxAdvertised"); - else if ( - CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) - json_object_boolean_true_add( - json_sub, - "rxReceived"); - } + PEER_CAP_ADDPATH_AF_TX_RCV)) + json_object_boolean_true_add( + json_sub, + "txAdvertisedAndReceived"); + else if ( + CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_ADV)) + json_object_boolean_true_add( + json_sub, + "txAdvertised"); + else if ( + CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_RCV)) + json_object_boolean_true_add( + json_sub, + "txReceived"); + } + if (CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_ADV) || + CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV)) { if (CHECK_FLAG( p->af_cap[afi] [safi], - PEER_CAP_ADDPATH_AF_TX_ADV) - || CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV) - || CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_ADV) - || CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) - json_object_object_add( - json_add, - print_store, - json_sub); - else - json_object_free( - json_sub); + PEER_CAP_ADDPATH_AF_RX_ADV) && + CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_RCV)) + json_object_boolean_true_add( + json_sub, + "rxAdvertisedAndReceived"); + else if ( + CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_ADV)) + json_object_boolean_true_add( + json_sub, + "rxAdvertised"); + else if ( + CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_RCV)) + json_object_boolean_true_add( + json_sub, + "rxReceived"); } - json_object_object_add( - json_cap, "addPath", json_add); + if (CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_ADV) || + CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV) || + CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_ADV) || + CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV)) + json_object_object_add( + json_add, print_store, + json_sub); + else + json_object_free(json_sub); } - /* Dynamic */ - if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) - || CHECK_FLAG(p->cap, - PEER_CAP_DYNAMIC_ADV)) { - if (CHECK_FLAG(p->cap, - PEER_CAP_DYNAMIC_ADV) - && CHECK_FLAG(p->cap, - PEER_CAP_DYNAMIC_RCV)) - json_object_string_add( - json_cap, "dynamic", - "advertisedAndReceived"); - else if (CHECK_FLAG( - p->cap, - PEER_CAP_DYNAMIC_ADV)) - json_object_string_add( - json_cap, "dynamic", - "advertised"); - else if (CHECK_FLAG( - p->cap, - PEER_CAP_DYNAMIC_RCV)) - json_object_string_add( - json_cap, "dynamic", - "received"); - } + json_object_object_add(json_cap, "addPath", + json_add); + } + + /* Dynamic */ + if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) { + if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV) && + CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV)) + json_object_string_add( + json_cap, "dynamic", + "advertisedAndReceived"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_DYNAMIC_ADV)) + json_object_string_add(json_cap, + "dynamic", + "advertised"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_DYNAMIC_RCV)) + json_object_string_add(json_cap, + "dynamic", + "received"); + } - /* Extended nexthop */ - if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV) - || CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) { - json_object *json_nxt = NULL; - const char *print_store; + /* Extended nexthop */ + if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) { + json_object *json_nxt = NULL; + const char *print_store; - if (CHECK_FLAG(p->cap, - PEER_CAP_ENHE_ADV) - && CHECK_FLAG(p->cap, - PEER_CAP_ENHE_RCV)) - json_object_string_add( - json_cap, - "extendedNexthop", - "advertisedAndReceived"); - else if (CHECK_FLAG(p->cap, - PEER_CAP_ENHE_ADV)) - json_object_string_add( - json_cap, - "extendedNexthop", - "advertised"); - else if (CHECK_FLAG(p->cap, - PEER_CAP_ENHE_RCV)) - json_object_string_add( - json_cap, - "extendedNexthop", - "received"); + if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV) && + CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)) + json_object_string_add( + json_cap, "extendedNexthop", + "advertisedAndReceived"); + else if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) + json_object_string_add( + json_cap, "extendedNexthop", + "advertised"); + else if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)) + json_object_string_add( + json_cap, "extendedNexthop", + "received"); - if (CHECK_FLAG(p->cap, - PEER_CAP_ENHE_RCV)) { - json_nxt = - json_object_new_object(); + if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)) { + json_nxt = json_object_new_object(); - for (safi = SAFI_UNICAST; - safi < SAFI_MAX; safi++) { - if (CHECK_FLAG( - p->af_cap - [AFI_IP] - [safi], - PEER_CAP_ENHE_AF_RCV)) { - print_store = get_afi_safi_str( + for (safi = SAFI_UNICAST; + safi < SAFI_MAX; safi++) { + if (CHECK_FLAG( + p->af_cap[AFI_IP] + [safi], + PEER_CAP_ENHE_AF_RCV)) { + print_store = + get_afi_safi_str( AFI_IP, - safi, true); - json_object_string_add( - json_nxt, - print_store, - "recieved"); /* misspelled for compatibility */ - } + safi, + true); + json_object_string_add( + json_nxt, + print_store, + "recieved"); /* misspelled for compatibility */ } - json_object_object_add( - json_cap, - "extendedNexthopFamililesByPeer", - json_nxt); } + json_object_object_add( + json_cap, + "extendedNexthopFamililesByPeer", + json_nxt); } + } - /* 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; + /* 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_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(); + 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( + 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_string_add( + json_llgr, + afi_safi_str, + "received"); } - json_object_object_add( - json_cap, - "longLivedGracefulRestartByPeer", - json_llgr); } + json_object_object_add( + json_cap, + "longLivedGracefulRestartByPeer", + json_llgr); } + } - /* Route Refresh */ - if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) - || CHECK_FLAG(p->cap, - PEER_CAP_REFRESH_NEW_RCV) - || CHECK_FLAG(p->cap, - PEER_CAP_REFRESH_OLD_RCV)) { - if (CHECK_FLAG(p->cap, - PEER_CAP_REFRESH_ADV) - && (CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_NEW_RCV) - || CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_OLD_RCV))) { + /* Route Refresh */ + if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) || + CHECK_FLAG(p->cap, PEER_CAP_REFRESH_NEW_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_REFRESH_OLD_RCV)) { + if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) && + (CHECK_FLAG(p->cap, + PEER_CAP_REFRESH_NEW_RCV) || + CHECK_FLAG(p->cap, + PEER_CAP_REFRESH_OLD_RCV))) { + if (CHECK_FLAG( + p->cap, + PEER_CAP_REFRESH_OLD_RCV) && + CHECK_FLAG( + p->cap, + PEER_CAP_REFRESH_NEW_RCV)) + json_object_string_add( + json_cap, + "routeRefresh", + "advertisedAndReceivedOldNew"); + else { if (CHECK_FLAG( p->cap, - PEER_CAP_REFRESH_OLD_RCV) - && CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_NEW_RCV)) + PEER_CAP_REFRESH_OLD_RCV)) json_object_string_add( json_cap, "routeRefresh", - "advertisedAndReceivedOldNew"); - else { - if (CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_OLD_RCV)) - json_object_string_add( - json_cap, - "routeRefresh", - "advertisedAndReceivedOld"); - else - json_object_string_add( - json_cap, - "routeRefresh", - "advertisedAndReceivedNew"); - } - } else if ( - CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_ADV)) - json_object_string_add( - json_cap, - "routeRefresh", - "advertised"); - else if ( - CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_NEW_RCV) - || CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_OLD_RCV)) - json_object_string_add( - json_cap, - "routeRefresh", - "received"); - } + "advertisedAndReceivedOld"); + else + json_object_string_add( + json_cap, + "routeRefresh", + "advertisedAndReceivedNew"); + } + } else if (CHECK_FLAG(p->cap, + PEER_CAP_REFRESH_ADV)) + json_object_string_add(json_cap, + "routeRefresh", + "advertised"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_REFRESH_NEW_RCV) || + CHECK_FLAG(p->cap, + PEER_CAP_REFRESH_OLD_RCV)) + json_object_string_add(json_cap, + "routeRefresh", + "received"); + } - /* Enhanced Route Refresh */ - if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV) - || CHECK_FLAG(p->cap, - PEER_CAP_ENHANCED_RR_RCV)) { - if (CHECK_FLAG(p->cap, - PEER_CAP_ENHANCED_RR_ADV) - && CHECK_FLAG( - p->cap, + /* Enhanced Route Refresh */ + if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV) || + CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_RCV)) { + if (CHECK_FLAG(p->cap, + PEER_CAP_ENHANCED_RR_ADV) && + CHECK_FLAG(p->cap, + PEER_CAP_ENHANCED_RR_RCV)) + json_object_string_add( + json_cap, + "enhancedRouteRefresh", + "advertisedAndReceived"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_ENHANCED_RR_ADV)) + json_object_string_add( + json_cap, + "enhancedRouteRefresh", + "advertised"); + else if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_RCV)) - json_object_string_add( - json_cap, - "enhancedRouteRefresh", + json_object_string_add( + json_cap, + "enhancedRouteRefresh", + "received"); + } + + /* Multiprotocol Extensions */ + json_object *json_multi = NULL; + + json_multi = json_object_new_object(); + + FOREACH_AFI_SAFI (afi, safi) { + if (p->afc_adv[afi][safi] || + p->afc_recv[afi][safi]) { + json_object *json_exten = NULL; + json_exten = json_object_new_object(); + + if (p->afc_adv[afi][safi] && + p->afc_recv[afi][safi]) + json_object_boolean_true_add( + json_exten, "advertisedAndReceived"); - else if ( - CHECK_FLAG( - p->cap, - PEER_CAP_ENHANCED_RR_ADV)) - json_object_string_add( - json_cap, - "enhancedRouteRefresh", + else if (p->afc_adv[afi][safi]) + json_object_boolean_true_add( + json_exten, "advertised"); - else if ( - CHECK_FLAG( - p->cap, - PEER_CAP_ENHANCED_RR_RCV)) - json_object_string_add( - json_cap, - "enhancedRouteRefresh", - "received"); + else if (p->afc_recv[afi][safi]) + json_object_boolean_true_add( + json_exten, "received"); + + json_object_object_add( + json_multi, + get_afi_safi_str(afi, safi, + true), + json_exten); } + } + json_object_object_add(json_cap, + "multiprotocolExtensions", + json_multi); - /* Multiprotocol Extensions */ - json_object *json_multi = NULL; - json_multi = json_object_new_object(); + /* Hostname capabilities */ + json_object *json_hname = NULL; - FOREACH_AFI_SAFI (afi, safi) { - if (p->afc_adv[afi][safi] - || p->afc_recv[afi][safi]) { - json_object *json_exten = NULL; - json_exten = - json_object_new_object(); - - if (p->afc_adv[afi][safi] - && p->afc_recv[afi][safi]) - json_object_boolean_true_add( - json_exten, - "advertisedAndReceived"); - else if (p->afc_adv[afi][safi]) - json_object_boolean_true_add( - json_exten, - "advertised"); - else if (p->afc_recv[afi][safi]) - json_object_boolean_true_add( - json_exten, - "received"); - - json_object_object_add( - json_multi, - get_afi_safi_str(afi, - safi, - true), - json_exten); - } - } - json_object_object_add( - json_cap, "multiprotocolExtensions", - json_multi); + json_hname = json_object_new_object(); - /* Hostname capabilities */ - json_object *json_hname = NULL; + if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) { + json_object_string_add( + json_hname, "advHostName", + bgp->peer_self->hostname + ? bgp->peer_self->hostname + : "n/a"); + json_object_string_add( + json_hname, "advDomainName", + bgp->peer_self->domainname + ? bgp->peer_self->domainname + : "n/a"); + } - json_hname = json_object_new_object(); - if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) { - json_object_string_add( - json_hname, "advHostName", - bgp->peer_self->hostname - ? bgp->peer_self - ->hostname - : "n/a"); - json_object_string_add( - json_hname, "advDomainName", - bgp->peer_self->domainname - ? bgp->peer_self - ->domainname - : "n/a"); - } + if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) { + json_object_string_add( + json_hname, "rcvHostName", + p->hostname ? p->hostname : "n/a"); + json_object_string_add( + json_hname, "rcvDomainName", + p->domainname ? p->domainname : "n/a"); + } + json_object_object_add(json_cap, "hostName", + json_hname); - if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) { + /* Gracefull Restart */ + if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) { + if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) && + CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) json_object_string_add( - json_hname, "rcvHostName", - p->hostname ? p->hostname - : "n/a"); + json_cap, "gracefulRestart", + "advertisedAndReceived"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_RESTART_ADV)) json_object_string_add( - json_hname, "rcvDomainName", - p->domainname ? p->domainname - : "n/a"); - } + json_cap, + "gracefulRestartCapability", + "advertised"); + else if (CHECK_FLAG(p->cap, + PEER_CAP_RESTART_RCV)) + json_object_string_add( + json_cap, + "gracefulRestartCapability", + "received"); - json_object_object_add(json_cap, "hostName", - json_hname); - - /* Gracefull Restart */ - if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) - || CHECK_FLAG(p->cap, - PEER_CAP_RESTART_ADV)) { - if (CHECK_FLAG(p->cap, - PEER_CAP_RESTART_ADV) - && CHECK_FLAG(p->cap, - PEER_CAP_RESTART_RCV)) - json_object_string_add( - json_cap, - "gracefulRestart", - "advertisedAndReceived"); - else if (CHECK_FLAG( - p->cap, - PEER_CAP_RESTART_ADV)) - json_object_string_add( - json_cap, - "gracefulRestartCapability", - "advertised"); - else if (CHECK_FLAG( - p->cap, - PEER_CAP_RESTART_RCV)) - json_object_string_add( - json_cap, - "gracefulRestartCapability", - "received"); + if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { + int restart_af_count = 0; + json_object *json_restart = NULL; + json_restart = json_object_new_object(); - if (CHECK_FLAG(p->cap, - PEER_CAP_RESTART_RCV)) { - int restart_af_count = 0; - json_object *json_restart = - NULL; - json_restart = - json_object_new_object(); + json_object_int_add( + json_cap, + "gracefulRestartRemoteTimerMsecs", + p->v_gr_restart * 1000); - json_object_int_add( - json_cap, - "gracefulRestartRemoteTimerMsecs", - p->v_gr_restart * 1000); + FOREACH_AFI_SAFI (afi, safi) { + if (CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_RESTART_AF_RCV)) { + json_object *json_sub = + NULL; + json_sub = + json_object_new_object(); - FOREACH_AFI_SAFI (afi, safi) { if (CHECK_FLAG( p->af_cap [afi] [safi], - PEER_CAP_RESTART_AF_RCV)) { - json_object * - json_sub = - NULL; - json_sub = - json_object_new_object(); - - if (CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_RESTART_AF_PRESERVE_RCV)) - json_object_boolean_true_add( - json_sub, - "preserved"); - restart_af_count++; - json_object_object_add( - json_restart, - get_afi_safi_str( - afi, - safi, - true), - json_sub); - } - } - if (!restart_af_count) { - json_object_string_add( - json_cap, - "addressFamiliesByPeer", - "none"); - json_object_free( - json_restart); - } else + PEER_CAP_RESTART_AF_PRESERVE_RCV)) + json_object_boolean_true_add( + json_sub, + "preserved"); + restart_af_count++; json_object_object_add( - json_cap, - "addressFamiliesByPeer", - json_restart); + json_restart, + get_afi_safi_str( + afi, + safi, + true), + json_sub); + } } + if (!restart_af_count) { + json_object_string_add( + json_cap, + "addressFamiliesByPeer", + "none"); + json_object_free(json_restart); + } else + json_object_object_add( + json_cap, + "addressFamiliesByPeer", + json_restart); } - json_object_object_add(json_neigh, - "neighborCapabilities", - json_cap); - } else { - vty_out(vty, " Neighbor capabilities:\n"); - - /* AS4 */ - if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV) - || CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) { - vty_out(vty, " 4 Byte AS:"); - if (CHECK_FLAG(p->cap, - PEER_CAP_AS4_ADV)) - vty_out(vty, " advertised"); - if (CHECK_FLAG(p->cap, - PEER_CAP_AS4_RCV)) - vty_out(vty, " %sreceived", - CHECK_FLAG( - p->cap, - PEER_CAP_AS4_ADV) - ? "and " - : ""); - vty_out(vty, "\n"); - } + } + json_object_object_add( + json_neigh, "neighborCapabilities", json_cap); + } else { + vty_out(vty, " Neighbor capabilities:\n"); + + /* AS4 */ + if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) { + vty_out(vty, " 4 Byte AS:"); + if (CHECK_FLAG(p->cap, PEER_CAP_AS4_ADV)) + vty_out(vty, " advertised"); + if (CHECK_FLAG(p->cap, PEER_CAP_AS4_RCV)) + vty_out(vty, " %sreceived", + CHECK_FLAG(p->cap, + PEER_CAP_AS4_ADV) + ? "and " + : ""); + vty_out(vty, "\n"); + } - /* Extended Message Support */ + /* Extended Message Support */ + if (CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_EXTENDED_MESSAGE_ADV)) { + vty_out(vty, " Extended Message:"); if (CHECK_FLAG(p->cap, - PEER_CAP_EXTENDED_MESSAGE_RCV) - || CHECK_FLAG( - p->cap, - PEER_CAP_EXTENDED_MESSAGE_ADV)) { - vty_out(vty, " Extended Message:"); - if (CHECK_FLAG( - p->cap, - PEER_CAP_EXTENDED_MESSAGE_ADV)) - vty_out(vty, " advertised"); + PEER_CAP_EXTENDED_MESSAGE_ADV)) + vty_out(vty, " advertised"); + if (CHECK_FLAG(p->cap, + PEER_CAP_EXTENDED_MESSAGE_RCV)) + vty_out(vty, " %sreceived", + CHECK_FLAG( + p->cap, + PEER_CAP_EXTENDED_MESSAGE_ADV) + ? "and " + : ""); + vty_out(vty, "\n"); + } + + /* AddPath */ + if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_ADV)) { + vty_out(vty, " AddPath:\n"); + + FOREACH_AFI_SAFI (afi, safi) { if (CHECK_FLAG( - p->cap, - PEER_CAP_EXTENDED_MESSAGE_RCV)) - vty_out(vty, " %sreceived", - CHECK_FLAG( - p->cap, - PEER_CAP_EXTENDED_MESSAGE_ADV) - ? "and " - : ""); - vty_out(vty, "\n"); - } + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_ADV) || + CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_TX_RCV)) { + vty_out(vty, " %s: TX ", + get_afi_safi_str( + afi, safi, + false)); - /* AddPath */ - if (CHECK_FLAG(p->cap, PEER_CAP_ADDPATH_RCV) - || CHECK_FLAG(p->cap, - PEER_CAP_ADDPATH_ADV)) { - vty_out(vty, " AddPath:\n"); + if (CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_ADV)) + vty_out(vty, + "advertised"); - FOREACH_AFI_SAFI (afi, safi) { if (CHECK_FLAG( p->af_cap[afi] [safi], - PEER_CAP_ADDPATH_AF_TX_ADV) - || CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV)) { + PEER_CAP_ADDPATH_AF_TX_RCV)) vty_out(vty, - " %s: TX ", - get_afi_safi_str( - afi, - safi, - false)); + "%sreceived", + CHECK_FLAG( + p->af_cap + [afi] + [safi], + PEER_CAP_ADDPATH_AF_TX_ADV) + ? " and " + : ""); - if (CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_ADV)) - vty_out(vty, - "advertised"); + vty_out(vty, "\n"); + } - if (CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_RCV)) - vty_out(vty, - "%sreceived", - CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_TX_ADV) - ? " and " - : ""); - - vty_out(vty, "\n"); - } + if (CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_ADV) || + CHECK_FLAG( + p->af_cap[afi][safi], + PEER_CAP_ADDPATH_AF_RX_RCV)) { + vty_out(vty, " %s: RX ", + get_afi_safi_str( + afi, safi, + false)); if (CHECK_FLAG( p->af_cap[afi] [safi], - PEER_CAP_ADDPATH_AF_RX_ADV) - || CHECK_FLAG( - p->af_cap[afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) { + PEER_CAP_ADDPATH_AF_RX_ADV)) vty_out(vty, - " %s: RX ", - get_afi_safi_str( - afi, - safi, - false)); + "advertised"); - if (CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_ADV)) - vty_out(vty, - "advertised"); + if (CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_RCV)) + vty_out(vty, + "%sreceived", + CHECK_FLAG( + p->af_cap + [afi] + [safi], + PEER_CAP_ADDPATH_AF_RX_ADV) + ? " and " + : ""); - if (CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_RCV)) - vty_out(vty, - "%sreceived", - CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_ADDPATH_AF_RX_ADV) - ? " and " - : ""); - - vty_out(vty, "\n"); - } + vty_out(vty, "\n"); } } + } - /* Dynamic */ - if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) - || CHECK_FLAG(p->cap, - PEER_CAP_DYNAMIC_ADV)) { - vty_out(vty, " Dynamic:"); - if (CHECK_FLAG(p->cap, - PEER_CAP_DYNAMIC_ADV)) - vty_out(vty, " advertised"); - if (CHECK_FLAG(p->cap, - PEER_CAP_DYNAMIC_RCV)) - vty_out(vty, " %sreceived", - CHECK_FLAG( - p->cap, - PEER_CAP_DYNAMIC_ADV) - ? "and " - : ""); - vty_out(vty, "\n"); - } + /* Dynamic */ + if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) { + vty_out(vty, " Dynamic:"); + if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_ADV)) + vty_out(vty, " advertised"); + if (CHECK_FLAG(p->cap, PEER_CAP_DYNAMIC_RCV)) + vty_out(vty, " %sreceived", + CHECK_FLAG(p->cap, + PEER_CAP_DYNAMIC_ADV) + ? "and " + : ""); + vty_out(vty, "\n"); + } - /* Extended nexthop */ - if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV) - || CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) { - vty_out(vty, " Extended nexthop:"); - if (CHECK_FLAG(p->cap, - PEER_CAP_ENHE_ADV)) - vty_out(vty, " advertised"); - if (CHECK_FLAG(p->cap, - PEER_CAP_ENHE_RCV)) - vty_out(vty, " %sreceived", - CHECK_FLAG( - p->cap, - PEER_CAP_ENHE_ADV) - ? "and " - : ""); - vty_out(vty, "\n"); + /* Extended nexthop */ + if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) { + vty_out(vty, " Extended nexthop:"); + if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_ADV)) + vty_out(vty, " advertised"); + if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)) + vty_out(vty, " %sreceived", + CHECK_FLAG(p->cap, + PEER_CAP_ENHE_ADV) + ? "and " + : ""); + vty_out(vty, "\n"); - if (CHECK_FLAG(p->cap, - PEER_CAP_ENHE_RCV)) { - vty_out(vty, - " Address families by peer:\n "); - for (safi = SAFI_UNICAST; - safi < SAFI_MAX; safi++) - if (CHECK_FLAG( - p->af_cap - [AFI_IP] - [safi], - PEER_CAP_ENHE_AF_RCV)) - vty_out(vty, - " %s\n", - get_afi_safi_str( - AFI_IP, - safi, - false)); - } + if (CHECK_FLAG(p->cap, PEER_CAP_ENHE_RCV)) { + vty_out(vty, + " Address families by peer:\n "); + for (safi = SAFI_UNICAST; + safi < SAFI_MAX; safi++) + if (CHECK_FLAG( + p->af_cap[AFI_IP] + [safi], + PEER_CAP_ENHE_AF_RCV)) + vty_out(vty, + " %s\n", + get_afi_safi_str( + AFI_IP, + safi, + false)); } + } - /* 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"); + /* 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)); - } + 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, - PEER_CAP_REFRESH_NEW_RCV) - || CHECK_FLAG(p->cap, - PEER_CAP_REFRESH_OLD_RCV)) { - vty_out(vty, " Route refresh:"); - if (CHECK_FLAG(p->cap, - PEER_CAP_REFRESH_ADV)) - vty_out(vty, " advertised"); - if (CHECK_FLAG(p->cap, - PEER_CAP_REFRESH_NEW_RCV) - || CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_OLD_RCV)) - vty_out(vty, " %sreceived(%s)", - CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_ADV) - ? "and " - : "", - (CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_OLD_RCV) - && CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_NEW_RCV)) - ? "old & new" - : CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_OLD_RCV) - ? "old" - : "new"); + /* Route Refresh */ + if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV) || + CHECK_FLAG(p->cap, PEER_CAP_REFRESH_NEW_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_REFRESH_OLD_RCV)) { + vty_out(vty, " Route refresh:"); + if (CHECK_FLAG(p->cap, PEER_CAP_REFRESH_ADV)) + vty_out(vty, " advertised"); + if (CHECK_FLAG(p->cap, + PEER_CAP_REFRESH_NEW_RCV) || + CHECK_FLAG(p->cap, + PEER_CAP_REFRESH_OLD_RCV)) + vty_out(vty, " %sreceived(%s)", + CHECK_FLAG(p->cap, + PEER_CAP_REFRESH_ADV) + ? "and " + : "", + (CHECK_FLAG( + p->cap, + PEER_CAP_REFRESH_OLD_RCV) && + CHECK_FLAG( + p->cap, + PEER_CAP_REFRESH_NEW_RCV)) + ? "old & new" + : CHECK_FLAG( + p->cap, + PEER_CAP_REFRESH_OLD_RCV) + ? "old" + : "new"); - vty_out(vty, "\n"); - } + vty_out(vty, "\n"); + } - /* Enhanced Route Refresh */ - if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV) - || CHECK_FLAG(p->cap, - PEER_CAP_ENHANCED_RR_RCV)) { - vty_out(vty, - " Enhanced Route Refresh:"); - if (CHECK_FLAG( - p->cap, - PEER_CAP_ENHANCED_RR_ADV)) + /* Enhanced Route Refresh */ + if (CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_ADV) || + CHECK_FLAG(p->cap, PEER_CAP_ENHANCED_RR_RCV)) { + vty_out(vty, " Enhanced Route Refresh:"); + if (CHECK_FLAG(p->cap, + PEER_CAP_ENHANCED_RR_ADV)) + vty_out(vty, " advertised"); + if (CHECK_FLAG(p->cap, + PEER_CAP_ENHANCED_RR_RCV)) + vty_out(vty, " %sreceived", + CHECK_FLAG(p->cap, + PEER_CAP_REFRESH_ADV) + ? "and " + : ""); + vty_out(vty, "\n"); + } + + /* Multiprotocol Extensions */ + FOREACH_AFI_SAFI (afi, safi) + if (p->afc_adv[afi][safi] || + p->afc_recv[afi][safi]) { + vty_out(vty, " Address Family %s:", + get_afi_safi_str(afi, safi, + false)); + if (p->afc_adv[afi][safi]) vty_out(vty, " advertised"); - if (CHECK_FLAG( - p->cap, - PEER_CAP_ENHANCED_RR_RCV)) + if (p->afc_recv[afi][safi]) vty_out(vty, " %sreceived", - CHECK_FLAG( - p->cap, - PEER_CAP_REFRESH_ADV) + p->afc_adv[afi][safi] ? "and " : ""); vty_out(vty, "\n"); } - /* Multiprotocol Extensions */ - FOREACH_AFI_SAFI (afi, safi) - if (p->afc_adv[afi][safi] - || p->afc_recv[afi][safi]) { - vty_out(vty, - " Address Family %s:", - get_afi_safi_str( - afi, - safi, - false)); - if (p->afc_adv[afi][safi]) - vty_out(vty, - " advertised"); - if (p->afc_recv[afi][safi]) - vty_out(vty, - " %sreceived", - p->afc_adv[afi] - [safi] - ? "and " - : ""); - vty_out(vty, "\n"); - } + /* Hostname capability */ + vty_out(vty, " Hostname Capability:"); - /* Hostname capability */ - vty_out(vty, " Hostname Capability:"); + if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) { + vty_out(vty, + " advertised (name: %s,domain name: %s)", + bgp->peer_self->hostname + ? bgp->peer_self->hostname + : "n/a", + bgp->peer_self->domainname + ? bgp->peer_self->domainname + : "n/a"); + } else { + vty_out(vty, " not advertised"); + } - if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_ADV)) { - vty_out(vty, - " advertised (name: %s,domain name: %s)", - bgp->peer_self->hostname - ? bgp->peer_self - ->hostname - : "n/a", - bgp->peer_self->domainname - ? bgp->peer_self - ->domainname - : "n/a"); - } else { - vty_out(vty, " not advertised"); - } + if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) { + vty_out(vty, + " received (name: %s,domain name: %s)", + p->hostname ? p->hostname : "n/a", + p->domainname ? p->domainname : "n/a"); + } else { + vty_out(vty, " not received"); + } - if (CHECK_FLAG(p->cap, PEER_CAP_HOSTNAME_RCV)) { - vty_out(vty, - " received (name: %s,domain name: %s)", - p->hostname ? p->hostname - : "n/a", - p->domainname ? p->domainname - : "n/a"); - } else { - vty_out(vty, " not received"); - } + vty_out(vty, "\n"); + /* Graceful Restart */ + if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) || + CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) { + vty_out(vty, + " Graceful Restart Capability:"); + if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) + vty_out(vty, " advertised"); + if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) + vty_out(vty, " %sreceived", + CHECK_FLAG(p->cap, + PEER_CAP_RESTART_ADV) + ? "and " + : ""); vty_out(vty, "\n"); - /* Graceful Restart */ - if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) - || CHECK_FLAG(p->cap, - PEER_CAP_RESTART_ADV)) { - vty_out(vty, - " Graceful Restart Capability:"); - if (CHECK_FLAG(p->cap, - PEER_CAP_RESTART_ADV)) - vty_out(vty, " advertised"); - if (CHECK_FLAG(p->cap, - PEER_CAP_RESTART_RCV)) - vty_out(vty, " %sreceived", - CHECK_FLAG( - p->cap, - PEER_CAP_RESTART_ADV) - ? "and " - : ""); - vty_out(vty, "\n"); - - if (CHECK_FLAG(p->cap, - PEER_CAP_RESTART_RCV)) { - int restart_af_count = 0; + if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { + int restart_af_count = 0; - vty_out(vty, - " Remote Restart timer is %d seconds\n", - p->v_gr_restart); - vty_out(vty, - " Address families by peer:\n "); + vty_out(vty, + " Remote Restart timer is %d seconds\n", + p->v_gr_restart); + vty_out(vty, + " Address families by peer:\n "); - FOREACH_AFI_SAFI (afi, safi) - if (CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_RESTART_AF_RCV)) { - vty_out(vty, - "%s%s(%s)", - restart_af_count - ? ", " - : "", - get_afi_safi_str( - afi, - safi, - false), - CHECK_FLAG( - p->af_cap - [afi] - [safi], - PEER_CAP_RESTART_AF_PRESERVE_RCV) - ? "preserved" - : "not preserved"); - restart_af_count++; - } - if (!restart_af_count) - vty_out(vty, "none"); - vty_out(vty, "\n"); - } - } /* Gracefull Restart */ - } + FOREACH_AFI_SAFI (afi, safi) + if (CHECK_FLAG( + p->af_cap[afi] + [safi], + PEER_CAP_RESTART_AF_RCV)) { + vty_out(vty, "%s%s(%s)", + restart_af_count + ? ", " + : "", + get_afi_safi_str( + afi, + safi, + false), + CHECK_FLAG( + p->af_cap + [afi] + [safi], + PEER_CAP_RESTART_AF_PRESERVE_RCV) + ? "preserved" + : "not preserved"); + restart_af_count++; + } + if (!restart_af_count) + vty_out(vty, "none"); + vty_out(vty, "\n"); + } + } /* Gracefull Restart */ } } /* graceful restart information */ - json_object *json_grace = NULL; - json_object *json_grace_send = NULL; - json_object *json_grace_recv = NULL; - int eor_send_af_count = 0; - int eor_receive_af_count = 0; - - if (use_json) { - json_grace = json_object_new_object(); - json_grace_send = json_object_new_object(); - json_grace_recv = json_object_new_object(); + json_object *json_grace = NULL; + json_object *json_grace_send = NULL; + json_object *json_grace_recv = NULL; + int eor_send_af_count = 0; + int eor_receive_af_count = 0; - if ((peer_established(p)) - && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { - FOREACH_AFI_SAFI (afi, safi) { - if (CHECK_FLAG(p->af_sflags[afi][safi], - PEER_STATUS_EOR_SEND)) { - json_object_boolean_true_add( - json_grace_send, - get_afi_safi_str(afi, - safi, - true)); - eor_send_af_count++; - } + if (use_json) { + json_grace = json_object_new_object(); + json_grace_send = json_object_new_object(); + json_grace_recv = json_object_new_object(); + + if ((peer_established(p)) && + CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { + FOREACH_AFI_SAFI (afi, safi) { + if (CHECK_FLAG(p->af_sflags[afi][safi], + PEER_STATUS_EOR_SEND)) { + json_object_boolean_true_add( + json_grace_send, + get_afi_safi_str(afi, safi, + true)); + eor_send_af_count++; } - FOREACH_AFI_SAFI (afi, safi) { - if (CHECK_FLAG( - p->af_sflags[afi][safi], - PEER_STATUS_EOR_RECEIVED)) { - json_object_boolean_true_add( - json_grace_recv, - get_afi_safi_str(afi, - safi, - true)); - eor_receive_af_count++; - } + } + FOREACH_AFI_SAFI (afi, safi) { + if (CHECK_FLAG(p->af_sflags[afi][safi], + PEER_STATUS_EOR_RECEIVED)) { + json_object_boolean_true_add( + json_grace_recv, + get_afi_safi_str(afi, safi, + true)); + eor_receive_af_count++; } } - json_object_object_add(json_grace, "endOfRibSend", - json_grace_send); - json_object_object_add(json_grace, "endOfRibRecv", - json_grace_recv); - + } + json_object_object_add(json_grace, "endOfRibSend", + json_grace_send); + json_object_object_add(json_grace, "endOfRibRecv", + json_grace_recv); - if (p->t_gr_restart) - json_object_int_add(json_grace, - "gracefulRestartTimerMsecs", - thread_timer_remain_second( - p->t_gr_restart) - * 1000); - if (p->t_gr_stale) - json_object_int_add( - json_grace, - "gracefulStalepathTimerMsecs", - thread_timer_remain_second( - p->t_gr_stale) - * 1000); - /* more gr info in new format */ - BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, - json_grace); - json_object_object_add( - json_neigh, "gracefulRestartInfo", json_grace); - } else { - vty_out(vty, " Graceful restart information:\n"); - if ((peer_established(p)) - && CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { + if (p->t_gr_restart) + json_object_int_add( + json_grace, "gracefulRestartTimerMsecs", + thread_timer_remain_second(p->t_gr_restart) * + 1000); - vty_out(vty, " End-of-RIB send: "); - FOREACH_AFI_SAFI (afi, safi) { - if (CHECK_FLAG(p->af_sflags[afi][safi], - PEER_STATUS_EOR_SEND)) { - vty_out(vty, "%s%s", - eor_send_af_count ? ", " - : "", - get_afi_safi_str( - afi, safi, - false)); - eor_send_af_count++; - } + if (p->t_gr_stale) + json_object_int_add( + json_grace, "gracefulStalepathTimerMsecs", + thread_timer_remain_second(p->t_gr_stale) * + 1000); + /* more gr info in new format */ + BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, json_grace); + json_object_object_add(json_neigh, "gracefulRestartInfo", + json_grace); + } else { + vty_out(vty, " Graceful restart information:\n"); + if ((peer_established(p)) && + CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) { + + vty_out(vty, " End-of-RIB send: "); + FOREACH_AFI_SAFI (afi, safi) { + if (CHECK_FLAG(p->af_sflags[afi][safi], + PEER_STATUS_EOR_SEND)) { + vty_out(vty, "%s%s", + eor_send_af_count ? ", " : "", + get_afi_safi_str(afi, safi, + false)); + eor_send_af_count++; } - vty_out(vty, "\n"); - vty_out(vty, " End-of-RIB received: "); - FOREACH_AFI_SAFI (afi, safi) { - if (CHECK_FLAG( - p->af_sflags[afi][safi], - PEER_STATUS_EOR_RECEIVED)) { - vty_out(vty, "%s%s", - eor_receive_af_count - ? ", " - : "", - get_afi_safi_str(afi, - safi, - false)); - eor_receive_af_count++; - } + } + vty_out(vty, "\n"); + vty_out(vty, " End-of-RIB received: "); + FOREACH_AFI_SAFI (afi, safi) { + if (CHECK_FLAG(p->af_sflags[afi][safi], + PEER_STATUS_EOR_RECEIVED)) { + vty_out(vty, "%s%s", + eor_receive_af_count ? ", " + : "", + get_afi_safi_str(afi, safi, + false)); + eor_receive_af_count++; } - vty_out(vty, "\n"); } + vty_out(vty, "\n"); + } - if (p->t_gr_restart) - vty_out(vty, - " The remaining time of restart timer is %ld\n", - thread_timer_remain_second( - p->t_gr_restart)); + if (p->t_gr_restart) + vty_out(vty, + " The remaining time of restart timer is %ld\n", + thread_timer_remain_second(p->t_gr_restart)); - if (p->t_gr_stale) - vty_out(vty, - " The remaining time of stalepath timer is %ld\n", - thread_timer_remain_second( - p->t_gr_stale)); + if (p->t_gr_stale) + vty_out(vty, + " The remaining time of stalepath timer is %ld\n", + thread_timer_remain_second(p->t_gr_stale)); - /* more gr info in new format */ - BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, NULL); - } + /* more gr info in new format */ + BGP_SHOW_PEER_GR_CAPABILITY(vty, p, use_json, NULL); + } if (use_json) { json_object *json_stat = NULL; @@ -14178,13 +14016,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"); } @@ -14424,11 +14258,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"); @@ -14737,11 +14567,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; } @@ -14813,10 +14639,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(); @@ -14928,9 +14751,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; @@ -14975,9 +14796,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, @@ -15409,14 +15229,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; } @@ -15436,12 +15252,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; } @@ -16674,6 +16486,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); @@ -18631,6 +18448,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); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 48ed07926c..21912d143e 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1254,6 +1254,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; @@ -1417,13 +1418,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; @@ -1433,18 +1434,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? */ @@ -2534,34 +2530,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: @@ -2574,15 +2562,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: 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 9316d71baf..b592724d27 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; @@ -2349,9 +2340,8 @@ void peer_nsf_stop(struct peer *peer) UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_WAIT); UNSET_FLAG(peer->sflags, PEER_STATUS_NSF_MODE); - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) - peer->nsf[afi][safi] = 0; + FOREACH_AFI_SAFI_NSF (afi, safi) + peer->nsf[afi][safi] = 0; if (peer->t_gr_restart) { BGP_TIMER_OFF(peer->t_gr_restart); @@ -4100,6 +4090,32 @@ bool peer_active_nego(struct peer *peer) return false; } +/* If peer received at least one address family MP, return true */ +bool peer_afc_received(struct peer *peer) +{ + afi_t afi; + safi_t safi; + + FOREACH_AFI_SAFI (afi, safi) + if (peer->afc_recv[afi][safi]) + return true; + + return false; +} + +/* If peer advertised at least one address family MP, return true */ +bool peer_afc_advertised(struct peer *peer) +{ + afi_t afi; + safi_t safi; + + FOREACH_AFI_SAFI (afi, safi) + if (peer->afc_adv[afi][safi]) + return true; + + return false; +} + void peer_change_action(struct peer *peer, afi_t afi, safi_t safi, enum peer_change_type type) { @@ -4181,6 +4197,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[] = { @@ -4280,17 +4297,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); @@ -4327,6 +4343,8 @@ 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]; /* do nothing if already shut down */ if (CHECK_FLAG(bgp->flags, BGP_FLAG_SHUTDOWN)) @@ -4344,15 +4362,24 @@ void bgp_shutdown_enable(struct bgp *bgp, const char *msg) /* send a RFC 4486 notification message if necessary */ if (BGP_IS_VALID_STATE_FOR_NOTIF(peer->status)) { - if (msg) + if (msg) { + size_t datalen = strlen(msg); + + if (datalen > BGP_ADMIN_SHUTDOWN_MSG_LEN) + datalen = BGP_ADMIN_SHUTDOWN_MSG_LEN; + + data[0] = datalen; + memcpy(data + 1, msg, datalen); + bgp_notify_send_with_data( peer, BGP_NOTIFY_CEASE, - BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, - (uint8_t *)(msg), strlen(msg)); - else + BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN, data, + datalen + 1); + } else { bgp_notify_send( peer, BGP_NOTIFY_CEASE, BGP_NOTIFY_CEASE_ADMIN_SHUTDOWN); + } } /* reset start timer to initial value */ @@ -7875,8 +7902,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(); } @@ -7903,11 +7929,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", @@ -7926,10 +7948,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 29775bccce..747c185e39 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1298,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 @@ -1384,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]; @@ -1398,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; @@ -1429,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; @@ -1724,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) @@ -1756,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 @@ -1878,7 +1885,7 @@ struct bgp_nlri { #define BGP_DEFAULT_UPDATE_ADVERTISEMENT_TIME 1 /* BGP Long-lived Graceful Restart */ -#define BGP_DEFAULT_LLGR_STALE_TIME 360 +#define BGP_DEFAULT_LLGR_STALE_TIME 0 /* BGP uptime string length. */ #define BGP_UPTIME_LEN 25 @@ -2014,6 +2021,8 @@ extern bgp_peer_sort_t peer_sort_lookup(struct peer *peer); extern bool peer_active(struct peer *); extern bool peer_active_nego(struct peer *); +extern bool peer_afc_received(struct peer *peer); +extern bool peer_afc_advertised(struct peer *peer); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); extern struct peer *peer_create(union sockunion *, const char *, struct bgp *, as_t, as_t, int, struct peer_group *); @@ -2469,4 +2478,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/configure.ac b/configure.ac index 42b3b659a7..0d598954cc 100644 --- a/configure.ac +++ b/configure.ac @@ -661,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], @@ -693,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], @@ -934,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 -------------------- @@ -1747,7 +1761,6 @@ fi AS_IF([test "$enable_pathd" != "no"], [ AC_DEFINE([HAVE_PATHD], [1], [pathd]) - AC_DEFINE([HAVE_PATHD_PCEP], [1], [pathd-pcep]) ]) @@ -1809,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) @@ -1915,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" diff --git a/doc/developer/MLD-and-PIMv6-Design.png b/doc/developer/MLD-and-PIMv6-Design.png Binary files differnew file mode 100644 index 0000000000..b5066defd3 --- /dev/null +++ b/doc/developer/MLD-and-PIMv6-Design.png diff --git a/doc/developer/PIMv6-Design.pptx b/doc/developer/PIMv6-Design.pptx Binary files differnew file mode 100644 index 0000000000..fc1705905f --- /dev/null +++ b/doc/developer/PIMv6-Design.pptx 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/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/logging.rst b/doc/developer/logging.rst index eaf8625efa..4e6fc04206 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -123,10 +123,14 @@ Networking data types :frrfmtout:`1.2.3.4` + ``%pI4s``: :frrfmtout:`*` — print star instead of ``0.0.0.0`` (for multicast) + .. frrfmt:: %pI6 (struct in6_addr *) :frrfmtout:`fe80::1234` + ``%pI6s``: :frrfmtout:`*` — print star instead of ``::`` (for multicast) + .. frrfmt:: %pEA (struct ethaddr *) :frrfmtout:`01:23:45:67:89:ab` @@ -135,6 +139,8 @@ Networking data types :frrfmtout:`1.2.3.4` / :frrfmtout:`fe80::1234` + ``%pIAs``: — print star instead of zero address (for multicast) + .. frrfmt:: %pFX (struct prefix *) :frrfmtout:`1.2.3.0/24` / :frrfmtout:`fe80::1234/64` @@ -153,11 +159,11 @@ Networking data types - :c:struct:`prefix_ls` - :c:struct:`prefix_rd` - :c:struct:`prefix_ptr` - - :c:struct:`prefix_sg` (use :frrfmt:`%pSG4`) + - :c:struct:`prefix_sg` (use :frrfmt:`%pPSG4`) - :c:union:`prefixptr` (dereference to get :c:struct:`prefix`) - :c:union:`prefixconstptr` (dereference to get :c:struct:`prefix`) -.. frrfmt:: %pSG4 (struct prefix_sg *) +.. frrfmt:: %pPSG4 (struct prefix_sg *) :frrfmtout:`(*,1.2.3.4)` @@ -213,6 +219,144 @@ Networking data types :frrfmtout:`SOCK_STREAM` +Time/interval formats +^^^^^^^^^^^^^^^^^^^^^ + +.. frrfmt:: %pTS (struct timespec *) + +.. frrfmt:: %pTV (struct timeval *) + +.. frrfmt:: %pTT (time_t *) + + Above 3 options internally result in the same code being called, support + the same flags and produce equal output with one exception: ``%pTT`` + has no sub-second precision and the formatter will never print a + (nonsensical) ``.000``. + + Exactly one of ``I``, ``M`` or ``R`` must immediately follow after + ``TS``/``TV``/``TT`` to specify whether the input is an interval, monotonic + timestamp or realtime timestamp: + + ``%pTVI``: input is an interval, not a timestamp. Print interval. + + ``%pTVIs``: input is an interval, convert to wallclock by subtracting it + from current time (i.e. interval has passed **s**\ ince.) + + ``%pTVIu``: input is an interval, convert to wallclock by adding it to + current time (i.e. **u**\ ntil interval has passed.) + + ``%pTVM`` - input is a timestamp on CLOCK_MONOTONIC, convert to wallclock + time (by grabbing current CLOCK_MONOTONIC and CLOCK_REALTIME and doing the + math) and print calendaric date. + + ``%pTVMs`` - input is a timestamp on CLOCK_MONOTONIC, print interval + **s**\ ince that timestamp (elapsed.) + + ``%pTVMu`` - input is a timestamp on CLOCK_MONOTONIC, print interval + **u**\ ntil that timestamp (deadline.) + + ``%pTVR`` - input is a timestamp on CLOCK_REALTIME, print calendaric date. + + ``%pTVRs`` - input is a timestamp on CLOCK_REALTIME, print interval + **s**\ ince that timestamp. + + ``%pTVRu`` - input is a timestamp on CLOCK_REALTIME, print interval + **u**\ ntil that timestamp. + + ``%pTVA`` - reserved for CLOCK_TAI in case a PTP implementation is + interfaced to FRR. Not currently implemented. + + .. note:: + + If ``%pTVRs`` or ``%pTVRu`` are used, this is generally an indication + that a CLOCK_MONOTONIC timestamp should be used instead (or added in + parallel.) CLOCK_REALTIME might be adjusted by NTP, PTP or similar + procedures, causing bogus intervals to be printed. + + ``%pTVM`` on first look might be assumed to have the same problem, but + on closer thought the assumption is always that current system time is + correct. And since a CLOCK_MONOTONIC interval is also quite safe to + assume to be correct, the (past) absolute timestamp to be printed from + this can likely be correct even if it doesn't match what CLOCK_REALTIME + would have indicated at that point in the past. This logic does, + however, not quite work for *future* times. + + Generally speaking, almost all use cases in FRR should (and do) use + CLOCK_MONOTONIC (through :c:func:`monotime()`.) + + Flags common to printing calendar times and intervals: + + ``p``: include spaces in appropriate places (depends on selected format.) + + ``%p.3TV...``: specify sub-second resolution (use with ``FMT_NSTD`` to + suppress gcc warning.) As noted above, ``%pTT`` will never print sub-second + digits since there are none. Only some formats support printing sub-second + digits and the default may vary. + + The following flags are available for printing calendar times/dates: + + (no flag): :frrfmtout:`Sat Jan 1 00:00:00 2022` - print output from + ``ctime()``, in local time zone. Since FRR does not currently use/enable + locale support, this is always the C locale. (Locale support getting added + is unlikely for the time being and would likely break other things worse + than this.) + + ``i``: :frrfmtout:`2022-01-01T00:00:00.123` - ISO8601 timestamp in local + time zone (note there is no ``Z`` or ``+00:00`` suffix.) Defaults to + millisecond precision. + + ``ip``: :frrfmtout:`2022-01-01 00:00:00.123` - use readable form of ISO8601 + with space instead of ``T`` separator. + + The following flags are available for printing intervals: + + (no flag): :frrfmtout:`9w9d09:09:09.123` - does not match any + preexisting format; added because it does not lose precision (like ``t``) + for longer intervals without printing huge numbers (like ``h``/``m``). + Defaults to millisecond precision. The week/day fields are left off if + they're zero, ``p`` adds a space after the respective letter. + + ``t``: :frrfmtout:`9w9d09h`, :frrfmtout:`9d09h09m`, :frrfmtout:`09:09:09` - + this replaces :c:func:`frrtime_to_interval()`. ``p`` adds spaces after + week/day/hour letters. + + ``d``: print decimal number of seconds. Defaults to millisecond precision. + + ``x`` / ``tx`` / ``dx``: Like no flag / ``t`` / ``d``, but print + :frrfmtout:`-` for zero or negative intervals (for use with unset timers.) + + ``h``: :frrfmtout:`09:09:09` + + ``hx``: :frrfmtout:`09:09:09`, :frrfmtout:`--:--:--` - this replaces + :c:func:`pim_time_timer_to_hhmmss()`. + + ``m``: :frrfmtout:`09:09` + + ``mx``: :frrfmtout:`09:09`, :frrfmtout:`--:--` - this replaces + :c:func:`pim_time_timer_to_mmss()`. + +FRR library helper formats +^^^^^^^^^^^^^^^^^^^^^^^^^^ + +.. frrfmt:: %pTH (struct thread *) + + Print remaining time on timer thread. Interval-printing flag characters + listed above for ``%pTV`` can be added, e.g. ``%pTHtx``. + + ``NULL`` pointers are printed as ``-``. + +.. frrfmt:: %pTHD (struct thread *) + + Print debugging information for given thread. Sample output: + + .. code-block:: none + + {(thread *)NULL} + {(thread *)0x55a3b5818910 arg=0x55a3b5827c50 timer r=7.824 mld_t_query() &mld_ifp->t_query from pimd/pim6_mld.c:1369} + {(thread *)0x55a3b5827230 arg=0x55a3b5827c50 read fd=16 mld_t_recv() &mld_ifp->t_recv from pimd/pim6_mld.c:1186} + + (The output is aligned to some degree.) + General utility formats ^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/doc/developer/topotests.rst b/doc/developer/topotests.rst index d8b3650944..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``. diff --git a/doc/developer/workflow.rst b/doc/developer/workflow.rst index e52ec056ad..54561d3b4b 100644 --- a/doc/developer/workflow.rst +++ b/doc/developer/workflow.rst @@ -249,23 +249,13 @@ changelog with some better description. Submitting Patches and Enhancements =================================== -FRR accepts patches from two sources: - -- GitHub pull request - -Contributors are highly encouraged to use GitHub's fork-and-PR workflow. It is -easier for us to review it, test it, try it and discuss it on GitHub than it is -via email, thus your patch will get more attention more quickly on GitHub. +FRR accepts patches using GitHub pull requests. The base branch for new contributions and non-critical bug fixes should be ``master``. Please ensure your pull request is based on this branch when you submit it. -GitHub Pull Requests --------------------- - -The preferred method of submitting changes is a GitHub pull request. Code -submitted by pull request will be automatically tested by one or more CI +Code submitted by pull request will be automatically tested by one or more CI systems. Once the automated tests succeed, other developers will review your code for quality and correctness. After any concerns are resolved, your code will be merged into the branch it was submitted against. diff --git a/doc/user/babeld.rst b/doc/user/babeld.rst index 2d9fef13c3..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 diff --git a/doc/user/basic.rst b/doc/user/basic.rst index 69f276d551..3b119d6237 100644 --- a/doc/user/basic.rst +++ b/doc/user/basic.rst @@ -712,6 +712,14 @@ These options apply to all |PACKAGE_NAME| daemons. be added to all files that use the statedir. If you have "/var/run/frr" as the default statedir then it will become "/var/run/frr/<namespace>". +.. option:: -o, --vrfdefaultname <name> + + Set the name used for the *Default VRF* in CLI commands and YANG models. + This option must be the same for all running daemons. By default, the name + is "default". + + .. seealso:: :ref:`zebra-vrf` + .. option:: -v, --version Print program version. diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index db59c42773..0fb5fa8482 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 @@ -995,11 +1006,13 @@ Long-lived Graceful Restart Currently, only restarter mode is supported. This capability is advertised only if graceful restart capability is negotiated. -.. clicmd:: bgp long-lived-graceful-restart stale-time (0-4294967295) +.. 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: @@ -1423,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 @@ -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 @@ -2792,9 +2832,8 @@ at the same time. EVPN Overlay Index Gateway IP ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -Draft https://tools.ietf.org/html/draft-ietf-bess-evpn-prefix-advertisement-11 -explains the use of overlay indexes for recursive route resolution for EVPN -type-5 route. +RFC https://datatracker.ietf.org/doc/html/rfc9136 explains the use of overlay +indexes for recursive route resolution for EVPN type-5 route. We support gateway IP overlay index. A gateway IP, advertised with EVPN prefix route, is used to find an EVPN MAC/IP @@ -3553,6 +3592,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 +3631,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 +3705,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/ospfd.rst b/doc/user/ospfd.rst index 26675c27fd..91e823e7a7 100644 --- a/doc/user/ospfd.rst +++ b/doc/user/ospfd.rst @@ -1016,10 +1016,11 @@ Summary Route will be originated on-behalf of all matched external LSAs. .. clicmd:: aggregation timer (5-1800) Configure aggregation delay timer interval. Summarisation starts only after - this delay timer expiry. By default, delay interval is 5 secs. + this delay timer expiry. By default, delay interval is 5 seconds. - Resetting the aggregation delay interval to default value. + The no form of the command resets the aggregation delay interval to default + value. .. clicmd:: show ip ospf [vrf <NAME|all>] summary-address [detail] [json] 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/routemap.rst b/doc/user/routemap.rst index d99911dc02..a7f22cd40c 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -152,6 +152,10 @@ Route Map Match Command This is a BGP specific match command. Matches the specified `ipv4_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. @@ -160,6 +164,10 @@ Route Map Match Command 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/setup.rst b/doc/user/setup.rst index dbbfca21e7..25934df9cb 100644 --- a/doc/user/setup.rst +++ b/doc/user/setup.rst @@ -22,6 +22,8 @@ of these buffers, pipe their contents through ``tr '\0' '\n'``. A blank line marks the end of valid unwritten data (it will generally be followed by garbled, older log messages since the buffer is not cleared.) +.. _daemons-configuration-file: + Daemons Configuration File -------------------------- After a fresh install, starting FRR will do nothing. This is because daemons 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/zebra.rst b/doc/user/zebra.rst index c5440ef88d..9ed6b6dd7f 100644 --- a/doc/user/zebra.rst +++ b/doc/user/zebra.rst @@ -51,13 +51,6 @@ Besides the common invocation options (:ref:`common-invocation-options`), the .. seealso:: :ref:`zebra-vrf` -.. option:: -o, --vrfdefaultname - - When *Zebra* starts with this option, the default VRF name is changed to the - parameter. - - .. seealso:: :ref:`zebra-vrf` - .. option:: -z <path_to_socket>, --socket <path_to_socket> If this option is supplied on the cli, the path to the zebra @@ -363,7 +356,13 @@ separate for each set of VRF, and routing daemons can have their own context for each VRF. This conceptual view introduces the *Default VRF* case. If the user does not -configure any specific VRF, then by default, FRR uses the *Default VRF*. +configure any specific VRF, then by default, FRR uses the *Default VRF*. The +name "default" is used to refer to this VRF in various CLI commands and YANG +models. It is possible to change that name by passing the ``-o`` option to all +daemons, for example, one can use ``-o vrf0`` to change the name to "vrf0". +The easiest way to pass the same option to all daemons is to use the +``frr_global_options`` variable in the +:ref:`Daemons Configuration File <daemons-configuration-file>`. Configuring VRF networking contexts can be done in various ways on FRR. The VRF interfaces can be configured by entering in interface configuration mode @@ -440,39 +439,6 @@ commands in relationship to VRF. Here is an extract of some of those commands: the default vrf and default table. If prefix is specified dump the number of prefix routes. -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 -*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. - -.. code-block:: shell - - touch /var/run/netns/vrf0 - 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``. -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``. - -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: - -.. code-block:: shell - - ./configure --with-defaultvrfname=global - .. _zebra-table-allocation: Table Allocation 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_main.c b/eigrpd/eigrp_main.c index 9dd795f0b0..a8936dfc31 100644 --- a/eigrpd/eigrp_main.c +++ b/eigrpd/eigrp_main.c @@ -189,7 +189,7 @@ int main(int argc, char **argv, char **envp) eigrp_error_init(); eigrp_vrf_init(); - vrf_init(NULL, NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL); /*EIGRPd init*/ eigrp_if_init(); diff --git a/eigrpd/eigrp_vrf.c b/eigrpd/eigrp_vrf.c index c8c8491056..acf3e6978d 100644 --- a/eigrpd/eigrp_vrf.c +++ b/eigrpd/eigrp_vrf.c @@ -45,6 +45,6 @@ static int eigrp_vrf_delete(struct vrf *vrf) void eigrp_vrf_init(void) { - vrf_init(eigrp_vrf_new, eigrp_vrf_enable, - eigrp_vrf_disable, eigrp_vrf_delete, NULL); + vrf_init(eigrp_vrf_new, eigrp_vrf_enable, eigrp_vrf_disable, + eigrp_vrf_delete); } diff --git a/isisd/isis_adjacency.c b/isisd/isis_adjacency.c index f5e8a790bf..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; + } } } } diff --git a/isisd/isis_cli.c b/isisd/isis_cli.c index bf03d0a050..21162045ad 100644 --- a/isisd/isis_cli.c +++ b/isisd/isis_cli.c @@ -1853,7 +1853,7 @@ 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", diff --git a/isisd/isisd.c b/isisd/isisd.c index b33f272f56..21c97aced4 100644 --- a/isisd/isisd.c +++ b/isisd/isisd.c @@ -646,51 +646,6 @@ static int isis_vrf_enable(struct vrf *vrf) vrf->vrf_id); isis = isis_lookup_by_vrfname(vrf->name); - 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". */ @@ -742,7 +697,7 @@ static int isis_vrf_disable(struct vrf *vrf) void isis_vrf_init(void) { vrf_init(isis_vrf_new, isis_vrf_enable, isis_vrf_disable, - isis_vrf_delete, isis_vrf_enable); + isis_vrf_delete); vrf_cmd_init(NULL); } diff --git a/ldpd/ldp_vty_exec.c b/ldpd/ldp_vty_exec.c index 804e3a35ec..7bad1dca7c 100644 --- a/ldpd/ldp_vty_exec.c +++ b/ldpd/ldp_vty_exec.c @@ -1844,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); @@ -2006,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/ldpd.c b/ldpd/ldpd.c index 6fa0e330f8..92cf24bd5d 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -373,7 +373,7 @@ main(int argc, char *argv[]) master = frr_init(); - vrf_init(NULL, NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL); access_list_init(); ldp_vty_init(); ldp_zebra_init(master); @@ -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; } } @@ -171,6 +171,12 @@ static struct interface *bfd_get_peer_info(struct stream *s, struct prefix *dp, return ifp; stream_failure: + /* + * Clean dp and sp because caller + * will immediately check them valid or not + */ + memset(dp, 0, sizeof(*dp)); + memset(sp, 0, sizeof(*sp)); return NULL; } @@ -251,8 +257,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; } @@ -310,8 +316,8 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args) stream_putw(s, args->family); stream_put(s, &args->src, addrlen); - /* Send the expected TTL. */ - stream_putc(s, args->ttl); + /* Send the expected hops. */ + stream_putc(s, args->hops); /* Send interface name if any. */ if (args->mhop) { @@ -349,8 +355,8 @@ int zclient_bfd_command(struct zclient *zc, struct bfd_session_arg *args) stream_putw(s, args->family); stream_put(s, &args->src, addrlen); - /* Send the expected TTL. */ - stream_putc(s, args->ttl); + /* Send the expected hops. */ + stream_putc(s, args->hops); } else { /* Multi hop indicator. */ stream_putc(s, 0); @@ -396,7 +402,7 @@ struct bfd_session_params *bfd_sess_new(bsp_status_update updatecb, void *arg) /* Set defaults. */ bsp->args.detection_multiplier = BFD_DEF_DETECT_MULT; - bsp->args.ttl = 1; + bsp->args.hops = 1; bsp->args.min_rx = BFD_DEF_MIN_RX; bsp->args.min_tx = BFD_DEF_MIN_TX; bsp->args.vrf_id = VRF_DEFAULT; @@ -648,13 +654,13 @@ void bfd_sess_set_vrf(struct bfd_session_params *bsp, vrf_id_t vrf_id) void bfd_sess_set_hop_count(struct bfd_session_params *bsp, uint8_t hops) { - if (bsp->args.ttl == hops) + if (bsp->args.hops == hops) return; /* If already installed, remove the old setting. */ _bfd_sess_remove(bsp); - bsp->args.ttl = hops; + bsp->args.hops = hops; bsp->args.mhop = (hops > 1); } @@ -692,7 +698,7 @@ enum bfd_session_state bfd_sess_status(const struct bfd_session_params *bsp) uint8_t bfd_sess_hop_count(const struct bfd_session_params *bsp) { - return bsp->args.ttl; + return bsp->args.hops; } const char *bfd_sess_profile(const struct bfd_session_params *bsp) @@ -385,8 +385,8 @@ struct bfd_session_arg { /** Multi hop indicator. */ uint8_t mhop; - /** Expected TTL. */ - uint8_t ttl; + /** Expected hops. */ + uint8_t hops; /** C bit (Control Plane Independent bit) indicator. */ uint8_t cbit; @@ -245,36 +245,6 @@ void if_update_to_new_vrf(struct interface *ifp, vrf_id_t vrf_id) 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 (!vrf_is_backend_netns() && 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); - } } @@ -1185,13 +1155,6 @@ DEFPY_YANG_NOSH (interface, struct vrf *vrf; int ret, count; - /* - * 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. - */ if (vrf_is_backend_netns()) { /* * For backward compatibility, if the VRF name is not specified @@ -1203,25 +1166,15 @@ DEFPY_YANG_NOSH (interface, if (count != 1) vrf_name = VRF_DEFAULT_NAME; } + + snprintf(xpath_list, XPATH_MAXLEN, + "/frr-interface:lib/interface[name='%s:%s']", vrf_name, + ifname); } else { - /* - * If the interface already exists, use its VRF regardless of - * what user specified. We can't have same interface name in - * different VRFs with VRF-lite backend. - */ - ifp = if_lookup_by_name_all_vrf(ifname); - if (ifp) { - vrf_name = ifp->vrf->name; - } else { - if (!vrf_name) - vrf_name = VRF_DEFAULT_NAME; - } + 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) { @@ -1257,27 +1210,72 @@ 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 netns_ifname_split(const char *xpath, char *ifname, char *vrfname) +{ + char *delim; + int len; + + 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) { - const char *vrf; + vty_out(vty, "!\n"); - vrf = yang_dnode_get_string(dnode, "./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"); - vty_out(vty, "interface %s", yang_dnode_get_string(dnode, "./name")); - if (!strmatch(vrf, VRF_DEFAULT_NAME)) - vty_out(vty, " vrf %s", vrf); vty_out(vty, "\n"); } @@ -1406,19 +1404,55 @@ 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 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: + if (vrf_is_backend_netns()) { + char ifname_ns[XPATH_MAXLEN]; + char vrfname_ns[XPATH_MAXLEN]; + + 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; + } + } + break; case NB_EV_PREPARE: case NB_EV_ABORT: break; case NB_EV_APPLY: - ifp = if_get_by_name(ifname, VRF_UNKNOWN, vrfname); + 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); @@ -1491,9 +1525,14 @@ static int lib_interface_get_keys(struct nb_cb_get_keys_args *args) { const struct interface *ifp = args->list_entry; - args->keys->num = 2; - strlcpy(args->keys->key[0], ifp->name, sizeof(args->keys->key[0])); - strlcpy(args->keys->key[1], ifp->vrf->name, sizeof(args->keys->key[1])); + args->keys->num = 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; } @@ -1501,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); - return vrf ? if_lookup_by_name(ifname, vrf->vrf_id) : NULL; + vrf = vrf_lookup_by_name(vrfname); + + return vrf ? if_lookup_by_name(ifname, vrf->vrf_id) : NULL; + } else { + return if_lookup_by_name_all_vrf(args->keys->key[0]); + } } /* @@ -1541,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 * @@ -1654,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, diff --git a/lib/libfrr.c b/lib/libfrr.c index 9b05bb4fbf..89bbe6de2e 100644 --- a/lib/libfrr.c +++ b/lib/libfrr.c @@ -116,53 +116,66 @@ static const struct option lo_always[] = { {"module", no_argument, NULL, 'M'}, {"profile", required_argument, NULL, 'F'}, {"pathspace", required_argument, NULL, 'N'}, + {"vrfdefaultname", required_argument, NULL, 'o'}, {"vty_socket", required_argument, NULL, OPTION_VTYSOCK}, {"moduledir", required_argument, NULL, OPTION_MODULEDIR}, {"scriptdir", required_argument, NULL, OPTION_SCRIPTDIR}, {"log", required_argument, NULL, OPTION_LOG}, {"log-level", required_argument, NULL, OPTION_LOGLEVEL}, - {"tcli", no_argument, NULL, OPTION_TCLI}, {"command-log-always", no_argument, NULL, OPTION_LOGGING}, {"limit-fds", required_argument, NULL, OPTION_LIMIT_FDS}, {NULL}}; static const struct optspec os_always = { - "hvdM:F:N:", + "hvdM:F:N:o:", " -h, --help Display this help and exit\n" " -v, --version Print program version\n" " -d, --daemon Runs in daemon mode\n" " -M, --module Load specified module\n" " -F, --profile Use specified configuration profile\n" " -N, --pathspace Insert prefix into config & socket paths\n" + " -o, --vrfdefaultname Set default VRF name.\n" " --vty_socket Override vty socket path\n" " --moduledir Override modules directory\n" " --scriptdir Override scripts directory\n" " --log Set Logging to stdout, syslog, or file:<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 +333,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 +476,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; @@ -495,20 +512,23 @@ static int frr_opt(int opt) snprintf(pidfile_default, sizeof(pidfile_default), "%s/%s.pid", frr_vtydir, di->name); break; + case 'o': + vrf_set_default_name(optarg); + 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 +1006,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 ed7e9c099e..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, diff --git a/lib/monotime.h b/lib/monotime.h index dda763784f..15b6933955 100644 --- a/lib/monotime.h +++ b/lib/monotime.h @@ -25,6 +25,9 @@ extern "C" { #endif +struct fbuf; +struct printfrr_eargs; + #ifndef TIMESPEC_TO_TIMEVAL /* should be in sys/time.h on BSD & Linux libcs */ #define TIMESPEC_TO_TIMEVAL(tv, ts) \ @@ -42,6 +45,31 @@ extern "C" { } while (0) #endif +/* Linux/glibc is sadly missing these timespec helpers */ +#ifndef timespecadd +#define timespecadd(tsp, usp, vsp) \ + do { \ + (vsp)->tv_sec = (tsp)->tv_sec + (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec + (usp)->tv_nsec; \ + if ((vsp)->tv_nsec >= 1000000000L) { \ + (vsp)->tv_sec++; \ + (vsp)->tv_nsec -= 1000000000L; \ + } \ + } while (0) +#endif + +#ifndef timespecsub +#define timespecsub(tsp, usp, vsp) \ + do { \ + (vsp)->tv_sec = (tsp)->tv_sec - (usp)->tv_sec; \ + (vsp)->tv_nsec = (tsp)->tv_nsec - (usp)->tv_nsec; \ + if ((vsp)->tv_nsec < 0) { \ + (vsp)->tv_sec--; \ + (vsp)->tv_nsec += 1000000000L; \ + } \ + } while (0) +#endif + static inline time_t monotime(struct timeval *tvo) { struct timespec ts; @@ -132,6 +160,53 @@ static inline const char *frrtime_to_interval(time_t t, char *buf, return buf; } +enum { + /* n/a - input was seconds precision, don't print any fractional */ + TIMEFMT_SECONDS = (1 << 0), + /* caller is directly invoking printfrr_time and has pre-specified + * I/Iu/Is/M/Mu/Ms/R/Ru/Rs (for printing timers) + */ + TIMEFMT_PRESELECT = (1 << 1), + /* don't print any output - this is needed for invoking printfrr_time + * from another printfrr extensions to skip over flag characters + */ + TIMEFMT_SKIP = (1 << 2), + /* use spaces in appropriate places */ + TIMEFMT_SPACE = (1 << 3), + + /* input interpretations: */ + TIMEFMT_REALTIME = (1 << 8), + TIMEFMT_MONOTONIC = (1 << 9), + TIMEFMT_SINCE = (1 << 10), + TIMEFMT_UNTIL = (1 << 11), + + TIMEFMT_ABSOLUTE = TIMEFMT_REALTIME | TIMEFMT_MONOTONIC, + TIMEFMT_ANCHORS = TIMEFMT_SINCE | TIMEFMT_UNTIL, + + /* calendaric formats: */ + TIMEFMT_ISO8601 = (1 << 16), + + /* interval formats: */ + /* 't' - use [t]raditional 3-block format */ + TIMEFMT_BASIC = (1 << 24), + /* 'm' - select mm:ss */ + TIMEFMT_MMSS = (1 << 25), + /* 'h' - select hh:mm:ss */ + TIMEFMT_HHMMSS = (1 << 26), + /* 'd' - print as decimal number of seconds */ + TIMEFMT_DECIMAL = (1 << 27), + /* 'mx'/'hx' - replace zero value with "--:--" or "--:--:--" */ + TIMEFMT_DASHES = (1 << 31), + + /* helpers for reference */ + TIMEFMT_TIMER_DEADLINE = + TIMEFMT_PRESELECT | TIMEFMT_MONOTONIC | TIMEFMT_UNTIL, + TIMEFMT_TIMER_INTERVAL = TIMEFMT_PRESELECT, +}; + +extern ssize_t printfrr_time(struct fbuf *buf, struct printfrr_eargs *ea, + const struct timespec *ts, unsigned int flags); + #ifdef __cplusplus } #endif diff --git a/lib/nexthop.c b/lib/nexthop.c index 2e09cb4bcc..e17eeb8303 100644 --- a/lib/nexthop.c +++ b/lib/nexthop.c @@ -943,7 +943,7 @@ int nexthop_str2backups(const char *str, int *num_backups, * eth0 * (0-length if no interface present) */ -printfrr_ext_autoreg_p("NH", printfrr_nh) +printfrr_ext_autoreg_p("NH", printfrr_nh); static ssize_t printfrr_nh(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { 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) diff --git a/lib/plist.c b/lib/plist.c index 0b3de88d9f..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( @@ -1482,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; @@ -1585,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); diff --git a/lib/prefix.c b/lib/prefix.c index df753fe10b..90ab48a13b 100644 --- a/lib/prefix.c +++ b/lib/prefix.c @@ -1353,7 +1353,7 @@ char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len) return buf; } -printfrr_ext_autoreg_p("EA", printfrr_ea) +printfrr_ext_autoreg_p("EA", printfrr_ea); static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { @@ -1368,47 +1368,93 @@ static ssize_t printfrr_ea(struct fbuf *buf, struct printfrr_eargs *ea, return bputs(buf, cbuf); } -printfrr_ext_autoreg_p("IA", printfrr_ia) +printfrr_ext_autoreg_p("IA", printfrr_ia); static ssize_t printfrr_ia(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { const struct ipaddr *ipa = ptr; char cbuf[INET6_ADDRSTRLEN]; + bool use_star = false; + + if (ea->fmt[0] == 's') { + use_star = true; + ea->fmt++; + } if (!ipa) return bputs(buf, "(null)"); + if (use_star) { + struct in_addr zero4 = {}; + struct in6_addr zero6 = {}; + + switch (ipa->ipa_type) { + case IPADDR_V4: + if (!memcmp(&ipa->ip.addr, &zero4, sizeof(zero4))) + return bputch(buf, '*'); + break; + + case IPADDR_V6: + if (!memcmp(&ipa->ip.addr, &zero6, sizeof(zero6))) + return bputch(buf, '*'); + break; + + default: + break; + } + } + ipaddr2str(ipa, cbuf, sizeof(cbuf)); return bputs(buf, cbuf); } -printfrr_ext_autoreg_p("I4", printfrr_i4) +printfrr_ext_autoreg_p("I4", printfrr_i4); static ssize_t printfrr_i4(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { char cbuf[INET_ADDRSTRLEN]; + bool use_star = false; + struct in_addr zero = {}; + + if (ea->fmt[0] == 's') { + use_star = true; + ea->fmt++; + } if (!ptr) return bputs(buf, "(null)"); + if (use_star && !memcmp(ptr, &zero, sizeof(zero))) + return bputch(buf, '*'); + inet_ntop(AF_INET, ptr, cbuf, sizeof(cbuf)); return bputs(buf, cbuf); } -printfrr_ext_autoreg_p("I6", printfrr_i6) +printfrr_ext_autoreg_p("I6", printfrr_i6); static ssize_t printfrr_i6(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { char cbuf[INET6_ADDRSTRLEN]; + bool use_star = false; + struct in6_addr zero = {}; + + if (ea->fmt[0] == 's') { + use_star = true; + ea->fmt++; + } if (!ptr) return bputs(buf, "(null)"); + if (use_star && !memcmp(ptr, &zero, sizeof(zero))) + return bputch(buf, '*'); + inet_ntop(AF_INET6, ptr, cbuf, sizeof(cbuf)); return bputs(buf, cbuf); } -printfrr_ext_autoreg_p("FX", printfrr_pfx) +printfrr_ext_autoreg_p("FX", printfrr_pfx); static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { @@ -1421,7 +1467,7 @@ static ssize_t printfrr_pfx(struct fbuf *buf, struct printfrr_eargs *ea, return bputs(buf, cbuf); } -printfrr_ext_autoreg_p("SG4", printfrr_psg) +printfrr_ext_autoreg_p("PSG4", printfrr_psg); static ssize_t printfrr_psg(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { diff --git a/lib/prefix.h b/lib/prefix.h index c92f5cec5a..f2773240d2 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -602,7 +602,7 @@ static inline int is_default_host_route(const struct prefix *p) #pragma FRR printfrr_ext "%pFX" (struct prefix_evpn *) #pragma FRR printfrr_ext "%pFX" (struct prefix_fs *) -#pragma FRR printfrr_ext "%pSG4" (struct prefix_sg *) +#pragma FRR printfrr_ext "%pPSG4" (struct prefix_sg *) #endif #ifdef __cplusplus diff --git a/lib/printf/glue.c b/lib/printf/glue.c index 1147901236..6e39c2d9cf 100644 --- a/lib/printf/glue.c +++ b/lib/printf/glue.c @@ -256,7 +256,7 @@ ssize_t printfrr_exti(struct fbuf *buf, struct printfrr_eargs *ea, return -1; } -printfrr_ext_autoreg_p("FB", printfrr_fb) +printfrr_ext_autoreg_p("FB", printfrr_fb); static ssize_t printfrr_fb(struct fbuf *out, struct printfrr_eargs *ea, const void *ptr) { @@ -278,7 +278,7 @@ static ssize_t printfrr_fb(struct fbuf *out, struct printfrr_eargs *ea, return in->pos - in->buf; } -printfrr_ext_autoreg_p("VA", printfrr_va) +printfrr_ext_autoreg_p("VA", printfrr_va); static ssize_t printfrr_va(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { diff --git a/lib/printfrr.h b/lib/printfrr.h index 37f1f9c8cd..a2d113ba1e 100644 --- a/lib/printfrr.h +++ b/lib/printfrr.h @@ -209,10 +209,11 @@ void printfrr_ext_reg(const struct printfrr_ext *); .print_ptr = print_fn, \ }; \ static void _printreg_##print_fn(void) __attribute__((constructor)); \ - static void _printreg_##print_fn(void) { \ + static void _printreg_##print_fn(void) \ + { \ printfrr_ext_reg(&_printext_##print_fn); \ } \ - /* end */ + MACRO_REQUIRE_SEMICOLON() #define printfrr_ext_autoreg_i(matchs, print_fn) \ static ssize_t print_fn(struct fbuf *, struct printfrr_eargs *, \ @@ -222,10 +223,11 @@ void printfrr_ext_reg(const struct printfrr_ext *); .print_int = print_fn, \ }; \ static void _printreg_##print_fn(void) __attribute__((constructor)); \ - static void _printreg_##print_fn(void) { \ + static void _printreg_##print_fn(void) \ + { \ printfrr_ext_reg(&_printext_##print_fn); \ } \ - /* end */ + MACRO_REQUIRE_SEMICOLON() /* fbuf helper functions - note all 3 of these return the length that would * be written regardless of how much space was available in the buffer, as @@ -286,6 +288,10 @@ struct va_format { #pragma FRR printfrr_ext "%pSE" (char *) #pragma FRR printfrr_ext "%pSQ" (char *) + +#pragma FRR printfrr_ext "%pTS" (struct timespec *) +#pragma FRR printfrr_ext "%pTV" (struct timeval *) +#pragma FRR printfrr_ext "%pTT" (time_t *) #endif /* when using non-ISO-C compatible extension specifiers... */ diff --git a/lib/resolver.c b/lib/resolver.c index e3dba5f8ae..29138bbc8d 100644 --- a/lib/resolver.c +++ b/lib/resolver.c @@ -21,6 +21,7 @@ #include "resolver.h" #include "command.h" #include "xref.h" +#include "vrf.h" XREF_SETUP(); @@ -244,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 *)) @@ -279,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); } 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/routemap.c b/lib/routemap.c index c4651f39a4..7f733c8114 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -282,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, diff --git a/lib/routemap.h b/lib/routemap.h index 675f89ba92..6c4916898a 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -252,6 +252,8 @@ DECLARE_QOBJ_TYPE(route_map); (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) \ @@ -617,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, @@ -764,6 +774,21 @@ struct route_map_match_set_hooks { 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, diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index e26e3a6d2d..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 @@ -550,23 +550,18 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, 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_IPv6_NEXTHOP_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 if (IS_MATCH_IPv4_NEXTHOP_LIST(condition)) - vty_out(vty, " match ip next-hop %s\n", acl); - else - vty_out(vty, " match ipv6 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( @@ -575,6 +570,10 @@ void route_map_condition_show(struct vty *vty, const 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( @@ -715,84 +714,40 @@ void route_map_condition_show(struct vty *vty, const 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 address %s\n", yang_dnode_get_string( @@ -1443,7 +1398,7 @@ void route_map_description_show(struct vty *vty, const 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") diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 7f7bc9f9c4..51b879959f 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -622,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/sockunion.c b/lib/sockunion.c index c7af458e9e..006ac142aa 100644 --- a/lib/sockunion.c +++ b/lib/sockunion.c @@ -662,7 +662,7 @@ void sockunion_init(union sockunion *su) memset(su, 0, sizeof(union sockunion)); } -printfrr_ext_autoreg_p("SU", printfrr_psu) +printfrr_ext_autoreg_p("SU", printfrr_psu); static ssize_t printfrr_psu(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { @@ -752,7 +752,7 @@ int sockunion_is_null(const union sockunion *su) } } -printfrr_ext_autoreg_i("PF", printfrr_pf) +printfrr_ext_autoreg_i("PF", printfrr_pf); static ssize_t printfrr_pf(struct fbuf *buf, struct printfrr_eargs *ea, uintmax_t val) { @@ -775,7 +775,7 @@ static ssize_t printfrr_pf(struct fbuf *buf, struct printfrr_eargs *ea, return bprintfrr(buf, "AF_(%ju)", val); } -printfrr_ext_autoreg_i("SO", printfrr_so) +printfrr_ext_autoreg_i("SO", printfrr_so); static ssize_t printfrr_so(struct fbuf *buf, struct printfrr_eargs *ea, uintmax_t val) { diff --git a/lib/srcdest_table.c b/lib/srcdest_table.c index d2e0682e95..828cf2cce0 100644 --- a/lib/srcdest_table.c +++ b/lib/srcdest_table.c @@ -306,7 +306,7 @@ const char *srcdest_rnode2str(const struct route_node *rn, char *str, int size) return srcdest2str(dst_p, (const struct prefix_ipv6 *)src_p, str, size); } -printfrr_ext_autoreg_p("RN", printfrr_rn) +printfrr_ext_autoreg_p("RN", printfrr_rn); static ssize_t printfrr_rn(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { 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/strformat.c b/lib/strformat.c index 431e573a0c..a420ba553a 100644 --- a/lib/strformat.c +++ b/lib/strformat.c @@ -22,10 +22,12 @@ #include <string.h> #include <ctype.h> +#include <time.h> #include "printfrr.h" +#include "monotime.h" -printfrr_ext_autoreg_p("HX", printfrr_hexdump) +printfrr_ext_autoreg_p("HX", printfrr_hexdump); static ssize_t printfrr_hexdump(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { @@ -56,7 +58,7 @@ static ssize_t printfrr_hexdump(struct fbuf *buf, struct printfrr_eargs *ea, /* string analog for hexdumps / the "this." in ("74 68 69 73 0a |this.|") */ -printfrr_ext_autoreg_p("HS", printfrr_hexdstr) +printfrr_ext_autoreg_p("HS", printfrr_hexdstr); static ssize_t printfrr_hexdstr(struct fbuf *buf, struct printfrr_eargs *ea, const void *ptr) { @@ -199,7 +201,7 @@ static ssize_t bquote(struct fbuf *buf, const uint8_t *pos, size_t len, return ret; } -printfrr_ext_autoreg_p("SE", printfrr_escape) +printfrr_ext_autoreg_p("SE", printfrr_escape); static ssize_t printfrr_escape(struct fbuf *buf, struct printfrr_eargs *ea, const void *vptr) { @@ -224,7 +226,7 @@ static ssize_t printfrr_escape(struct fbuf *buf, struct printfrr_eargs *ea, return bquote(buf, ptr, len, ESC_ALL); } -printfrr_ext_autoreg_p("SQ", printfrr_quote) +printfrr_ext_autoreg_p("SQ", printfrr_quote); static ssize_t printfrr_quote(struct fbuf *buf, struct printfrr_eargs *ea, const void *vptr) { @@ -270,3 +272,326 @@ static ssize_t printfrr_quote(struct fbuf *buf, struct printfrr_eargs *ea, ret += bputch(buf, '"'); return ret; } + +static ssize_t printfrr_abstime(struct fbuf *buf, struct printfrr_eargs *ea, + const struct timespec *ts, unsigned int flags); +static ssize_t printfrr_reltime(struct fbuf *buf, struct printfrr_eargs *ea, + const struct timespec *ts, unsigned int flags); + +ssize_t printfrr_time(struct fbuf *buf, struct printfrr_eargs *ea, + const struct timespec *ts, unsigned int flags) +{ + bool have_abs, have_anchor; + + if (!(flags & TIMEFMT_PRESELECT)) { + switch (ea->fmt[0]) { + case 'I': + /* no bit set */ + break; + case 'M': + flags |= TIMEFMT_MONOTONIC; + break; + case 'R': + flags |= TIMEFMT_REALTIME; + break; + default: + return bputs(buf, + "{invalid time format input specifier}"); + } + ea->fmt++; + + if (ea->fmt[0] == 's') { + flags |= TIMEFMT_SINCE; + ea->fmt++; + } else if (ea->fmt[0] == 'u') { + flags |= TIMEFMT_UNTIL; + ea->fmt++; + } + } + + have_abs = !!(flags & TIMEFMT_ABSOLUTE); + have_anchor = !!(flags & TIMEFMT_ANCHORS); + + if (have_abs ^ have_anchor) + return printfrr_abstime(buf, ea, ts, flags); + else + return printfrr_reltime(buf, ea, ts, flags); +} + +static ssize_t do_subsec(struct fbuf *buf, const struct timespec *ts, + int precision, unsigned int flags) +{ + unsigned long long frac; + + if (precision <= 0 || (flags & TIMEFMT_SECONDS)) + return 0; + + frac = ts->tv_nsec; + if (precision > 9) + precision = 9; + for (int i = precision; i < 9; i++) + frac /= 10; + return bprintfrr(buf, ".%0*llu", precision, frac); +} + +static ssize_t printfrr_abstime(struct fbuf *buf, struct printfrr_eargs *ea, + const struct timespec *ts, unsigned int flags) +{ + struct timespec real_ts[1]; + struct tm tm; + char cbuf[32] = ""; /* manpage says 26 for ctime_r */ + ssize_t ret = 0; + int precision = ea->precision; + + while (ea->fmt[0]) { + char ch = *ea->fmt++; + + switch (ch) { + case 'p': + flags |= TIMEFMT_SPACE; + continue; + case 'i': + flags |= TIMEFMT_ISO8601; + continue; + } + + ea->fmt--; + break; + } + + if (flags & TIMEFMT_SKIP) + return 0; + + if (flags & TIMEFMT_REALTIME) + *real_ts = *ts; + else if (flags & TIMEFMT_MONOTONIC) { + struct timespec mono_now[1]; + + clock_gettime(CLOCK_REALTIME, real_ts); + clock_gettime(CLOCK_MONOTONIC, mono_now); + + timespecsub(real_ts, mono_now, real_ts); + timespecadd(real_ts, ts, real_ts); + } else { + clock_gettime(CLOCK_REALTIME, real_ts); + + if (flags & TIMEFMT_SINCE) + timespecsub(real_ts, ts, real_ts); + else /* flags & TIMEFMT_UNTIL */ + timespecadd(real_ts, ts, real_ts); + } + + localtime_r(&real_ts->tv_sec, &tm); + + if (flags & TIMEFMT_ISO8601) { + if (flags & TIMEFMT_SPACE) + strftime(cbuf, sizeof(cbuf), "%Y-%m-%d %H:%M:%S", &tm); + else + strftime(cbuf, sizeof(cbuf), "%Y-%m-%dT%H:%M:%S", &tm); + ret += bputs(buf, cbuf); + + if (precision == -1) + precision = 3; + ret += do_subsec(buf, real_ts, precision, flags); + } else { + size_t len; + + asctime_r(&tm, cbuf); + + len = strlen(cbuf); + if (!len) + /* WTF. */ + return 0; + if (cbuf[len - 1] == '\n') + cbuf[len - 1] = '\0'; + + ret += bputs(buf, cbuf); + } + return ret; +} + +static ssize_t printfrr_reltime(struct fbuf *buf, struct printfrr_eargs *ea, + const struct timespec *ts, unsigned int flags) +{ + struct timespec real_ts[1]; + ssize_t ret = 0; + const char *space = ""; + const char *dashes = "-"; + int precision = ea->precision; + + while (ea->fmt[0]) { + char ch = *ea->fmt++; + + switch (ch) { + case 'p': + flags |= TIMEFMT_SPACE; + space = " "; + continue; + case 't': + flags |= TIMEFMT_BASIC; + continue; + case 'd': + flags |= TIMEFMT_DECIMAL; + continue; + case 'm': + flags |= TIMEFMT_MMSS; + dashes = "--:--"; + continue; + case 'h': + flags |= TIMEFMT_HHMMSS; + dashes = "--:--:--"; + continue; + case 'x': + flags |= TIMEFMT_DASHES; + continue; + } + + ea->fmt--; + break; + } + + if (flags & TIMEFMT_SKIP) + return 0; + + if (flags & TIMEFMT_ABSOLUTE) { + struct timespec anchor[1]; + + if (flags & TIMEFMT_REALTIME) + clock_gettime(CLOCK_REALTIME, anchor); + else + clock_gettime(CLOCK_MONOTONIC, anchor); + if (flags & TIMEFMT_UNTIL) + timespecsub(ts, anchor, real_ts); + else /* flags & TIMEFMT_SINCE */ + timespecsub(anchor, ts, real_ts); + } else + *real_ts = *ts; + + if (real_ts->tv_sec == 0 && real_ts->tv_nsec == 0 && + (flags & TIMEFMT_DASHES)) + return bputs(buf, dashes); + + if (real_ts->tv_sec < 0) { + if (flags & TIMEFMT_DASHES) + return bputs(buf, dashes); + + /* -0.3s is { -1s + 700ms } */ + real_ts->tv_sec = -real_ts->tv_sec - 1; + real_ts->tv_nsec = 1000000000L - real_ts->tv_nsec; + if (real_ts->tv_nsec >= 1000000000L) { + real_ts->tv_sec++; + real_ts->tv_nsec -= 1000000000L; + } + + /* all formats have a - make sense in front */ + ret += bputch(buf, '-'); + } + + if (flags & TIMEFMT_DECIMAL) { + ret += bprintfrr(buf, "%lld", (long long)real_ts->tv_sec); + if (precision == -1) + precision = 3; + ret += do_subsec(buf, real_ts, precision, flags); + return ret; + } + + /* these divisions may be slow on embedded boxes, hence only do the + * ones we need, plus the ?: zero check to hopefully skip zeros fast + */ + lldiv_t min_sec = lldiv(real_ts->tv_sec, 60); + + if (flags & TIMEFMT_MMSS) { + ret += bprintfrr(buf, "%02lld:%02lld", min_sec.quot, + min_sec.rem); + ret += do_subsec(buf, real_ts, precision, flags); + return ret; + } + + lldiv_t hour_min = min_sec.quot ? lldiv(min_sec.quot, 60) : (lldiv_t){}; + + if (flags & TIMEFMT_HHMMSS) { + ret += bprintfrr(buf, "%02lld:%02lld:%02lld", hour_min.quot, + hour_min.rem, min_sec.rem); + ret += do_subsec(buf, real_ts, precision, flags); + return ret; + } + + lldiv_t day_hour = + hour_min.quot ? lldiv(hour_min.quot, 24) : (lldiv_t){}; + lldiv_t week_day = + day_hour.quot ? lldiv(day_hour.quot, 7) : (lldiv_t){}; + + /* if sub-second precision is not supported, return */ + if (flags & TIMEFMT_BASIC) { + /* match frrtime_to_interval (without space flag) */ + if (week_day.quot) + ret += bprintfrr(buf, "%lldw%s%lldd%s%02lldh", + week_day.quot, space, week_day.rem, + space, day_hour.rem); + else if (day_hour.quot) + ret += bprintfrr(buf, "%lldd%s%02lldh%s%02lldm", + day_hour.quot, space, day_hour.rem, + space, hour_min.rem); + else + ret += bprintfrr(buf, "%02lld:%02lld:%02lld", + hour_min.quot, hour_min.rem, + min_sec.rem); + /* no sub-seconds here */ + return ret; + } + + /* default format */ + if (week_day.quot) + ret += bprintfrr(buf, "%lldw%s", week_day.quot, space); + if (week_day.rem || week_day.quot) + ret += bprintfrr(buf, "%lldd%s", week_day.rem, space); + + ret += bprintfrr(buf, "%02lld:%02lld:%02lld", day_hour.rem, + hour_min.rem, min_sec.rem); + + if (precision == -1) + precision = 3; + ret += do_subsec(buf, real_ts, precision, flags); + return ret; +} + +printfrr_ext_autoreg_p("TS", printfrr_ts); +static ssize_t printfrr_ts(struct fbuf *buf, struct printfrr_eargs *ea, + const void *vptr) +{ + const struct timespec *ts = vptr; + + if (!ts) + return bputs(buf, "(null)"); + return printfrr_time(buf, ea, ts, 0); +} + +printfrr_ext_autoreg_p("TV", printfrr_tv); +static ssize_t printfrr_tv(struct fbuf *buf, struct printfrr_eargs *ea, + const void *vptr) +{ + const struct timeval *tv = vptr; + struct timespec ts; + + if (!tv) + return bputs(buf, "(null)"); + + ts.tv_sec = tv->tv_sec; + ts.tv_nsec = tv->tv_usec * 1000; + return printfrr_time(buf, ea, &ts, 0); +} + +printfrr_ext_autoreg_p("TT", printfrr_tt); +static ssize_t printfrr_tt(struct fbuf *buf, struct printfrr_eargs *ea, + const void *vptr) +{ + const time_t *tt = vptr; + struct timespec ts; + + if (!tt) + return bputs(buf, "(null)"); + + ts.tv_sec = *tt; + ts.tv_nsec = 0; + return printfrr_time(buf, ea, &ts, TIMEFMT_SECONDS); +} diff --git a/lib/thread.c b/lib/thread.c index 7b223ed6de..77e34f48f3 100644 --- a/lib/thread.c +++ b/lib/thread.c @@ -2056,3 +2056,70 @@ bool thread_is_scheduled(struct thread *thread) return true; } + +static ssize_t printfrr_thread_dbg(struct fbuf *buf, struct printfrr_eargs *ea, + const struct thread *thread) +{ + static const char * const types[] = { + [THREAD_READ] = "read", + [THREAD_WRITE] = "write", + [THREAD_TIMER] = "timer", + [THREAD_EVENT] = "event", + [THREAD_READY] = "ready", + [THREAD_UNUSED] = "unused", + [THREAD_EXECUTE] = "exec", + }; + ssize_t rv = 0; + char info[16] = ""; + + if (!thread) + return bputs(buf, "{(thread *)NULL}"); + + rv += bprintfrr(buf, "{(thread *)%p arg=%p", thread, thread->arg); + + if (thread->type < array_size(types) && types[thread->type]) + rv += bprintfrr(buf, " %-6s", types[thread->type]); + else + rv += bprintfrr(buf, " INVALID(%u)", thread->type); + + switch (thread->type) { + case THREAD_READ: + case THREAD_WRITE: + snprintfrr(info, sizeof(info), "fd=%d", thread->u.fd); + break; + + case THREAD_TIMER: + snprintfrr(info, sizeof(info), "r=%pTVMud", &thread->u.sands); + break; + } + + rv += bprintfrr(buf, " %-12s %s() %s from %s:%d}", info, + thread->xref->funcname, thread->xref->dest, + thread->xref->xref.file, thread->xref->xref.line); + return rv; +} + +printfrr_ext_autoreg_p("TH", printfrr_thread); +static ssize_t printfrr_thread(struct fbuf *buf, struct printfrr_eargs *ea, + const void *ptr) +{ + const struct thread *thread = ptr; + struct timespec remain = {}; + + if (ea->fmt[0] == 'D') { + ea->fmt++; + return printfrr_thread_dbg(buf, ea, thread); + } + + if (!thread) { + /* need to jump over time formatting flag characters in the + * input format string, i.e. adjust ea->fmt! + */ + printfrr_time(buf, ea, &remain, + TIMEFMT_TIMER_DEADLINE | TIMEFMT_SKIP); + return bputch(buf, '-'); + } + + TIMEVAL_TO_TIMESPEC(&thread->u.sands, &remain); + return printfrr_time(buf, ea, &remain, TIMEFMT_TIMER_DEADLINE); +} diff --git a/lib/thread.h b/lib/thread.h index 39f21da11d..49a70696d0 100644 --- a/lib/thread.h +++ b/lib/thread.h @@ -128,6 +128,10 @@ struct thread { pthread_mutex_t mtx; /* mutex for thread.c functions */ }; +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pTH" (struct thread *) +#endif + struct cpu_thread_history { int (*func)(struct thread *); atomic_size_t total_cpu_warn; @@ -69,7 +69,6 @@ static struct vrf_master { int (*vrf_delete_hook)(struct vrf *); int (*vrf_enable_hook)(struct vrf *); int (*vrf_disable_hook)(struct vrf *); - int (*vrf_update_name_hook)(struct vrf *vrf); } vrf_master = { 0, }; @@ -176,8 +175,6 @@ struct vrf *vrf_get(vrf_id_t vrf_id, const char *name) name, NS_NAMSIZ); strlcpy(vrf->name, name, sizeof(vrf->name)); RB_INSERT(vrf_name_head, &vrfs_by_name, vrf); - if (vrf->vrf_id == VRF_DEFAULT) - vrf_set_default_name(vrf->name, false); } else if (name && vrf->name[0] == '\0') { strlcpy(vrf->name, name, sizeof(vrf->name)); RB_INSERT(vrf_name_head, &vrfs_by_name, vrf); @@ -487,8 +484,7 @@ static const struct cmd_variable_handler vrf_var_handlers[] = { /* Initialize VRF module. */ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), - int (*disable)(struct vrf *), int (*destroy)(struct vrf *), - int ((*update)(struct vrf *))) + int (*disable)(struct vrf *), int (*destroy)(struct vrf *)) { struct vrf *default_vrf; @@ -501,7 +497,6 @@ void vrf_init(int (*create)(struct vrf *), int (*enable)(struct vrf *), vrf_master.vrf_enable_hook = enable; vrf_master.vrf_disable_hook = disable; vrf_master.vrf_delete_hook = destroy; - vrf_master.vrf_update_name_hook = update; /* The default VRF always exists. */ default_vrf = vrf_get(VRF_DEFAULT, VRF_DEFAULT_NAME); @@ -562,7 +557,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, @@ -690,15 +686,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); } @@ -778,33 +769,9 @@ void vrf_cmd_init(int (*writefunc)(struct vty *vty)) install_element(VRF_NODE, &vrf_exit_cmd); } -void vrf_set_default_name(const char *default_name, bool force) +void vrf_set_default_name(const char *default_name) { - struct vrf *def_vrf; - static bool def_vrf_forced; - - def_vrf = vrf_lookup_by_id(VRF_DEFAULT); - assert(default_name); - if (def_vrf && !force && def_vrf_forced) { - zlog_debug("VRF: %s, avoid changing name to %s, previously forced (%u)", - def_vrf->name, default_name, - def_vrf->vrf_id); - return; - } - if (strmatch(vrf_default_name, default_name)) - return; snprintf(vrf_default_name, VRF_NAMSIZ, "%s", default_name); - if (def_vrf) { - if (force) - def_vrf_forced = true; - RB_REMOVE(vrf_name_head, &vrfs_by_name, def_vrf); - strlcpy(def_vrf->data.l.netns_name, - vrf_default_name, NS_NAMSIZ); - strlcpy(def_vrf->name, vrf_default_name, sizeof(def_vrf->name)); - RB_INSERT(vrf_name_head, &vrfs_by_name, def_vrf); - if (vrf_master.vrf_update_name_hook) - (*vrf_master.vrf_update_name_hook)(def_vrf); - } } const char *vrf_get_default_name(void) @@ -212,9 +212,10 @@ extern int vrf_bitmap_check(vrf_bitmap_t, vrf_id_t); * delete -> Called back when a vrf is being deleted from * the system ( 2 and 3 ) above. */ -extern void vrf_init(int (*create)(struct vrf *vrf), int (*enable)(struct vrf *vrf), - int (*disable)(struct vrf *vrf), int (*destroy)(struct vrf *vrf), - int (*update)(struct vrf *vrf)); +extern void vrf_init(int (*create)(struct vrf *vrf), + int (*enable)(struct vrf *vrf), + int (*disable)(struct vrf *vrf), + int (*destroy)(struct vrf *vrf)); /* * Call vrf_terminate when the protocol is being shutdown @@ -267,7 +268,9 @@ extern int vrf_ioctl(vrf_id_t vrf_id, int d, unsigned long request, char *args); /* The default VRF ID */ #define VRF_DEFAULT 0 -extern void vrf_set_default_name(const char *default_name, bool force); +/* Must be called only during startup, before config is read */ +extern void vrf_set_default_name(const char *default_name); + extern const char *vrf_get_default_name(void); #define VRF_DEFAULT_NAME vrf_get_default_name() diff --git a/lib/zclient.c b/lib/zclient.c index 000dcaac8f..ab2dd09896 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2135,9 +2135,6 @@ static int zclient_vrf_add(ZAPI_CALLBACK_ARGS) vrf->data.l.table_id = data.l.table_id; memcpy(vrf->data.l.netns_name, data.l.netns_name, NS_NAMSIZ); - /* overwrite default vrf */ - if (vrf_id == VRF_DEFAULT) - vrf_set_default_name(vrfname_tmp, false); vrf_enable(vrf); return 0; diff --git a/lib/zebra.h b/lib/zebra.h index c9794352c7..139e47e8d7 100644 --- a/lib/zebra.h +++ b/lib/zebra.h @@ -346,6 +346,10 @@ typedef enum { for (afi = AFI_IP; afi < AFI_MAX; afi++) \ for (safi = SAFI_UNICAST; safi < SAFI_MAX; safi++) +#define FOREACH_AFI_SAFI_NSF(afi, safi) \ + for (afi = AFI_IP; afi < AFI_MAX; afi++) \ + for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) + /* Default Administrative Distance of each protocol. */ #define ZEBRA_KERNEL_DISTANCE_DEFAULT 0 #define ZEBRA_CONNECT_DISTANCE_DEFAULT 0 diff --git a/nhrpd/nhrp_main.c b/nhrpd/nhrp_main.c index d8f14a3fc0..bece89ca79 100644 --- a/nhrpd/nhrp_main.c +++ b/nhrpd/nhrp_main.c @@ -142,7 +142,7 @@ int main(int argc, char **argv) /* Library inits. */ master = frr_init(); nhrp_error_init(); - vrf_init(NULL, NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL); nhrp_interface_init(); resolver_init(master); diff --git a/nhrpd/nhrp_nhs.c b/nhrpd/nhrp_nhs.c index 597c125e17..3733910a63 100644 --- a/nhrpd/nhrp_nhs.c +++ b/nhrpd/nhrp_nhs.c @@ -324,8 +324,8 @@ 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; } diff --git a/ospf6d/ospf6_abr.c b/ospf6d/ospf6_abr.c index a9b4c7756c..443759344e 100644 --- a/ospf6d/ospf6_abr.c +++ b/ospf6d/ospf6_abr.c @@ -394,7 +394,8 @@ 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"); @@ -447,6 +448,20 @@ int ospf6_abr_originate_summary_to_area(struct ospf6_route *route, 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; + } + /* Do not generate if the area is stub */ /* XXX */ } @@ -1161,7 +1176,7 @@ void ospf6_abr_examin_summary(struct ospf6_lsa *lsa, struct ospf6_area *oa) if (lsa->header->adv_router == router_lsa->router_id) { if (is_debug) zlog_debug( - "Ignorning Inter-Router LSA for an ABR (%s)", + "Ignoring Inter-Router LSA for an ABR (%s)", buf); if (old) ospf6_route_remove(old, table); diff --git a/ospf6d/ospf6_area.c b/ospf6d/ospf6_area.c index f35971ba8c..417fc69694 100644 --- a/ospf6d/ospf6_area.c +++ b/ospf6d/ospf6_area.c @@ -1045,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; } @@ -1079,6 +1075,8 @@ DEFUN(show_ipv6_ospf6_spf_tree, show_ipv6_ospf6_spf_tree_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1146,6 +1144,8 @@ DEFUN(show_ipv6_ospf6_area_spf_tree, show_ipv6_ospf6_area_spf_tree_cmd, } } + OSPF6_CMD_CHECK_VRF(false, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1234,6 +1234,8 @@ DEFUN(show_ipv6_ospf6_simulate_spf_tree_root, } } + OSPF6_CMD_CHECK_VRF(false, all_vrf, ospf6); + return CMD_SUCCESS; } diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index b439f947de..5e7ba81a33 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -207,7 +207,7 @@ int ospf6_orig_as_external_lsa(struct thread *thread) if (oi->state == OSPF6_INTERFACE_DOWN) return 0; - if (IS_AREA_NSSA(oi->area)) + if (IS_AREA_NSSA(oi->area) || IS_AREA_STUB(oi->area)) return 0; type = htons(OSPF6_LSTYPE_AS_EXTERNAL); @@ -1409,9 +1409,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct ospf6_external_info tinfo; 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; red = ospf6_redist_lookup(ospf6, type, 0); @@ -1497,21 +1494,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)); - zlog_debug( - "Advertise as AS-External Id:%s prefix %pFX metric %u", - ibuf, prefix, match->path.metric_type); - } - match->path.origin.id = htonl(info->id); ospf6_handle_external_lsa_origination(ospf6, match, prefix); @@ -1944,13 +1926,13 @@ DEFPY (ospf6_default_route_originate, if (mtype_str == NULL) mtype = -1; - /* To check ,if user is providing same route map */ - if ((rtmap == ROUTEMAP_NAME(red)) - || (rtmap && ROUTEMAP_NAME(red) - && (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0))) + /* To check if user is providing same route map */ + if ((!rtmap && !ROUTEMAP_NAME(red)) || + (rtmap && ROUTEMAP_NAME(red) && + (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0))) sameRtmap = true; - /* Don't allow if the same lsa is aleardy originated. */ + /* Don't allow if the same lsa is already originated. */ if ((sameRtmap) && (red->dmetric.type == mtype) && (red->dmetric.value == mval) && (cur_originate == default_originate)) @@ -2553,10 +2535,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) @@ -2564,6 +2543,8 @@ DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -2787,7 +2768,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 +2776,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 +2987,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 +3026,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); } @@ -3642,7 +3606,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, @@ -3678,14 +3641,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_flood.c b/ospf6d/ospf6_flood.c index 6e00bd766f..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, 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_helper.c b/ospf6d/ospf6_gr_helper.c index 4dc2d8af83..84ee35a3ed 100644 --- a/ospf6d/ospf6_gr_helper.c +++ b/ospf6d/ospf6_gr_helper.c @@ -1188,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; } diff --git a/ospf6d/ospf6_interface.c b/ospf6d/ospf6_interface.c index 487ecc4072..ae9f13bc10 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -971,6 +971,10 @@ static const char *ospf6_iftype_str(uint8_t iftype) return "UNKNOWN"; } +#if CONFDATE > 20220709 +CPP_NOTICE("Time to remove ospf6Enabled from JSON output") +#endif + /* show specified interface structure */ static int ospf6_interface_show(struct vty *vty, struct interface *ifp, json_object *json_obj, bool use_json) @@ -1260,14 +1264,13 @@ struct in6_addr *ospf6_interface_get_global_address(struct interface *ifp) static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id, int argc, struct cmd_token **argv, int idx_ifname, int intf_idx, - int json_idx) + int json_idx, bool uj) { struct vrf *vrf = vrf_lookup_by_id(vrf_id); struct interface *ifp; json_object *json; json_object *json_int; - bool uj = use_json(argc, argv); if (uj) { json = json_object_new_object(); @@ -1277,10 +1280,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; } @@ -1294,10 +1294,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); @@ -1329,6 +1326,7 @@ DEFUN(show_ipv6_ospf6_interface, show_ipv6_ospf6_interface_ifname_cmd, const char *vrf_name = NULL; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); if (idx_vrf > 0) { @@ -1341,13 +1339,15 @@ DEFUN(show_ipv6_ospf6_interface, show_ipv6_ospf6_interface_ifname_cmd, if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { show_ospf6_interface_common(vty, ospf6->vrf_id, argc, argv, idx_ifname, intf_idx, - json_idx); + json_idx, uj); if (!all_vrf) break; } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1463,14 +1463,13 @@ static int ospf6_interface_show_traffic(struct vty *vty, static int ospf6_interface_show_traffic_common(struct vty *vty, int argc, struct cmd_token **argv, - vrf_id_t vrf_id) + vrf_id_t vrf_id, bool uj) { int idx_ifname = 0; int display_once = 0; char *intf_name = NULL; struct interface *ifp = NULL; json_object *json = NULL; - bool uj = use_json(argc, argv); if (uj) json = json_object_new_object(); @@ -1484,10 +1483,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) { @@ -1496,10 +1492,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 { @@ -1519,12 +1512,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; } @@ -1541,19 +1530,22 @@ DEFUN(show_ipv6_ospf6_interface_traffic, show_ipv6_ospf6_interface_traffic_cmd, const char *vrf_name = NULL; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { ospf6_interface_show_traffic_common(vty, argc, argv, - ospf6->vrf_id); + ospf6->vrf_id, uj); if (!all_vrf) break; } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1617,6 +1609,8 @@ DEFUN(show_ipv6_ospf6_interface_ifname_prefix, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1667,6 +1661,8 @@ DEFUN(show_ipv6_ospf6_interface_prefix, show_ipv6_ospf6_interface_prefix_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } diff --git a/ospf6d/ospf6_message.c b/ospf6d/ospf6_message.c index 9238b81c5f..352cb137ed 100644 --- a/ospf6d/ospf6_message.c +++ b/ospf6d/ospf6_message.c @@ -431,6 +431,14 @@ static void ospf6_hello_recv(struct in6_addr *src, struct in6_addr *dst, 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; + } + /* Find neighbor, create if not exist */ on = ospf6_neighbor_lookup(oh->router_id, oi); if (on == NULL) { diff --git a/ospf6d/ospf6_neighbor.c b/ospf6d/ospf6_neighbor.c index 8ec916dba8..afa504d13c 100644 --- a/ospf6d/ospf6_neighbor.c +++ b/ospf6d/ospf6_neighbor.c @@ -1073,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); } } @@ -1114,12 +1111,15 @@ DEFUN(show_ipv6_ospf6_neighbor, show_ipv6_ospf6_neighbor_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } static int ospf6_neighbor_show_common(struct vty *vty, int argc, struct cmd_token **argv, - struct ospf6 *ospf6, int idx_ipv4) + struct ospf6 *ospf6, int idx_ipv4, + bool uj) { struct ospf6_neighbor *on; struct ospf6_interface *oi; @@ -1129,7 +1129,6 @@ static int ospf6_neighbor_show_common(struct vty *vty, int argc, json_object *json, bool use_json); uint32_t router_id; json_object *json = NULL; - bool uj = use_json(argc, argv); showfunc = ospf6_neighbor_show_detail; if (uj) @@ -1148,12 +1147,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; } @@ -1171,6 +1166,7 @@ DEFUN(show_ipv6_ospf6_neighbor_one, show_ipv6_ospf6_neighbor_one_cmd, const char *vrf_name = NULL; bool all_vrf = false; int idx_vrf = 0; + bool uj = use_json(argc, argv); OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); if (idx_vrf > 0) @@ -1179,13 +1175,15 @@ DEFUN(show_ipv6_ospf6_neighbor_one, show_ipv6_ospf6_neighbor_one_cmd, for (ALL_LIST_ELEMENTS_RO(om6->ospf6, node, ospf6)) { if (all_vrf || strcmp(ospf6->name, vrf_name) == 0) { ospf6_neighbor_show_common(vty, argc, argv, ospf6, - idx_ipv4); + idx_ipv4, uj); if (!all_vrf) break; } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } diff --git a/ospf6d/ospf6_nssa.c b/ospf6d/ospf6_nssa.c index cd1be3a5b7..042907d0f6 100644 --- a/ospf6d/ospf6_nssa.c +++ b/ospf6d/ospf6_nssa.c @@ -135,7 +135,7 @@ static void ospf6_flush_translated_lsa(struct ospf6_area *area) zlog_debug("%s: finish area %s", __func__, area->name); } -/* Check NSSA status for all nssa areas*/ +/* Check NSSA status for all nssa areas */ void ospf6_abr_nssa_check_status(struct ospf6 *ospf6) { struct ospf6_area *area; @@ -271,7 +271,7 @@ static void ospf6_abr_announce_aggregates(struct ospf6 *ospf6) struct listnode *node; if (IS_OSPF6_DEBUG_ABR) - zlog_debug("ospf6_abr_announce_aggregates(): Start"); + zlog_debug("%s: Start", __func__); for (ALL_LIST_ELEMENTS_RO(ospf6->area_list, node, area)) { if (IS_OSPF6_DEBUG_ABR) @@ -285,7 +285,7 @@ static void ospf6_abr_announce_aggregates(struct ospf6 *ospf6) } if (IS_OSPF6_DEBUG_ABR) - zlog_debug("ospf6_abr_announce_aggregates(): Stop"); + zlog_debug("%s: Stop", __func__); } /* Flush the summary LSA's which are not approved.*/ @@ -387,7 +387,7 @@ static void ospf6_abr_unapprove_translates(struct ospf6 *ospf6) uint16_t type; if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_unapprove_translates(): Start"); + zlog_debug("%s: Start", __func__); type = htons(OSPF6_LSTYPE_AS_EXTERNAL); for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa)) { @@ -401,10 +401,10 @@ static void ospf6_abr_unapprove_translates(struct ospf6 *ospf6) } if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_unapprove_translates(): Stop"); + zlog_debug("%s: Stop", __func__); } -/* Generate the translated external lsa from NSSA lsa */ +/* Generate the translated external lsa from NSSA lsa */ static struct ospf6_lsa *ospf6_lsa_translated_nssa_new(struct ospf6_area *area, struct ospf6_lsa *type7) { @@ -536,10 +536,10 @@ static void ospf6_ls_retransmit_delete_nbr_as(struct ospf6 *ospf6, ospf6_flood_clear_area(lsa, area); if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("%s : finish lsa %s", __func__, lsa->name); + zlog_debug("%s : finish lsa %s", __func__, lsa->name); } -/* Refresh translated AS-external-LSA. */ +/* Refresh translated AS-external-LSA. */ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area, struct ospf6_lsa *type7, struct ospf6_lsa *type5) @@ -575,8 +575,9 @@ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area, 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); + htons(OSPF6_LSTYPE_AS_EXTERNAL), + match->path.origin.id, ospf6->router_id, + ospf6->lsdb); } if (type5) { @@ -604,7 +605,6 @@ 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) @@ -615,7 +615,7 @@ struct ospf6_lsa *ospf6_translated_nssa_refresh(struct ospf6_area *area, static void ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa *lsa) { - /* Incoming Type-7 or later aggregated Type-7 + /* Incoming Type-7 or aggregated Type-7 * * LSA is skipped if P-bit is off. * @@ -707,7 +707,7 @@ static void ospf6_abr_translate_nssa(struct ospf6_area *area, struct ospf6_lsa * static void ospf6_abr_process_nssa_translates(struct ospf6 *ospf6) { /* Scan through all NSSA_LSDB records for all areas; - * If P-bit is on, translate all Type-7's to 5's and aggregate or\ + * If P-bit is on, translate all Type-7's to 5's and aggregate or * flood install as approved in Type-5 LSDB with XLATE Flag on * later, do same for all aggregates... At end, DISCARD all * remaining UNAPPROVED Type-5's (Aggregate is for future ) */ @@ -739,7 +739,7 @@ static void ospf6_abr_process_nssa_translates(struct ospf6 *ospf6) type = htons(OSPF6_LSTYPE_TYPE_7); for (ALL_LSDB_TYPED(oa->lsdb, type, lsa)) { zlog_debug("%s : lsa %s , id %pI4 , adv router %pI4", - lsa->name, __func__, &lsa->header->id, + __func__, lsa->name, &lsa->header->id, &lsa->header->adv_router); ospf6_abr_translate_nssa(oa, lsa); } @@ -783,7 +783,7 @@ static void ospf6_abr_remove_unapproved_translates(struct ospf6 *ospf6) /* All AREA PROCESS should have APPROVED necessary LSAs */ /* Remove any left over and not APPROVED */ if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_remove_unapproved_translates(): Start"); + zlog_debug("%s: Start", __func__); type = htons(OSPF6_LSTYPE_AS_EXTERNAL); for (ALL_LSDB_TYPED(ospf6->lsdb, type, lsa)) { @@ -798,7 +798,7 @@ static void ospf6_abr_remove_unapproved_translates(struct ospf6 *ospf6) } if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf_abr_remove_unapproved_translates(): Stop"); + zlog_debug("%s: Stop", __func__); } static void ospf6_abr_nssa_type_7_default_create(struct ospf6 *ospf6, @@ -897,17 +897,17 @@ static void ospf6_abr_nssa_task(struct ospf6 *ospf6) /* Each area must confirm TranslatorRole */ if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_nssa_task(): Start"); + zlog_debug("%s: Start", __func__); /* For all Global Entries flagged "local-translate", unset APPROVED */ if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_nssa_task(): unapprove translates"); + zlog_debug("%s: unapprove translates", __func__); ospf6_abr_unapprove_translates(ospf6); /* Originate Type-7 aggregates */ if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_nssa_task(): send NSSA aggregates"); + zlog_debug("%s: send NSSA aggregates", __func__); ospf6_abr_send_nssa_aggregates(ospf6); /* For all NSSAs, Type-7s, translate to 5's, INSTALL/FLOOD, or @@ -915,17 +915,16 @@ static void ospf6_abr_nssa_task(struct ospf6 *ospf6) * Install or Approve in Type-5 Global LSDB */ if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_nssa_task(): process translates"); + zlog_debug("%s: process translates", __func__); ospf6_abr_process_nssa_translates(ospf6); /* Flush any unapproved previous translates from Global Data Base */ if (IS_OSPF6_DEBUG_NSSA) - zlog_debug( - "ospf6_abr_nssa_task(): remove unapproved translates"); + zlog_debug("%s: remove unapproved translates", __func__); ospf6_abr_remove_unapproved_translates(ospf6); if (IS_OSPF6_DEBUG_NSSA) - zlog_debug("ospf6_abr_nssa_task(): Stop"); + zlog_debug("%s: Stop", __func__); } int ospf6_redistribute_check(struct ospf6 *ospf6, struct ospf6_route *route, @@ -1021,10 +1020,10 @@ static void ospf6_nssa_flush_area(struct ospf6_area *area) /* Flush the translated LSA */ if (ospf6_check_and_set_router_abr(ospf6)) { - type = htons(OSPF6_LSTYPE_AS_EXTERNAL); type5 = ospf6_lsdb_lookup( - htons(type), lsa->external_lsa_id, - ospf6->router_id, ospf6->lsdb); + htons(OSPF6_LSTYPE_AS_EXTERNAL), + lsa->external_lsa_id, ospf6->router_id, + ospf6->lsdb); if (type5 && CHECK_FLAG(type5->flag, OSPF6_LSA_LOCAL_XLT)) { type5->header->age = htons(OSPF_LSA_MAXAGE); @@ -1376,7 +1375,7 @@ DEFPY (no_area_nssa_range, 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); + vty_out(vty, "%% range %s does not exist.\n", prefix_str); return CMD_SUCCESS; } diff --git a/ospf6d/ospf6_route.c b/ospf6d/ospf6_route.c index 92fcbf71e8..f5d60d80fa 100644 --- a/ospf6d/ospf6_route.c +++ b/ospf6d/ospf6_route.c @@ -1610,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; } @@ -1629,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; } @@ -1647,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_top.c b/ospf6d/ospf6_top.c index b50f32059e..e2db77d44b 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -236,7 +236,7 @@ static int ospf6_vrf_enable(struct vrf *vrf) void ospf6_vrf_init(void) { vrf_init(ospf6_vrf_new, ospf6_vrf_enable, ospf6_vrf_disable, - ospf6_vrf_delete, ospf6_vrf_enable); + ospf6_vrf_delete); vrf_cmd_init(NULL); } @@ -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; @@ -516,7 +515,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); @@ -1532,10 +1530,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", @@ -1575,6 +1570,8 @@ DEFUN(show_ipv6_ospf6, show_ipv6_ospf6_cmd, if (uj) json_object_free(json); + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1613,6 +1610,8 @@ DEFUN(show_ipv6_ospf6_route, show_ipv6_ospf6_route_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1646,6 +1645,8 @@ DEFUN(show_ipv6_ospf6_route_match, show_ipv6_ospf6_route_match_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1680,6 +1681,8 @@ DEFUN(show_ipv6_ospf6_route_match_detail, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1715,6 +1718,8 @@ DEFUN(show_ipv6_ospf6_route_type_detail, show_ipv6_ospf6_route_type_detail_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -2127,19 +2132,18 @@ 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); } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } 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 fae5569168..77156f961d 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/ospf6d.c b/ospf6d/ospf6d.c index 5e6dcde991..cc5a0f7870 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"); } @@ -427,6 +421,8 @@ DEFUN(show_ipv6_ospf6_database, show_ipv6_ospf6_database_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -477,6 +473,8 @@ DEFUN(show_ipv6_ospf6_database_type, show_ipv6_ospf6_database_type_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -518,6 +516,8 @@ DEFUN(show_ipv6_ospf6_database_id, show_ipv6_ospf6_database_id_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -563,6 +563,8 @@ DEFUN(show_ipv6_ospf6_database_router, show_ipv6_ospf6_database_router_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -631,6 +633,8 @@ DEFUN_HIDDEN( } } + OSPF6_CMD_CHECK_VRF(false, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -687,6 +691,8 @@ DEFUN(show_ipv6_ospf6_database_type_id, show_ipv6_ospf6_database_type_id_cmd, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -746,6 +752,8 @@ DEFUN(show_ipv6_ospf6_database_type_router, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -795,6 +803,8 @@ DEFUN(show_ipv6_ospf6_database_id_router, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -844,6 +854,8 @@ DEFUN(show_ipv6_ospf6_database_adv_router_linkstate_id, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -905,6 +917,8 @@ DEFUN(show_ipv6_ospf6_database_type_id_router, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -973,6 +987,8 @@ DEFUN (show_ipv6_ospf6_database_type_adv_router_linkstate_id, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1014,6 +1030,8 @@ DEFUN(show_ipv6_ospf6_database_self_originated, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1071,6 +1089,8 @@ DEFUN(show_ipv6_ospf6_database_type_self_originated, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1133,6 +1153,8 @@ DEFUN(show_ipv6_ospf6_database_type_self_originated_linkstate_id, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1193,6 +1215,8 @@ DEFUN(show_ipv6_ospf6_database_type_id_self_originated, } } + OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1269,6 +1293,8 @@ DEFUN(show_ipv6_ospf6_border_routers, show_ipv6_ospf6_border_routers_cmd, } } + OSPF6_CMD_CHECK_VRF(false, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1312,6 +1338,8 @@ DEFUN(show_ipv6_ospf6_linkstate, show_ipv6_ospf6_linkstate_cmd, } } + OSPF6_CMD_CHECK_VRF(false, all_vrf, ospf6); + return CMD_SUCCESS; } @@ -1352,6 +1380,8 @@ DEFUN(show_ipv6_ospf6_linkstate_detail, show_ipv6_ospf6_linkstate_detail_cmd, } } + OSPF6_CMD_CHECK_VRF(false, all_vrf, ospf6); + return CMD_SUCCESS; } diff --git a/ospf6d/ospf6d.h b/ospf6d/ospf6d.h index 041a9b1df9..43549de741 100644 --- a/ospf6d/ospf6d.h +++ b/ospf6d/ospf6d.h @@ -93,14 +93,24 @@ extern struct thread_master *master; #define OSPF6_ROUTER_ID_STR "Specify Router-ID\n" #define OSPF6_LS_ID_STR "Specify Link State ID\n" +#define OSPF6_CMD_CHECK_VRF(uj, all_vrf, ospf6) \ + do { \ + if (uj == false && all_vrf == false && ospf6 == NULL) { \ + vty_out(vty, "%% OSPFv3 instance not found\n"); \ + return CMD_SUCCESS; \ + } \ + } while (0) + #define IS_OSPF6_ASBR(O) ((O)->flag & OSPF6_FLAG_ASBR) #define OSPF6_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf) \ - if (argv_find(argv, argc, "vrf", &idx_vrf)) { \ - vrf_name = argv[idx_vrf + 1]->arg; \ - all_vrf = strmatch(vrf_name, "all"); \ - } else { \ - vrf_name = VRF_DEFAULT_NAME; \ - } + do { \ + if (argv_find(argv, argc, "vrf", &idx_vrf)) { \ + vrf_name = argv[idx_vrf + 1]->arg; \ + all_vrf = strmatch(vrf_name, "all"); \ + } else { \ + vrf_name = VRF_DEFAULT_NAME; \ + } \ + } while (0) #define OSPF6_FALSE false #define OSPF6_TRUE true 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_asbr.c b/ospfd/ospf_asbr.c index 982fad63ec..000c62e305 100644 --- a/ospfd/ospf_asbr.c +++ b/ospfd/ospf_asbr.c @@ -420,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; @@ -431,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_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_gr_helper.c b/ospfd/ospf_gr_helper.c index a58a120b6b..ae002fdc97 100644 --- a/ospfd/ospf_gr_helper.c +++ b/ospfd/ospf_gr_helper.c @@ -624,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. */ diff --git a/ospfd/ospf_ldp_sync.c b/ospfd/ospf_ldp_sync.c index 7471ba7ba2..247ceb0a08 100644 --- a/ospfd/ospf_ldp_sync.c +++ b/ospfd/ospf_ldp_sync.c @@ -1031,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 10541b09bb..6588d70208 100644 --- a/ospfd/ospf_lsa.c +++ b/ospfd/ospf_lsa.c @@ -2692,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 @@ -2700,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; @@ -3302,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); @@ -3326,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 2e648b3354..a979573715 100644 --- a/ospfd/ospf_lsa.h +++ b/ospfd/ospf_lsa.h @@ -293,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_neighbor.c b/ospfd/ospf_neighbor.c index 98fb54d82a..c59734b9f3 100644 --- a/ospfd/ospf_neighbor.c +++ b/ospfd/ospf_neighbor.c @@ -382,10 +382,17 @@ void ospf_renegotiate_optional_capabilities(struct ospf *top) struct route_table *nbrs; struct route_node *rn; struct ospf_neighbor *nbr; + uint8_t shutdown_save = top->inst_shutdown; /* At first, flush self-originated LSAs from routing domain. */ ospf_flush_self_originated_lsas_now(top); + /* ospf_flush_self_originated_lsas_now is primarily intended for shut + * down scenarios. Reset the inst_shutdown flag that it sets. We are + * just changing configuration, and the flag can change the scheduling + * of when maxage LSAs are sent. */ + top->inst_shutdown = shutdown_save; + /* Revert all neighbor status to ExStart. */ for (ALL_LIST_ELEMENTS_RO(top->oiflist, node, oi)) { if ((nbrs = oi->nbrs) == NULL) diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index a83e83f6f4..181cc37f4f 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -3024,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; } @@ -3043,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; } @@ -3057,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_te.c b/ospfd/ospf_te.c index c5d1079e91..999bc49d91 100644 --- a/ospfd/ospf_te.c +++ b/ospfd/ospf_te.c @@ -4432,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 ac1b2b807c..3d0804b018 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -157,7 +157,7 @@ static int ospf_router_cmd_parse(struct vty *vty, struct cmd_token *argv[], *instance = strtoul(argv[idx_inst]->arg, NULL, 10); } - *vrf_name = NULL; + *vrf_name = VRF_DEFAULT_NAME; if (argv_find(argv, argc, "vrf", &idx_vrf)) { if (ospf_instance != 0) { vty_out(vty, @@ -166,8 +166,6 @@ static int ospf_router_cmd_parse(struct vty *vty, struct cmd_token *argv[], } *vrf_name = argv[idx_vrf + 1]->arg; - if (*vrf_name && strmatch(*vrf_name, VRF_DEFAULT_NAME)) - *vrf_name = NULL; } return CMD_SUCCESS; @@ -3433,23 +3431,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; @@ -3458,12 +3450,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; @@ -3513,11 +3502,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; } @@ -4177,24 +4163,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; @@ -4206,12 +4186,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; @@ -4220,11 +4197,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; } @@ -4265,11 +4239,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; } @@ -4320,12 +4291,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; } @@ -4350,11 +4317,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; } @@ -4607,12 +4571,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; @@ -4620,12 +4581,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; @@ -4634,12 +4592,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; @@ -4694,11 +4649,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; } @@ -4832,12 +4784,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; } @@ -4904,11 +4852,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; } @@ -4953,11 +4898,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; @@ -5457,11 +5400,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; @@ -5612,12 +5553,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; } @@ -5684,11 +5621,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; } @@ -5801,12 +5735,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; } @@ -5874,11 +5804,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; } @@ -5934,11 +5861,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; @@ -6013,7 +5938,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. */ @@ -6072,10 +5996,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: @@ -6097,15 +6020,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( @@ -7247,12 +7169,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; } @@ -7464,12 +7382,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; } @@ -9406,7 +9320,7 @@ DEFUN (ospf_default_information_originate, struct ospf_redist *red; int idx = 0; int cur_originate = ospf->default_originate; - int sameRtmap = 0; + bool sameRtmap = false; char *rtmap = NULL; red = ospf_redist_add(ospf, DEFAULT_ROUTE, 0); @@ -9431,13 +9345,13 @@ DEFUN (ospf_default_information_originate, if (argv_find(argv, argc, "WORD", &idx)) rtmap = argv[idx]->arg; - /* To check ,if user is providing same route map */ - if ((rtmap == ROUTEMAP_NAME(red)) || - (rtmap && ROUTEMAP_NAME(red) - && (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0))) - sameRtmap = 1; + /* To check if user is providing same route map */ + if ((!rtmap && !ROUTEMAP_NAME(red)) || + (rtmap && ROUTEMAP_NAME(red) && + (strcmp(rtmap, ROUTEMAP_NAME(red)) == 0))) + sameRtmap = true; - /* Don't allow if the same lsa is aleardy originated. */ + /* Don't allow if the same lsa is already originated. */ if ((sameRtmap) && (red->dmetric.type == type) && (red->dmetric.value == metric) @@ -9859,10 +9773,161 @@ DEFUN (no_ospf_proactive_arp, return CMD_SUCCESS; } -#if CONFDATE > 20211209 -CPP_NOTICE("Time to remove broken OSPF GR helper") +/* Graceful Restart HELPER Commands */ +DEFPY(ospf_gr_helper_enable, ospf_gr_helper_enable_cmd, + "graceful-restart helper enable [A.B.C.D$address]", + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Enable Helper support\n" + "Advertising Router-ID\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + if (address_str) { + ospf_gr_helper_support_set_per_routerid(ospf, &address, + OSPF_GR_TRUE); + return CMD_SUCCESS; + } + + ospf_gr_helper_support_set(ospf, OSPF_GR_TRUE); + + return CMD_SUCCESS; +} + +DEFPY(no_ospf_gr_helper_enable, + no_ospf_gr_helper_enable_cmd, + "no graceful-restart helper enable [A.B.C.D$address]", + NO_STR + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Enable Helper support\n" + "Advertising Router-ID\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + if (address_str) { + ospf_gr_helper_support_set_per_routerid(ospf, &address, + OSPF_GR_FALSE); + return CMD_SUCCESS; + } + + ospf_gr_helper_support_set(ospf, OSPF_GR_FALSE); + return CMD_SUCCESS; +} + +#if CONFDATE > 20220921 +CPP_NOTICE( + "Time to remove the deprecated \"[no] graceful-restart helper-only\" commands") #endif +DEFPY_HIDDEN(ospf_gr_helper_only, ospf_gr_helper_only_cmd, + "graceful-restart helper-only [A.B.C.D]", + "OSPF Graceful Restart\n" + "Enable Helper support\n" + "Advertising router id\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + struct in_addr addr; + int ret; + + vty_out(vty, + "%% This command is deprecated. Please, use `graceful-restart helper enable` instead.\n"); + + if (argc == 3) { + ret = inet_aton(argv[2]->arg, &addr); + if (!ret) { + vty_out(vty, + "Please specify the valid routerid address.\n"); + return CMD_WARNING_CONFIG_FAILED; + } + + ospf_gr_helper_support_set_per_routerid(ospf, &addr, OSPF_GR_TRUE); + return CMD_SUCCESS; + } + + ospf_gr_helper_support_set(ospf, OSPF_GR_TRUE); + + return CMD_SUCCESS; +} + +ALIAS_HIDDEN(no_ospf_gr_helper_enable, + no_ospf_gr_helper_only_cmd, + "no graceful-restart helper-only [A.B.C.D]", + NO_STR + "OSPF Graceful Restart\n" + "Disable Helper support\n" + "Advertising router id\n") + +DEFPY(ospf_gr_helper_enable_lsacheck, + ospf_gr_helper_enable_lsacheck_cmd, + "graceful-restart helper strict-lsa-checking", + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Enable strict LSA check\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_lsa_check_set(ospf, OSPF_GR_TRUE); + return CMD_SUCCESS; +} + +DEFPY(no_ospf_gr_helper_enable_lsacheck, + no_ospf_gr_helper_enable_lsacheck_cmd, + "no graceful-restart helper strict-lsa-checking", + NO_STR + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Disable strict LSA check\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_lsa_check_set(ospf, OSPF_GR_FALSE); + return CMD_SUCCESS; +} + +DEFPY(ospf_gr_helper_supported_grace_time, + ospf_gr_helper_supported_grace_time_cmd, + "graceful-restart helper supported-grace-time (10-1800)$interval", + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Supported grace timer\n" + "Grace interval(in seconds)\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_supported_gracetime_set(ospf, interval); + return CMD_SUCCESS; +} + +DEFPY(no_ospf_gr_helper_supported_grace_time, + no_ospf_gr_helper_supported_grace_time_cmd, + "no graceful-restart helper supported-grace-time (10-1800)$interval", + NO_STR + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Supported grace timer\n" + "Grace interval(in seconds)\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_supported_gracetime_set(ospf, OSPF_MAX_GRACE_INTERVAL); + return CMD_SUCCESS; +} + +DEFPY(ospf_gr_helper_planned_only, + ospf_gr_helper_planned_only_cmd, + "graceful-restart helper planned-only", + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Supported only planned restart\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_set_supported_planned_only_restart(ospf, OSPF_GR_TRUE); + + return CMD_SUCCESS; +} + /* External Route Aggregation */ DEFUN (ospf_external_route_aggregation, ospf_external_route_aggregation_cmd, @@ -9899,7 +9964,7 @@ DEFUN (ospf_external_route_aggregation, ret = ospf_asbr_external_aggregator_set(ospf, &p, tag); if (ret == OSPF_INVALID) - vty_out(vty, "Inavlid configuration!!\n"); + vty_out(vty, "Invalid configuration!!\n"); return CMD_SUCCESS; } @@ -9940,11 +10005,261 @@ DEFUN (no_ospf_external_route_aggregation, ret = ospf_asbr_external_aggregator_unset(ospf, &p, tag); if (ret == OSPF_INVALID) - vty_out(vty, "Inavlid configuration!!\n"); + vty_out(vty, "Invalid configuration!!\n"); + + return CMD_SUCCESS; +} + +DEFPY(no_ospf_gr_helper_planned_only, + no_ospf_gr_helper_planned_only_cmd, + "no graceful-restart helper planned-only", + NO_STR + "OSPF Graceful Restart\n" + "OSPF GR Helper\n" + "Supported only for planned restart\n") +{ + VTY_DECLVAR_INSTANCE_CONTEXT(ospf, ospf); + + ospf_gr_helper_set_supported_planned_only_restart(ospf, OSPF_GR_FALSE); return CMD_SUCCESS; } +static int ospf_print_vty_helper_dis_rtr_walkcb(struct hash_bucket *bucket, + void *arg) +{ + struct advRtr *rtr = bucket->data; + struct vty *vty = (struct vty *)arg; + static unsigned int count; + + vty_out(vty, "%-6pI4,", &rtr->advRtrAddr); + count++; + + if (count % 5 == 0) + vty_out(vty, "\n"); + + return HASHWALK_CONTINUE; +} + +static int ospf_show_gr_helper_details(struct vty *vty, struct ospf *ospf, + uint8_t use_vrf, json_object *json, + bool uj, bool detail) +{ + struct listnode *node; + struct ospf_interface *oi; + char buf[PREFIX_STRLEN]; + json_object *json_vrf = NULL; + + if (uj) { + if (use_vrf) + json_vrf = json_object_new_object(); + else + json_vrf = json; + } + + if (ospf->instance) { + if (uj) + json_object_int_add(json, "ospfInstance", + ospf->instance); + else + vty_out(vty, "\nOSPF Instance: %d\n\n", ospf->instance); + } + + ospf_show_vrf_name(ospf, vty, json_vrf, use_vrf); + + if (uj) { + if (use_vrf) + json_object_object_add(json, ospf_get_name(ospf), + json_vrf); + } else + vty_out(vty, "\n"); + + /* Show Router ID. */ + if (uj) { + json_object_string_add(json_vrf, "routerId", + inet_ntop(AF_INET, &ospf->router_id, + buf, sizeof(buf))); + } else { + vty_out(vty, "\n OSPF Router with ID (%pI4)\n\n", + &ospf->router_id); + } + + if (!uj) { + + if (ospf->is_helper_supported) + vty_out(vty, + " Graceful restart helper support enabled.\n"); + else + vty_out(vty, + " Graceful restart helper support disabled.\n"); + + if (ospf->strict_lsa_check) + vty_out(vty, " Strict LSA check is enabled.\n"); + else + vty_out(vty, " Strict LSA check is disabled.\n"); + + if (ospf->only_planned_restart) + vty_out(vty, + " Helper supported for planned restarts only.\n"); + else + vty_out(vty, + " Helper supported for Planned and Unplanned Restarts.\n"); + + vty_out(vty, + " Supported Graceful restart interval: %d(in seconds).\n", + ospf->supported_grace_time); + + if (OSPF_HELPER_ENABLE_RTR_COUNT(ospf)) { + vty_out(vty, " Enable Router list:\n"); + vty_out(vty, " "); + hash_walk(ospf->enable_rtr_list, + ospf_print_vty_helper_dis_rtr_walkcb, vty); + vty_out(vty, "\n\n"); + } + + if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE) { + vty_out(vty, " Last Helper exit Reason :%s\n", + ospf_exit_reason2str(ospf->last_exit_reason)); + } + + if (ospf->active_restarter_cnt) + vty_out(vty, + " Number of Active neighbours in graceful restart: %d\n", + ospf->active_restarter_cnt); + else + vty_out(vty, "\n"); + + } else { + json_object_string_add( + json_vrf, "helperSupport", + (ospf->is_helper_supported) ? "Enabled" : "Disabled"); + json_object_string_add(json_vrf, "strictLsaCheck", + (ospf->strict_lsa_check) ? "Enabled" + : "Disabled"); + json_object_string_add( + json_vrf, "restartSupoort", + (ospf->only_planned_restart) + ? "Planned Restart only" + : "Planned and Unplanned Restarts"); + + json_object_int_add(json_vrf, "supportedGracePeriod", + ospf->supported_grace_time); + + if (ospf->last_exit_reason != OSPF_GR_HELPER_EXIT_NONE) + json_object_string_add( + json_vrf, "LastExitReason", + ospf_exit_reason2str(ospf->last_exit_reason)); + + if (ospf->active_restarter_cnt) + json_object_int_add(json_vrf, "activeRestarterCnt", + ospf->active_restarter_cnt); + } + + + if (detail) { + int cnt = 1; + json_object *json_neighbors = NULL; + + for (ALL_LIST_ELEMENTS_RO(ospf->oiflist, node, oi)) { + struct route_node *rn; + struct ospf_neighbor *nbr; + json_object *json_neigh; + + if (ospf_interface_neighbor_count(oi) == 0) + continue; + + if (uj) { + json_object_object_get_ex(json_vrf, "Neighbors", + &json_neighbors); + if (!json_neighbors) { + json_neighbors = + json_object_new_object(); + json_object_object_add(json_vrf, + "Neighbors", + json_neighbors); + } + } + + for (rn = route_top(oi->nbrs); rn; + rn = route_next(rn)) { + + if (!rn->info) + continue; + + nbr = rn->info; + + if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) + continue; + + if (!uj) { + vty_out(vty, " Neighbour %d :\n", cnt); + vty_out(vty, " Address : %pI4\n", + &nbr->address.u.prefix4); + vty_out(vty, " Routerid : %pI4\n", + &nbr->router_id); + vty_out(vty, + " Received Grace period : %d(in seconds).\n", + nbr->gr_helper_info + .recvd_grace_period); + vty_out(vty, + " Actual Grace period : %d(in seconds)\n", + nbr->gr_helper_info + .actual_grace_period); + vty_out(vty, + " Remaining GraceTime:%ld(in seconds).\n", + thread_timer_remain_second( + nbr->gr_helper_info + .t_grace_timer)); + vty_out(vty, + " Graceful Restart reason: %s.\n\n", + ospf_restart_reason2str( + nbr->gr_helper_info + .gr_restart_reason)); + cnt++; + } else { + json_neigh = json_object_new_object(); + json_object_string_add( + json_neigh, "srcAddr", + inet_ntop(AF_INET, &nbr->src, + buf, sizeof(buf))); + + json_object_string_add( + json_neigh, "routerid", + inet_ntop(AF_INET, + &nbr->router_id, + buf, sizeof(buf))); + json_object_int_add( + json_neigh, + "recvdGraceInterval", + nbr->gr_helper_info + .recvd_grace_period); + json_object_int_add( + json_neigh, + "actualGraceInterval", + nbr->gr_helper_info + .actual_grace_period); + json_object_int_add( + json_neigh, "remainGracetime", + thread_timer_remain_second( + nbr->gr_helper_info + .t_grace_timer)); + json_object_string_add( + json_neigh, "restartReason", + ospf_restart_reason2str( + nbr->gr_helper_info + .gr_restart_reason)); + json_object_object_add( + json_neighbors, + inet_ntop(AF_INET, &nbr->src, + buf, sizeof(buf)), + json_neigh); + } + } + } + } + return CMD_SUCCESS; +} + DEFUN (ospf_external_route_aggregation_no_adrvertise, ospf_external_route_aggregation_no_adrvertise_cmd, "summary-address A.B.C.D/M no-advertise", @@ -9975,7 +10290,7 @@ DEFUN (ospf_external_route_aggregation_no_adrvertise, ret = ospf_asbr_external_rt_no_advertise(ospf, &p); if (ret == OSPF_INVALID) - vty_out(vty, "Inavlid configuration!!\n"); + vty_out(vty, "Invalid configuration!!\n"); return CMD_SUCCESS; } @@ -10011,7 +10326,7 @@ DEFUN (no_ospf_external_route_aggregation_no_adrvertise, ret = ospf_asbr_external_rt_advertise(ospf, &p); if (ret == OSPF_INVALID) - vty_out(vty, "Inavlid configuration!!\n"); + vty_out(vty, "Invalid configuration!!\n"); return CMD_SUCCESS; } @@ -10033,6 +10348,95 @@ DEFUN (ospf_route_aggregation_timer, return CMD_SUCCESS; } +DEFPY (show_ip_ospf_gr_helper, + show_ip_ospf_gr_helper_cmd, + "show ip ospf [vrf <NAME|all>] graceful-restart helper [detail] [json]", + SHOW_STR + IP_STR + "OSPF information\n" + VRF_CMD_HELP_STR + "All VRFs\n" + "OSPF Graceful Restart\n" + "Helper details in the router\n" + "Detailed informtion\n" + JSON_STR) +{ + char *vrf_name = NULL; + bool all_vrf = false; + int ret = CMD_SUCCESS; + int idx_vrf = 0; + int idx = 0; + uint8_t use_vrf = 0; + bool uj = use_json(argc, argv); + struct ospf *ospf = NULL; + json_object *json = NULL; + struct listnode *node = NULL; + int inst = 0; + bool detail = false; + + OSPF_FIND_VRF_ARGS(argv, argc, idx_vrf, vrf_name, all_vrf); + + if (argv_find(argv, argc, "detail", &idx)) + detail = true; + + if (uj) + json = json_object_new_object(); + + /* vrf input is provided */ + if (vrf_name) { + use_vrf = 1; + + if (all_vrf) { + for (ALL_LIST_ELEMENTS_RO(om->ospf, node, ospf)) { + if (!ospf->oi_running) + continue; + + ret = ospf_show_gr_helper_details( + vty, ospf, use_vrf, json, uj, detail); + } + + if (uj) + vty_json(vty, json); + + return ret; + } + + ospf = ospf_lookup_by_inst_name(inst, vrf_name); + + if (ospf == NULL || !ospf->oi_running) { + + if (uj) + vty_json(vty, json); + else + vty_out(vty, "%% OSPF instance not found\n"); + + return CMD_SUCCESS; + } + + } else { + /* Default Vrf */ + ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); + + if (ospf == NULL || !ospf->oi_running) { + + if (uj) + vty_json(vty, json); + else + vty_out(vty, "%% OSPF instance not found\n"); + + return CMD_SUCCESS; + } + + ospf_show_gr_helper_details(vty, ospf, use_vrf, json, uj, + detail); + } + + if (uj) + vty_json(vty, json); + + return CMD_SUCCESS; +} +/* Graceful Restart HELPER commands end */ DEFUN (no_ospf_route_aggregation_timer, no_ospf_route_aggregation_timer_cmd, "no aggregation timer", @@ -10679,11 +11083,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"); @@ -10691,14 +11091,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; @@ -10707,14 +11102,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; @@ -10818,9 +11208,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", @@ -11107,12 +11495,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; } @@ -11120,12 +11504,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; @@ -11136,12 +11517,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; @@ -11150,11 +11528,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; } @@ -11864,12 +12239,12 @@ static int ospf_config_write_one(struct vty *vty, struct ospf *ospf) int write = 0; /* `router ospf' print. */ - if (ospf->instance && ospf->name) { + if (ospf->instance && strcmp(ospf->name, VRF_DEFAULT_NAME)) { vty_out(vty, "router ospf %d vrf %s\n", ospf->instance, ospf->name); } else if (ospf->instance) { vty_out(vty, "router ospf %d\n", ospf->instance); - } else if (ospf->name) { + } else if (strcmp(ospf->name, VRF_DEFAULT_NAME)) { vty_out(vty, "router ospf vrf %s\n", ospf->name); } else vty_out(vty, "router ospf\n"); @@ -12085,6 +12460,9 @@ void ospf_vty_show_init(void) /* "show ip ospf vrfs" commands. */ install_element(VIEW_NODE, &show_ip_ospf_vrfs_cmd); + /* "show ip ospf gr-helper details" command */ + install_element(VIEW_NODE, &show_ip_ospf_gr_helper_cmd); + /* "show ip ospf summary-address" command */ install_element(VIEW_NODE, &show_ip_ospf_external_aggregator_cmd); } @@ -12195,6 +12573,18 @@ static void ospf_vty_zebra_init(void) install_element(OSPF_NODE, &no_ospf_distance_ospf_cmd); install_element(OSPF_NODE, &ospf_distance_ospf_cmd); + /*Ospf garcefull restart helper configurations */ + install_element(OSPF_NODE, &ospf_gr_helper_enable_cmd); + install_element(OSPF_NODE, &no_ospf_gr_helper_enable_cmd); + install_element(OSPF_NODE, &ospf_gr_helper_only_cmd); + install_element(OSPF_NODE, &no_ospf_gr_helper_only_cmd); + install_element(OSPF_NODE, &ospf_gr_helper_enable_lsacheck_cmd); + install_element(OSPF_NODE, &no_ospf_gr_helper_enable_lsacheck_cmd); + install_element(OSPF_NODE, &ospf_gr_helper_supported_grace_time_cmd); + install_element(OSPF_NODE, &no_ospf_gr_helper_supported_grace_time_cmd); + install_element(OSPF_NODE, &ospf_gr_helper_planned_only_cmd); + install_element(OSPF_NODE, &no_ospf_gr_helper_planned_only_cmd); + /* External LSA summarisation config commands.*/ install_element(OSPF_NODE, &ospf_external_route_aggregation_cmd); install_element(OSPF_NODE, &no_ospf_external_route_aggregation_cmd); diff --git a/ospfd/ospfd.c b/ospfd/ospfd.c index d051151601..726ce329e3 100644 --- a/ospfd/ospfd.c +++ b/ospfd/ospfd.c @@ -314,22 +314,19 @@ struct ospf *ospf_new_alloc(unsigned short instance, const char *name) new->instance = instance; new->router_id.s_addr = htonl(0); new->router_id_static.s_addr = htonl(0); - if (name) { - vrf = vrf_lookup_by_name(name); - if (vrf) - new->vrf_id = vrf->vrf_id; - else - new->vrf_id = VRF_UNKNOWN; - /* Freed in ospf_finish_final */ - new->name = XSTRDUP(MTYPE_OSPF_TOP, name); - if (IS_DEBUG_OSPF_EVENT) - zlog_debug( - "%s: Create new ospf instance with vrf_name %s vrf_id %u", - __func__, name, new->vrf_id); - } else { - new->vrf_id = VRF_DEFAULT; - vrf = vrf_lookup_by_id(VRF_DEFAULT); - } + + vrf = vrf_lookup_by_name(name); + if (vrf) + new->vrf_id = vrf->vrf_id; + else + new->vrf_id = VRF_UNKNOWN; + + /* Freed in ospf_finish_final */ + new->name = XSTRDUP(MTYPE_OSPF_TOP, name); + if (IS_DEBUG_OSPF_EVENT) + zlog_debug( + "%s: Create new ospf instance with vrf_name %s vrf_id %u", + __func__, name, new->vrf_id); if (vrf) ospf_vrf_link(new, vrf); @@ -481,9 +478,6 @@ struct ospf *ospf_lookup_by_inst_name(unsigned short instance, const char *name) struct ospf *ospf = NULL; struct listnode *node, *nnode; - if (name == NULL || strmatch(name, VRF_DEFAULT_NAME)) - return ospf_lookup_by_vrf_id(VRF_DEFAULT); - for (ALL_LIST_ELEMENTS(om->ospf, node, nnode, ospf)) { if ((ospf->instance == instance) && ((ospf->name == NULL && name == NULL) @@ -913,8 +907,7 @@ static void ospf_finish_final(struct ospf *ospf) if (vrf) ospf_vrf_unlink(ospf, vrf); - if (ospf->name) - XFREE(MTYPE_OSPF_TOP, ospf->name); + XFREE(MTYPE_OSPF_TOP, ospf->name); XFREE(MTYPE_OSPF_TOP, ospf); } @@ -2213,10 +2206,6 @@ static int ospf_vrf_enable(struct vrf *vrf) ospf = ospf_lookup_by_name(vrf->name); if (ospf) { - if (ospf->name && strmatch(vrf->name, VRF_DEFAULT_NAME)) { - XFREE(MTYPE_OSPF_TOP, ospf->name); - ospf->name = NULL; - } old_vrf_id = ospf->vrf_id; /* We have instance configured, link to VRF and make it "up". */ ospf_vrf_link(ospf, vrf); @@ -2285,7 +2274,7 @@ static int ospf_vrf_disable(struct vrf *vrf) void ospf_vrf_init(void) { vrf_init(ospf_vrf_new, ospf_vrf_enable, ospf_vrf_disable, - ospf_vrf_delete, ospf_vrf_enable); + ospf_vrf_delete); } void ospf_vrf_terminate(void) 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/pbrd/pbr_vrf.c b/pbrd/pbr_vrf.c index c3558ab591..277269a986 100644 --- a/pbrd/pbr_vrf.c +++ b/pbrd/pbr_vrf.c @@ -124,8 +124,7 @@ bool pbr_vrf_is_valid(const struct pbr_vrf *pbr_vrf) void pbr_vrf_init(void) { - vrf_init(pbr_vrf_new, pbr_vrf_enable, pbr_vrf_disable, pbr_vrf_delete, - NULL); + vrf_init(pbr_vrf_new, pbr_vrf_enable, pbr_vrf_disable, pbr_vrf_delete); } void pbr_vrf_terminate(void) diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index dddca1d720..ebcbbb7205 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -917,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(); @@ -953,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) @@ -1037,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; } @@ -1064,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); @@ -1142,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; } 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 05f8bfb547..ffbe802d34 100644 --- a/pceplib/test/pcep_msg_tools_test.c +++ b/pceplib/test/pcep_msg_tools_test.c @@ -174,12 +174,11 @@ 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(char *filename, - 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); @@ -216,11 +215,10 @@ void test_pcep_msg_read_pcep_initiate() { char filename[BASE_TMPFILE_SIZE]; - int fd = convert_hexstrs_to_binary(filename, - pcep_initiate_hexbyte_strs, + 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); @@ -321,11 +319,11 @@ void test_pcep_msg_read_pcep_initiate2() { 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); + 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); @@ -414,11 +412,10 @@ void test_pcep_msg_read_pcep_open() { char filename[BASE_TMPFILE_SIZE]; - int fd = convert_hexstrs_to_binary(filename, - pcep_open_odl_hexbyte_strs, + 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); @@ -463,11 +460,10 @@ void test_pcep_msg_read_pcep_update() { char filename[BASE_TMPFILE_SIZE]; - int fd = convert_hexstrs_to_binary(filename, - pcep_update_hexbyte_strs, + 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); @@ -553,8 +549,8 @@ void test_pcep_msg_read_pcep_open_initiate() int fd = convert_hexstrs_to_binary( 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); @@ -586,8 +582,8 @@ void test_pcep_msg_read_pcep_open_cisco_pce() int fd = convert_hexstrs_to_binary( 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); @@ -653,8 +649,8 @@ void test_pcep_msg_read_pcep_update_cisco_pce() int fd = convert_hexstrs_to_binary( 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); @@ -801,8 +797,8 @@ void test_pcep_msg_read_pcep_report_cisco_pcc() int fd = convert_hexstrs_to_binary( 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); @@ -966,8 +962,8 @@ void test_pcep_msg_read_pcep_initiate_cisco_pcc() int fd = convert_hexstrs_to_binary( 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); diff --git a/pceplib/test/pcep_session_logic_loop_test.c b/pceplib/test/pcep_session_logic_loop_test.c index 96beceac59..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; diff --git a/pimd/.gitignore b/pimd/.gitignore index b1780df758..3f73471086 100644 --- a/pimd/.gitignore +++ b/pimd/.gitignore @@ -1,3 +1,4 @@ -pimd -mtracebis -test_igmpv3_join +/pimd +/pim6d +/mtracebis +/test_igmpv3_join diff --git a/pimd/pim6_main.c b/pimd/pim6_main.c new file mode 100644 index 0000000000..02654e1cb6 --- /dev/null +++ b/pimd/pim6_main.c @@ -0,0 +1,214 @@ +/* + * PIMv6 main() + * Copyright (C) 2021 David Lamparter for NetDEF, Inc. + * Copyright (C) 2008 Everton da Silva Marques (pim_main.c) + * + * 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.h> + +#include "lib/vrf.h" +#include "lib/filter.h" +#include "lib/plist.h" +#include "lib/routemap.h" +#include "lib/routing_nb.h" + +#include "lib/privs.h" +#include "lib/sigevent.h" +#include "lib/libfrr.h" +#include "lib/version.h" + +#include "pimd.h" +#include "pim_instance.h" +#include "pim_errors.h" +#include "pim_iface.h" +#include "pim_zebra.h" + +zebra_capabilities_t _caps_p[] = { + ZCAP_SYS_ADMIN, + ZCAP_NET_ADMIN, + ZCAP_NET_RAW, + ZCAP_BIND, +}; + +/* pimd privileges to run with */ +struct zebra_privs_t pimd_privs = { +#if defined(FRR_USER) && defined(FRR_GROUP) + .user = FRR_USER, + .group = FRR_GROUP, +#endif +#ifdef VTY_GROUP + .vty_group = VTY_GROUP, +#endif + .caps_p = _caps_p, + .cap_num_p = array_size(_caps_p), + .cap_num_i = 0, +}; + +static void pim6_terminate(void); + +static void pim6_sighup(void) +{ + zlog_info("SIGHUP received, ignoring"); +} + +static void pim6_sigint(void) +{ + zlog_notice("Terminating on signal SIGINT"); + pim6_terminate(); + exit(1); +} + +static void pim6_sigterm(void) +{ + zlog_notice("Terminating on signal SIGTERM"); + pim6_terminate(); + exit(1); +} + +static void pim6_sigusr1(void) +{ + zlog_rotate(); +} + +struct frr_signal_t pim6d_signals[] = { + { + .signal = SIGHUP, + .handler = &pim6_sighup, + }, + { + .signal = SIGUSR1, + .handler = &pim6_sigusr1, + }, + { + .signal = SIGINT, + .handler = &pim6_sigint, + }, + { + .signal = SIGTERM, + .handler = &pim6_sigterm, + }, +}; + +static const struct frr_yang_module_info *const pim6d_yang_modules[] = { + &frr_filter_info, + &frr_interface_info, + &frr_route_map_info, + &frr_vrf_info, + &frr_routing_info, +}; + +/* clang-format off */ +FRR_DAEMON_INFO(pim6d, PIM6, + .vty_port = 0, + .flags = FRR_NO_SPLIT_CONFIG, + + .proghelp = "Protocol Independent Multicast (RFC7761) for IPv6", + + .signals = pim6d_signals, + .n_signals = array_size(pim6d_signals), + + .privs = &pimd_privs, + + .yang_modules = pim6d_yang_modules, + .n_yang_modules = array_size(pim6d_yang_modules), +); +/* clang-format on */ + + +int main(int argc, char **argv, char **envp) +{ + static struct option longopts[] = { + {}, + }; + + frr_preinit(&pim6d_di, argc, argv); + frr_opt_add("", longopts, ""); + + /* this while just reads the options */ + while (1) { + int opt; + + opt = frr_getopt(argc, argv, NULL); + + if (opt == EOF) + break; + + switch (opt) { + case 0: + break; + default: + frr_help_exit(1); + } + } + + pim_router_init(); + /* TODO PIM6: temporary enable all debugs, remove later in PIMv6 work */ + router->debugs = ~0U; + + access_list_init(); + prefix_list_init(); + + /* + * Initializations + */ + pim_error_init(); + pim_vrf_init(); +#if 0 + prefix_list_add_hook(pim_prefix_list_update); + prefix_list_delete_hook(pim_prefix_list_update); + + pim_route_map_init(); + pim_init(); +#endif + + /* + * Initialize zclient "update" and "lookup" sockets + */ + if_zapi_callbacks(pim_ifp_create, pim_ifp_up, + pim_ifp_down, pim_ifp_destroy); + + /* TODO PIM6: next line is temporary since pim_cmd_init is disabled */ + if_cmd_init(NULL); + +#if 0 + pim_zebra_init(); + pim_bfd_init(); + pim_mlag_init(); + + hook_register(routing_conf_event, + routing_control_plane_protocols_name_validate); + + routing_control_plane_protocols_register_vrf_dependency(); +#endif + + frr_config_fork(); + frr_run(router->master); + + /* never reached */ + return 0; +} + +static void pim6_terminate(void) +{ + pim_vrf_terminate(); + pim_router_terminate(); + + prefix_list_reset(); + access_list_reset(); + + frr_fini(); +} diff --git a/pimd/pim_addr.c b/pimd/pim_addr.c new file mode 100644 index 0000000000..8d89b57141 --- /dev/null +++ b/pimd/pim_addr.c @@ -0,0 +1,69 @@ +/* + * PIM address generalizations + * Copyright (C) 2022 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 + */ + +#include <zebra.h> + +#include "pim_addr.h" +#include "printfrr.h" +#include "prefix.h" + + +printfrr_ext_autoreg_p("PA", printfrr_pimaddr); +static ssize_t printfrr_pimaddr(struct fbuf *buf, struct printfrr_eargs *ea, + const void *vptr) +{ + const pim_addr *addr = vptr; + bool use_star = false; + + if (ea->fmt[0] == 's') { + use_star = true; + ea->fmt++; + } + + if (!addr) + return bputs(buf, "(null)"); + + if (use_star) { + pim_addr zero = {}; + + if (memcmp(addr, &zero, sizeof(zero)) == 0) + return bputch(buf, '*'); + } + +#if PIM_IPV == 4 + return bprintfrr(buf, "%pI4", addr); +#elif !defined(PIM_V6_TEMP_BREAK) + CPP_NOTICE("note IPv6 typing for pim_addr is temporarily disabled."); + return bprintfrr(buf, "%pI4", addr); +#else + return bprintfrr(buf, "%pI6", addr); +#endif +} + +printfrr_ext_autoreg_p("SG", printfrr_sgaddr); +static ssize_t printfrr_sgaddr(struct fbuf *buf, struct printfrr_eargs *ea, + const void *vptr) +{ + const pim_sgaddr *sga = vptr; + + if (!sga) + return bputs(buf, "(null)"); + + return bprintfrr(buf, "(%pPAs,%pPAs)", &sga->src, &sga->grp); +} diff --git a/pimd/pim_addr.h b/pimd/pim_addr.h new file mode 100644 index 0000000000..a1a8b55a5c --- /dev/null +++ b/pimd/pim_addr.h @@ -0,0 +1,67 @@ +/* + * PIM address generalizations + * Copyright (C) 2022 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 + */ + +#ifndef _PIMD_PIM_ADDR_H +#define _PIMD_PIM_ADDR_H + +#include "jhash.h" + +/* temporarily disable IPv6 types to keep code compiling. + * Defining PIM_V6_TEMP_BREAK will show a lot of compile errors - they are + * very useful to see TODOs. + */ +#if PIM_IPV == 4 || !defined(PIM_V6_TEMP_BREAK) +typedef struct in_addr pim_addr; +#define PIM_ADDRSTRLEN INET_ADDRSTRLEN +#else +typedef struct in6_addr pim_addr; +#define PIM_ADDRSTRLEN INET6_ADDRSTRLEN +#endif + +/* don't use this struct directly, use the pim_sgaddr typedef */ +struct _pim_sgaddr { + pim_addr grp; + pim_addr src; +}; + +typedef struct _pim_sgaddr pim_sgaddr; + +static inline int pim_sgaddr_cmp(const pim_sgaddr a, const pim_sgaddr b) +{ + /* memcmp over the entire struct = memcmp(grp) + memcmp(src) */ + return memcmp(&a, &b, sizeof(a)); +} + +static inline uint32_t pim_sgaddr_hash(const pim_sgaddr a, uint32_t initval) +{ + return jhash2((uint32_t *)&a, sizeof(a) / sizeof(uint32_t), initval); +} + +#ifdef _FRR_ATTRIBUTE_PRINTFRR +#pragma FRR printfrr_ext "%pPA" (pim_addr *) +#pragma FRR printfrr_ext "%pSG" (pim_sgaddr *) +#endif + +/* + * There is no pim_sgaddr2str(). This is intentional. Instead, use: + * snprintfrr(buf, sizeof(buf), "%pPA", sgaddr) + * (and note that snprintfrr is implicit for vty_out and zlog_*) + */ + +#endif /* _PIMD_PIM_ADDR_H */ diff --git a/pimd/pim_assert.c b/pimd/pim_assert.c index 0988938701..79b46994aa 100644 --- a/pimd/pim_assert.c +++ b/pimd/pim_assert.c @@ -43,12 +43,11 @@ static void assert_action_a6(struct pim_ifchannel *ch, struct pim_assert_metric winner_metric); void pim_ifassert_winner_set(struct pim_ifchannel *ch, - enum pim_ifassert_state new_state, - struct in_addr winner, + enum pim_ifassert_state new_state, pim_addr winner, struct pim_assert_metric winner_metric) { struct pim_interface *pim_ifp = ch->interface->info; - int winner_changed = (ch->ifassert_winner.s_addr != winner.s_addr); + int winner_changed = !!pim_addr_cmp(ch->ifassert_winner, winner); int metric_changed = !pim_assert_metric_match( &ch->ifassert_winner_metric, &winner_metric); @@ -142,9 +141,9 @@ static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, struct pim_assert_metric recv_metric) { struct pim_ifchannel *ch; - struct prefix_sg sg; + pim_sgaddr sg; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = source_addr; sg.grp = group_addr; ch = pim_ifchannel_add(ifp, &sg, 0, 0); @@ -179,8 +178,8 @@ static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, } break; case PIM_IFASSERT_I_AM_LOSER: - if (recv_metric.ip_address.s_addr - == ch->ifassert_winner.s_addr) { + if (!pim_addr_cmp(recv_metric.ip_address, + ch->ifassert_winner)) { /* Assert from current winner */ if (cancel_assert(&recv_metric)) { @@ -216,7 +215,7 @@ static int dispatch_assert(struct interface *ifp, struct in_addr source_addr, int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, struct in_addr src_addr, uint8_t *buf, int buf_size) { - struct prefix_sg sg; + pim_sgaddr sg; struct prefix msg_source_addr; struct pim_assert_metric msg_metric; int offset; @@ -232,7 +231,7 @@ int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, /* Parse assert group addr */ - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); offset = pim_parse_addr_group(&sg, curr, curr_size); if (offset < 1) { char src_str[INET_ADDRSTRLEN]; @@ -340,7 +339,7 @@ int pim_assert_metric_better(const struct pim_assert_metric *m1, if (m1->route_metric > m2->route_metric) return 0; - return ntohl(m1->ip_address.s_addr) > ntohl(m2->ip_address.s_addr); + return pim_addr_cmp(m1->ip_address, m2->ip_address) > 0; } int pim_assert_metric_match(const struct pim_assert_metric *m1, @@ -353,7 +352,7 @@ int pim_assert_metric_match(const struct pim_assert_metric *m1, if (m1->route_metric != m2->route_metric) return 0; - return m1->ip_address.s_addr == m2->ip_address.s_addr; + return !pim_addr_cmp(m1->ip_address, m2->ip_address); } int pim_assert_build_msg(uint8_t *pim_msg, int buf_size, struct interface *ifp, diff --git a/pimd/pim_assert.h b/pimd/pim_assert.h index c07cbeb013..a149fb176e 100644 --- a/pimd/pim_assert.h +++ b/pimd/pim_assert.h @@ -37,7 +37,7 @@ struct pim_assert_metric { uint32_t rpt_bit_flag; uint32_t metric_preference; uint32_t route_metric; - struct in_addr ip_address; /* neighbor router that sourced the Assert + pim_addr ip_address; /* neighbor router that sourced the Assert message */ }; @@ -55,8 +55,7 @@ struct pim_assert_metric { #define PIM_ASSERT_ROUTE_METRIC_MAX (0xFFFFFFFF) void pim_ifassert_winner_set(struct pim_ifchannel *ch, - enum pim_ifassert_state new_state, - struct in_addr winner, + enum pim_ifassert_state new_state, pim_addr winner, struct pim_assert_metric winner_metric); int pim_assert_recv(struct interface *ifp, struct pim_neighbor *neigh, diff --git a/pimd/pim_br.c b/pimd/pim_br.c index fc6a02ec93..b3fc8969b8 100644 --- a/pimd/pim_br.c +++ b/pimd/pim_br.c @@ -29,7 +29,7 @@ #include "linklist.h" struct pim_br { - struct prefix_sg sg; + pim_sgaddr sg; struct in_addr pmbr; }; @@ -37,7 +37,7 @@ struct in_addr pim_br_unknown = {.s_addr = 0}; static struct list *pim_br_list = NULL; -struct in_addr pim_br_get_pmbr(struct prefix_sg *sg) +struct in_addr pim_br_get_pmbr(pim_sgaddr *sg) { struct listnode *node; struct pim_br *pim_br; @@ -51,7 +51,7 @@ struct in_addr pim_br_get_pmbr(struct prefix_sg *sg) return pim_br_unknown; } -void pim_br_set_pmbr(struct prefix_sg *sg, struct in_addr br) +void pim_br_set_pmbr(pim_sgaddr *sg, struct in_addr br) { struct listnode *node, *next; struct pim_br *pim_br; @@ -75,7 +75,7 @@ void pim_br_set_pmbr(struct prefix_sg *sg, struct in_addr br) /* * Remove the (S,G) from the stored values */ -void pim_br_clear_pmbr(struct prefix_sg *sg) +void pim_br_clear_pmbr(pim_sgaddr *sg) { struct listnode *node, *next; struct pim_br *pim_br; diff --git a/pimd/pim_br.h b/pimd/pim_br.h index 836ff5ee83..ef24ef3c19 100644 --- a/pimd/pim_br.h +++ b/pimd/pim_br.h @@ -20,10 +20,10 @@ #ifndef PIM_BR_H #define PIM_BR_H -struct in_addr pim_br_get_pmbr(struct prefix_sg *sg); +struct in_addr pim_br_get_pmbr(pim_sgaddr *sg); -void pim_br_set_pmbr(struct prefix_sg *sg, struct in_addr value); -void pim_br_clear_pmbr(struct prefix_sg *sg); +void pim_br_set_pmbr(pim_sgaddr *sg, struct in_addr value); +void pim_br_clear_pmbr(pim_sgaddr *sg); void pim_br_init(void); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 501d69dbf5..c0401b83ce 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -501,14 +501,14 @@ 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; if (!pim_ifp) continue; - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) { char uptime[10]; char query_hhmmss[10]; @@ -575,7 +575,7 @@ 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; @@ -610,7 +610,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, if (strcmp(ifname, "detail") && strcmp(ifname, ifp->name)) continue; - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) { found_ifname = 1; pim_time_uptime(uptime, sizeof(uptime), @@ -625,35 +625,34 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, gmi_msec = PIM_IGMP_GMI_MSEC( igmp->querier_robustness_variable, igmp->querier_query_interval, - pim_ifp->igmp_query_max_response_time_dsec); + pim_ifp->gm_query_max_response_time_dsec); - sqi = PIM_IGMP_SQI( - pim_ifp->igmp_default_query_interval); + sqi = PIM_IGMP_SQI(pim_ifp->gm_default_query_interval); oqpi_msec = PIM_IGMP_OQPI_MSEC( igmp->querier_robustness_variable, igmp->querier_query_interval, - pim_ifp->igmp_query_max_response_time_dsec); + pim_ifp->gm_query_max_response_time_dsec); lmqt_msec = PIM_IGMP_LMQT_MSEC( - pim_ifp->igmp_specific_query_max_response_time_dsec, - pim_ifp->igmp_last_member_query_count); + pim_ifp->gm_specific_query_max_response_time_dsec, + pim_ifp->gm_last_member_query_count); ohpi_msec = PIM_IGMP_OHPI_DSEC( igmp->querier_robustness_variable, igmp->querier_query_interval, - pim_ifp->igmp_query_max_response_time_dsec) - * 100; + pim_ifp->gm_query_max_response_time_dsec) * + 100; - qri_msec = pim_ifp->igmp_query_max_response_time_dsec - * 100; + qri_msec = + pim_ifp->gm_query_max_response_time_dsec * 100; if (pim_ifp->pim_sock_fd >= 0) mloop = pim_socket_mcastloop_get( pim_ifp->pim_sock_fd); else mloop = 0; - lmqc = pim_ifp->igmp_last_member_query_count; + lmqc = pim_ifp->gm_last_member_query_count; if (uj) { json_row = json_object_new_object(); @@ -824,7 +823,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]; @@ -833,14 +832,14 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty, if (!pim_ifp) continue; - if (!pim_ifp->igmp_join_list) + if (!pim_ifp->gm_join_list) continue; pri_addr = pim_find_primary_addr(ifp); pim_inet4_dump("<pri?>", pri_addr, pri_addr_str, sizeof(pri_addr_str)); - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_join_list, join_node, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_join_list, join_node, ij)) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -887,7 +886,7 @@ static void igmp_show_interface_join(struct pim_instance *pim, struct vty *vty, ifp->name, pri_addr_str, source_str, group_str, ij->sock_fd, uptime); } - } /* for (pim_ifp->igmp_join_list) */ + } /* for (pim_ifp->gm_join_list) */ } /* for (iflist) */ @@ -1330,7 +1329,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; @@ -1340,7 +1339,7 @@ static void igmp_show_statistics(struct pim_instance *pim, struct vty *vty, if (ifname && strcmp(ifname, ifp->name)) continue; - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) { igmp_stats_add(&rx_stats, &igmp->rx_stats); } @@ -1741,7 +1740,7 @@ static void pim_show_join_helper(struct vty *vty, struct pim_interface *pim_ifp, } static void pim_show_join(struct pim_instance *pim, struct vty *vty, - struct prefix_sg *sg, bool uj) + pim_sgaddr *sg, bool uj) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; @@ -2439,7 +2438,7 @@ static const char *pim_reg_state2brief_str(enum pim_reg_state reg_state, } static void pim_show_upstream(struct pim_instance *pim, struct vty *vty, - struct prefix_sg *sg, bool uj) + pim_sgaddr *sg, bool uj) { struct pim_upstream *up; time_t now; @@ -3423,13 +3422,13 @@ 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; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, grp)) { char group_str[INET_ADDRSTRLEN]; char hhmmss[10]; @@ -3517,18 +3516,18 @@ 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; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, grp)) { 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, @@ -3570,17 +3569,17 @@ 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; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, 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)); @@ -3610,7 +3609,7 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) uptime); } /* scan group sources */ - } /* scan igmp groups */ + } /* scan igmp groups */ } /* scan interfaces */ } @@ -3626,17 +3625,17 @@ 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; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_group_list, grpnode, 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)); @@ -3654,7 +3653,7 @@ static void igmp_show_source_retransmission(struct pim_instance *pim, src->source_query_retransmit_count); } /* scan group sources */ - } /* scan igmp groups */ + } /* scan igmp groups */ } /* scan interfaces */ } @@ -3794,6 +3793,7 @@ static const char *pim_cli_get_vrf_name(struct vty *vty) return yang_dnode_get_string(vrf_node, "./name"); } +#if PIM_IPV != 6 /** * Compatibility function to keep the legacy mesh group CLI behavior: * Delete group when there are no more configurations in it. @@ -3815,7 +3815,7 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']", + FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); /* Group must exists, otherwise just quit. */ if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) @@ -3841,6 +3841,7 @@ static void pim_cli_legacy_mesh_group_behavior(struct vty *vty, /* No configurations found: delete it. */ nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY, NULL); } +#endif /* PIM_IPV != 6 */ DEFUN (clear_ip_interfaces, clear_ip_interfaces_cmd, @@ -3908,7 +3909,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) @@ -3923,9 +3924,9 @@ static void clear_mroute(struct pim_instance *pim) /* clean up all igmp groups */ - if (pim_ifp->igmp_group_list) { - while (pim_ifp->igmp_group_list->count) { - grp = listnode_head(pim_ifp->igmp_group_list); + if (pim_ifp->gm_group_list) { + while (pim_ifp->gm_group_list->count) { + grp = listnode_head(pim_ifp->gm_group_list); igmp_group_delete(grp); } } @@ -4603,7 +4604,7 @@ DEFPY (show_ip_pim_join, "The Group\n" JSON_STR) { - struct prefix_sg sg = {0}; + pim_sgaddr sg = {0}; struct vrf *v; bool uj = !!json; struct pim_instance *pim; @@ -4644,7 +4645,7 @@ DEFUN (show_ip_pim_join_vrf_all, "PIM interface join information\n" JSON_STR) { - struct prefix_sg sg = {0}; + pim_sgaddr sg = {0}; bool uj = use_json(argc, argv); struct vrf *vrf; bool first = true; @@ -5223,7 +5224,7 @@ DEFPY (show_ip_pim_upstream, "The Group\n" JSON_STR) { - struct prefix_sg sg = {0}; + pim_sgaddr sg = {0}; struct vrf *v; bool uj = !!json; struct pim_instance *pim; @@ -5263,7 +5264,7 @@ DEFUN (show_ip_pim_upstream_vrf_all, "PIM upstream information\n" JSON_STR) { - struct prefix_sg sg = {0}; + pim_sgaddr sg = {0}; bool uj = use_json(argc, argv); struct vrf *vrf; bool first = true; @@ -5888,7 +5889,7 @@ DEFUN(show_ip_multicast_count_vrf_all, } static void show_mroute(struct pim_instance *pim, struct vty *vty, - struct prefix_sg *sg, bool fill, bool uj) + pim_sgaddr *sg, bool fill, bool uj) { struct listnode *node; struct channel_oil *c_oil; @@ -6273,7 +6274,7 @@ DEFPY (show_ip_mroute, "Fill in Assumed data\n" JSON_STR) { - struct prefix_sg sg = {0}; + pim_sgaddr sg = {0}; struct pim_instance *pim; struct vrf *v; @@ -6311,7 +6312,7 @@ DEFUN (show_ip_mroute_vrf_all, "Fill in Assumed data\n" JSON_STR) { - struct prefix_sg sg = {0}; + pim_sgaddr sg = {0}; bool uj = use_json(argc, argv); int idx = 4; struct vrf *vrf; @@ -6791,13 +6792,13 @@ DEFUN (ip_pim_spt_switchover_infinity, return CMD_WARNING_CONFIG_FAILED; snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", sizeof(spt_plist_xpath)); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(spt_action_xpath, "/spt-switchover/spt-action", sizeof(spt_action_xpath)); @@ -6830,13 +6831,13 @@ DEFUN (ip_pim_spt_switchover_infinity_plist, return CMD_WARNING_CONFIG_FAILED; snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", sizeof(spt_plist_xpath)); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(spt_action_xpath, "/spt-switchover/spt-action", sizeof(spt_action_xpath)); @@ -6867,13 +6868,13 @@ DEFUN (no_ip_pim_spt_switchover_infinity, return CMD_WARNING_CONFIG_FAILED; snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", sizeof(spt_plist_xpath)); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(spt_action_xpath, "/spt-switchover/spt-action", sizeof(spt_action_xpath)); @@ -6905,13 +6906,13 @@ DEFUN (no_ip_pim_spt_switchover_infinity_plist, return CMD_WARNING_CONFIG_FAILED; snprintf(spt_plist_xpath, sizeof(spt_plist_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(spt_plist_xpath, "/spt-switchover/spt-infinity-prefix-list", sizeof(spt_plist_xpath)); snprintf(spt_action_xpath, sizeof(spt_action_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(spt_action_xpath, "/spt-switchover/spt-action", sizeof(spt_action_xpath)); @@ -6940,7 +6941,7 @@ DEFPY (pim_register_accept_list, return CMD_WARNING_CONFIG_FAILED; snprintf(reg_alist_xpath, sizeof(reg_alist_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(reg_alist_xpath, "/register-accept-list", sizeof(reg_alist_xpath)); @@ -6963,8 +6964,13 @@ DEFUN (ip_pim_joinprune_time, "Join Prune Send Interval\n" "Seconds\n") { - nb_cli_enqueue_change(vty, "/frr-pim:pim/join-prune-interval", - NB_OP_MODIFY, argv[3]->arg); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + "frr-routing:ipv4"); + strlcat(xpath, "/join-prune-interval", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[3]->arg); return nb_cli_apply_changes(vty, NULL); } @@ -6978,8 +6984,13 @@ DEFUN (no_ip_pim_joinprune_time, "Join Prune Send Interval\n" IGNORED_IN_NO_STR) { - nb_cli_enqueue_change(vty, "/frr-pim:pim/join-prune-interval", - NB_OP_DESTROY, NULL); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + "frr-routing:ipv4"); + strlcat(xpath, "/join-prune-interval", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -6992,8 +7003,13 @@ DEFUN (ip_pim_register_suppress, "Register Suppress Timer\n" "Seconds\n") { - nb_cli_enqueue_change(vty, "/frr-pim:pim/register-suppress-time", - NB_OP_MODIFY, argv[3]->arg); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + "frr-routing:ipv4"); + strlcat(xpath, "/register-suppress-time", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[3]->arg); return nb_cli_apply_changes(vty, NULL); } @@ -7007,8 +7023,13 @@ DEFUN (no_ip_pim_register_suppress, "Register Suppress Timer\n" IGNORED_IN_NO_STR) { - nb_cli_enqueue_change(vty, "/frr-pim:pim/register-suppress-time", - NB_OP_DESTROY, NULL); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + "frr-routing:ipv4"); + strlcat(xpath, "/register-suppress-time", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -7030,7 +7051,8 @@ DEFUN (ip_pim_rp_keep_alive, return CMD_WARNING_CONFIG_FAILED; snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname); + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", sizeof(rp_ka_timer_xpath)); @@ -7054,10 +7076,16 @@ DEFUN (no_ip_pim_rp_keep_alive, char rp_ka_timer[6]; char rp_ka_timer_xpath[XPATH_MAXLEN]; uint v; + char rs_timer_xpath[XPATH_MAXLEN]; + + snprintf(rs_timer_xpath, sizeof(rs_timer_xpath), + FRR_PIM_ROUTER_XPATH, "frr-routing:ipv4"); + strlcat(rs_timer_xpath, "/register-suppress-time", + sizeof(rs_timer_xpath)); /* RFC4601 */ v = yang_dnode_get_uint16(vty->candidate_config->dnode, - "/frr-pim:pim/register-suppress-time"); + rs_timer_xpath); v = 3 * v + PIM_REGISTER_PROBE_TIME_DEFAULT; if (v > UINT16_MAX) v = UINT16_MAX; @@ -7068,7 +7096,8 @@ DEFUN (no_ip_pim_rp_keep_alive, return CMD_WARNING_CONFIG_FAILED; snprintf(rp_ka_timer_xpath, sizeof(rp_ka_timer_xpath), - FRR_PIM_XPATH, "frr-pim:pimd", "pim", vrfname); + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, + "frr-routing:ipv4"); strlcat(rp_ka_timer_xpath, "/rp-keep-alive-timer", sizeof(rp_ka_timer_xpath)); @@ -7093,8 +7122,8 @@ DEFUN (ip_pim_keep_alive, if (vrfname == NULL) return CMD_WARNING_CONFIG_FAILED; - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH, - "frr-pim:pimd", "pim", vrfname); + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_MODIFY, @@ -7119,8 +7148,8 @@ DEFUN (no_ip_pim_keep_alive, if (vrfname == NULL) return CMD_WARNING_CONFIG_FAILED; - snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_XPATH, - "frr-pim:pimd", "pim", vrfname); + snprintf(ka_timer_xpath, sizeof(ka_timer_xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ka_timer_xpath, "/keep-alive-timer", sizeof(ka_timer_xpath)); nb_cli_enqueue_change(vty, ka_timer_xpath, NB_OP_DESTROY, NULL); @@ -7136,8 +7165,13 @@ DEFUN (ip_pim_packets, "packets to process at one time per fd\n" "Number of packets\n") { - nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_MODIFY, - argv[3]->arg); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + "frr-routing:ipv4"); + strlcat(xpath, "/packets", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_MODIFY, argv[3]->arg); return nb_cli_apply_changes(vty, NULL); } @@ -7151,7 +7185,13 @@ DEFUN (no_ip_pim_packets, "packets to process at one time per fd\n" IGNORED_IN_NO_STR) { - nb_cli_enqueue_change(vty, "/frr-pim:pim/packets", NB_OP_DESTROY, NULL); + char xpath[XPATH_MAXLEN]; + + snprintf(xpath, sizeof(xpath), FRR_PIM_ROUTER_XPATH, + "frr-routing:ipv4"); + strlcat(xpath, "/packets", sizeof(xpath)); + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, NULL); } @@ -7200,7 +7240,7 @@ DEFUN (ip_pim_v6_secondary, return CMD_WARNING_CONFIG_FAILED; snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(send_v6_secondary_xpath, "/send-v6-secondary", sizeof(send_v6_secondary_xpath)); @@ -7227,7 +7267,7 @@ DEFUN (no_ip_pim_v6_secondary, return CMD_WARNING_CONFIG_FAILED; snprintf(send_v6_secondary_xpath, sizeof(send_v6_secondary_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(send_v6_secondary_xpath, "/send-v6-secondary", sizeof(send_v6_secondary_xpath)); @@ -7441,7 +7481,7 @@ DEFUN (ip_pim_ssm_prefix_list, if (vrfname == NULL) return CMD_WARNING_CONFIG_FAILED; - snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_AF_XPATH, + snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); @@ -7467,7 +7507,7 @@ DEFUN (no_ip_pim_ssm_prefix_list, return CMD_WARNING_CONFIG_FAILED; snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); @@ -7496,7 +7536,7 @@ DEFUN (no_ip_pim_ssm_prefix_list_name, return CMD_WARNING_CONFIG_FAILED; snprintf(ssm_plist_xpath, sizeof(ssm_plist_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ssm_plist_xpath, "/ssm-prefix-list", sizeof(ssm_plist_xpath)); ssm_plist_dnode = yang_dnode_get(vty->candidate_config->dnode, @@ -7655,7 +7695,7 @@ DEFUN (ip_ssmpingd, return CMD_WARNING_CONFIG_FAILED; snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip", sizeof(ssmpingd_ip_xpath)); @@ -7684,7 +7724,7 @@ DEFUN (no_ip_ssmpingd, return CMD_WARNING_CONFIG_FAILED; snprintf(ssmpingd_ip_xpath, sizeof(ssmpingd_ip_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ssmpingd_ip_xpath, "/ssm-pingd-source-ip", sizeof(ssmpingd_ip_xpath)); @@ -7709,8 +7749,8 @@ DEFUN (ip_pim_ecmp, if (vrfname == NULL) return CMD_WARNING_CONFIG_FAILED; - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH, - "frr-pim:pimd", "pim", vrfname); + snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "true"); @@ -7732,8 +7772,8 @@ DEFUN (no_ip_pim_ecmp, if (vrfname == NULL) return CMD_WARNING_CONFIG_FAILED; - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH, - "frr-pim:pimd", "pim", vrfname); + snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); nb_cli_enqueue_change(vty, ecmp_xpath, NB_OP_MODIFY, "false"); @@ -7757,12 +7797,12 @@ DEFUN (ip_pim_ecmp_rebalance, if (vrfname == NULL) return CMD_WARNING_CONFIG_FAILED; - snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_XPATH, - "frr-pim:pimd", "pim", vrfname); + snprintf(ecmp_xpath, sizeof(ecmp_xpath), FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ecmp_xpath, "/ecmp", sizeof(ecmp_xpath)); snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_XPATH, - "frr-pim:pimd", "pim", vrfname); + FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", sizeof(ecmp_rebalance_xpath)); @@ -7789,8 +7829,8 @@ DEFUN (no_ip_pim_ecmp_rebalance, return CMD_WARNING_CONFIG_FAILED; snprintf(ecmp_rebalance_xpath, sizeof(ecmp_rebalance_xpath), - FRR_PIM_XPATH, - "frr-pim:pimd", "pim", vrfname); + FRR_PIM_VRF_XPATH, + "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); strlcat(ecmp_rebalance_xpath, "/ecmp-rebalance", sizeof(ecmp_rebalance_xpath)); @@ -7805,9 +7845,10 @@ DEFUN (interface_ip_igmp, IP_STR IFACE_IGMP_STR) { - nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, "true"); + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_no_ip_igmp, @@ -7821,10 +7862,12 @@ DEFUN (interface_no_ip_igmp, char pim_if_xpath[XPATH_MAXLEN + 20]; snprintf(pim_if_xpath, sizeof(pim_if_xpath), - "%s/frr-pim:pim", VTY_CURR_XPATH); + "%s/frr-pim:pim/address-family[address-family='%s']", + VTY_CURR_XPATH, "frr-routing:ipv4"); pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/pim-enable", pim_if_xpath); + FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!pim_enable_dnode) { nb_cli_enqueue_change(vty, pim_if_xpath, NB_OP_DESTROY, NULL); nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); @@ -7834,11 +7877,12 @@ DEFUN (interface_no_ip_igmp, NULL); nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); } else - nb_cli_enqueue_change(vty, "./igmp-enable", + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "false"); } - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_ip_igmp_join, @@ -7866,7 +7910,7 @@ DEFUN (interface_ip_igmp_join, } else source_str = "0.0.0.0"; - snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH, + snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv4", argv[idx_group]->arg, source_str); nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); @@ -7900,7 +7944,7 @@ DEFUN (interface_no_ip_igmp_join, } else source_str = "0.0.0.0"; - snprintf(xpath, sizeof(xpath), FRR_IGMP_JOIN_XPATH, + snprintf(xpath, sizeof(xpath), FRR_GMP_JOIN_XPATH, "frr-routing:ipv4", argv[idx_group]->arg, source_str); nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); @@ -7920,20 +7964,22 @@ DEFUN (interface_ip_igmp_query_interval, pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-pim:pim/pim-enable", VTY_CURR_XPATH); + FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!pim_enable_dnode) { - nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } else { if (!yang_dnode_get_bool(pim_enable_dnode, ".")) - nb_cli_enqueue_change(vty, "./igmp-enable", + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } nb_cli_enqueue_change(vty, "./query-interval", NB_OP_MODIFY, argv[3]->arg); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_no_ip_igmp_query_interval, @@ -7947,7 +7993,8 @@ DEFUN (interface_no_ip_igmp_query_interval, { nb_cli_enqueue_change(vty, "./query-interval", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_ip_igmp_version, @@ -7958,11 +8005,13 @@ DEFUN (interface_ip_igmp_version, "IGMP version\n" "IGMP version number\n") { - nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); - nb_cli_enqueue_change(vty, "./version", NB_OP_MODIFY, argv[3]->arg); + nb_cli_enqueue_change(vty, "./igmp-version", NB_OP_MODIFY, + argv[3]->arg); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_no_ip_igmp_version, @@ -7974,9 +8023,10 @@ DEFUN (interface_no_ip_igmp_version, "IGMP version\n" "IGMP version number\n") { - nb_cli_enqueue_change(vty, "./version", NB_OP_DESTROY, NULL); + nb_cli_enqueue_change(vty, "./igmp-version", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_ip_igmp_query_max_response_time, @@ -7991,21 +8041,23 @@ DEFUN (interface_ip_igmp_query_max_response_time, pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-pim:pim/pim-enable", VTY_CURR_XPATH); + FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!pim_enable_dnode) { - nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } else { if (!yang_dnode_get_bool(pim_enable_dnode, ".")) - nb_cli_enqueue_change(vty, "./igmp-enable", + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY, argv[3]->arg); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_no_ip_igmp_query_max_response_time, @@ -8019,7 +8071,8 @@ DEFUN (interface_no_ip_igmp_query_max_response_time, { nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec, @@ -8034,20 +8087,22 @@ DEFUN_HIDDEN (interface_ip_igmp_query_max_response_time_dsec, pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-pim:pim/pim-enable", VTY_CURR_XPATH); + FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!pim_enable_dnode) { - nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } else { if (!yang_dnode_get_bool(pim_enable_dnode, ".")) - nb_cli_enqueue_change(vty, "./igmp-enable", + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_MODIFY, argv[3]->arg); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec, @@ -8062,7 +8117,8 @@ DEFUN_HIDDEN (interface_no_ip_igmp_query_max_response_time_dsec, nb_cli_enqueue_change(vty, "./query-max-response-time", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_ip_igmp_last_member_query_count, @@ -8077,20 +8133,22 @@ DEFUN (interface_ip_igmp_last_member_query_count, pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-pim:pim/pim-enable", VTY_CURR_XPATH); + FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!pim_enable_dnode) { - nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } else { if (!yang_dnode_get_bool(pim_enable_dnode, ".")) - nb_cli_enqueue_change(vty, "./igmp-enable", + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_MODIFY, argv[3]->arg); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_no_ip_igmp_last_member_query_count, @@ -8105,7 +8163,8 @@ DEFUN (interface_no_ip_igmp_last_member_query_count, nb_cli_enqueue_change(vty, "./robustness-variable", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_ip_igmp_last_member_query_interval, @@ -8120,20 +8179,22 @@ DEFUN (interface_ip_igmp_last_member_query_interval, pim_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-pim:pim/pim-enable", VTY_CURR_XPATH); + FRR_PIM_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!pim_enable_dnode) { - nb_cli_enqueue_change(vty, "./igmp-enable", NB_OP_MODIFY, + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } else { if (!yang_dnode_get_bool(pim_enable_dnode, ".")) - nb_cli_enqueue_change(vty, "./igmp-enable", + nb_cli_enqueue_change(vty, "./enable", NB_OP_MODIFY, "true"); } nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_MODIFY, argv[3]->arg); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_no_ip_igmp_last_member_query_interval, @@ -8148,7 +8209,8 @@ DEFUN (interface_no_ip_igmp_last_member_query_interval, nb_cli_enqueue_change(vty, "./last-member-query-interval", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-igmp:igmp"); + return nb_cli_apply_changes(vty, FRR_GMP_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_ip_pim_drprio, @@ -8164,7 +8226,8 @@ DEFUN (interface_ip_pim_drprio, nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_MODIFY, argv[idx_number]->arg); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_no_ip_pim_drprio, @@ -8178,7 +8241,8 @@ DEFUN (interface_no_ip_pim_drprio, { nb_cli_enqueue_change(vty, "./dr-priority", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFPY_HIDDEN (interface_ip_igmp_query_generate, @@ -8219,7 +8283,7 @@ DEFPY_HIDDEN (pim_test_sg_keepalive, { struct pim_upstream *up; struct pim_instance *pim; - struct prefix_sg sg; + pim_sgaddr sg; sg.src = source; sg.grp = group; @@ -8276,7 +8340,9 @@ DEFPY (interface_ip_pim_activeactive, "true"); } - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN_HIDDEN (interface_ip_pim_ssm, @@ -8290,7 +8356,9 @@ DEFUN_HIDDEN (interface_ip_pim_ssm, nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - ret = nb_cli_apply_changes(vty, "./frr-pim:pim"); + ret = nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); if (ret != NB_OK) return ret; @@ -8310,7 +8378,9 @@ DEFUN_HIDDEN (interface_ip_pim_sm, { nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_ip_pim, @@ -8321,7 +8391,10 @@ DEFUN (interface_ip_pim, { nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); + } DEFUN_HIDDEN (interface_no_ip_pim_ssm, @@ -8336,10 +8409,12 @@ DEFUN_HIDDEN (interface_no_ip_pim_ssm, char igmp_if_xpath[XPATH_MAXLEN + 20]; snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), - "%s/frr-igmp:igmp", VTY_CURR_XPATH); + "%s/frr-gmp:gmp/address-family[address-family='%s']", + VTY_CURR_XPATH, "frr-routing:ipv4"); igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/igmp-enable", igmp_if_xpath); - + FRR_GMP_ENABLE_XPATH, + VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!igmp_enable_dnode) { nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); @@ -8353,7 +8428,8 @@ DEFUN_HIDDEN (interface_no_ip_pim_ssm, "false"); } - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN_HIDDEN (interface_no_ip_pim_sm, @@ -8368,9 +8444,12 @@ DEFUN_HIDDEN (interface_no_ip_pim_sm, char igmp_if_xpath[XPATH_MAXLEN + 20]; snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), - "%s/frr-igmp:igmp", VTY_CURR_XPATH); - igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/igmp-enable", igmp_if_xpath); + "%s/frr-gmp:gmp/address-family[address-family='%s']", + VTY_CURR_XPATH, "frr-routing:ipv4"); + igmp_enable_dnode = + yang_dnode_getf(vty->candidate_config->dnode, + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!igmp_enable_dnode) { nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); @@ -8385,7 +8464,9 @@ DEFUN_HIDDEN (interface_no_ip_pim_sm, "false"); } - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_no_ip_pim, @@ -8399,9 +8480,12 @@ DEFUN (interface_no_ip_pim, char igmp_if_xpath[XPATH_MAXLEN + 20]; snprintf(igmp_if_xpath, sizeof(igmp_if_xpath), - "%s/frr-igmp:igmp", VTY_CURR_XPATH); - igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/igmp-enable", igmp_if_xpath); + "%s/frr-gmp:gmp/address-family[address-family='%s']", + VTY_CURR_XPATH, "frr-routing:ipv4"); + igmp_enable_dnode = + yang_dnode_getf(vty->candidate_config->dnode, + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!igmp_enable_dnode) { nb_cli_enqueue_change(vty, igmp_if_xpath, NB_OP_DESTROY, NULL); @@ -8416,7 +8500,9 @@ DEFUN (interface_no_ip_pim, "false"); } - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } /* boundaries */ @@ -8433,7 +8519,7 @@ DEFUN(interface_ip_pim_boundary_oil, argv[4]->arg); return nb_cli_apply_changes(vty, - "./frr-pim:pim/address-family[address-family='%s']", + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); } @@ -8452,7 +8538,7 @@ DEFUN(interface_no_ip_pim_boundary_oil, NULL); return nb_cli_apply_changes(vty, - "./frr-pim:pim/address-family[address-family='%s']", + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); } @@ -8478,7 +8564,7 @@ DEFUN (interface_ip_mroute, argv[idx_interface]->arg); return nb_cli_apply_changes(vty, - "./frr-pim:pim/address-family[address-family='%s']/mroute[source-addr='%s'][group-addr='%s']", + FRR_PIM_MROUTE_XPATH, "frr-routing:ipv4", source_str, argv[idx_ipv4]->arg); } @@ -8504,7 +8590,7 @@ DEFUN (interface_no_ip_mroute, nb_cli_enqueue_change(vty, ".", NB_OP_DESTROY, NULL); return nb_cli_apply_changes(vty, - "./frr-pim:pim/address-family[address-family='%s']/mroute[source-addr='%s'][group-addr='%s']", + FRR_PIM_MROUTE_XPATH, "frr-routing:ipv4", source_str, argv[idx_ipv4]->arg); } @@ -8524,7 +8610,8 @@ DEFUN (interface_ip_pim_hello, igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-igmp:igmp/igmp-enable", VTY_CURR_XPATH); + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!igmp_enable_dnode) { nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); @@ -8541,7 +8628,9 @@ DEFUN (interface_ip_pim_hello, nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_MODIFY, argv[idx_hold]->arg); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (interface_no_ip_pim_hello, @@ -8557,7 +8646,9 @@ DEFUN (interface_no_ip_pim_hello, nb_cli_enqueue_change(vty, "./hello-interval", NB_OP_DESTROY, NULL); nb_cli_enqueue_change(vty, "./hello-holdtime", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (debug_igmp, @@ -9205,7 +9296,7 @@ DEFUN (interface_pim_use_source, nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, argv[3]->arg); return nb_cli_apply_changes(vty, - "./frr-pim:pim/address-family[address-family='%s']", + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); } @@ -9221,7 +9312,7 @@ DEFUN (interface_no_pim_use_source, nb_cli_enqueue_change(vty, "./use-source", NB_OP_MODIFY, "0.0.0.0"); return nb_cli_apply_changes(vty, - "./frr-pim:pim/address-family[address-family='%s']", + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); } @@ -9238,7 +9329,8 @@ DEFPY (ip_pim_bfd, igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-igmp:igmp/igmp-enable", VTY_CURR_XPATH); + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!igmp_enable_dnode) nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); @@ -9252,7 +9344,9 @@ DEFPY (ip_pim_bfd, if (prof) nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_MODIFY, prof); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFPY(no_ip_pim_bfd_profile, no_ip_pim_bfd_profile_cmd, @@ -9266,7 +9360,9 @@ DEFPY(no_ip_pim_bfd_profile, no_ip_pim_bfd_profile_cmd, { nb_cli_enqueue_change(vty, "./bfd/profile", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (no_ip_pim_bfd, @@ -9279,7 +9375,9 @@ DEFUN (no_ip_pim_bfd, { nb_cli_enqueue_change(vty, "./bfd", NB_OP_DESTROY, NULL); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, + "frr-routing:ipv4"); } DEFUN (ip_pim_bsm, @@ -9293,7 +9391,8 @@ DEFUN (ip_pim_bsm, igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-igmp:igmp/igmp-enable", VTY_CURR_XPATH); + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!igmp_enable_dnode) nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); @@ -9305,7 +9404,8 @@ DEFUN (ip_pim_bsm, nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "true"); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); } DEFUN (no_ip_pim_bsm, @@ -9318,7 +9418,8 @@ DEFUN (no_ip_pim_bsm, { nb_cli_enqueue_change(vty, "./bsm", NB_OP_MODIFY, "false"); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); } DEFUN (ip_pim_ucast_bsm, @@ -9332,7 +9433,8 @@ DEFUN (ip_pim_ucast_bsm, igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-igmp:igmp/igmp-enable", VTY_CURR_XPATH); + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!igmp_enable_dnode) nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); @@ -9344,7 +9446,9 @@ DEFUN (ip_pim_ucast_bsm, nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "true"); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); + } DEFUN (no_ip_pim_ucast_bsm, @@ -9357,7 +9461,8 @@ DEFUN (no_ip_pim_ucast_bsm, { nb_cli_enqueue_change(vty, "./unicast-bsm", NB_OP_MODIFY, "false"); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); } #if HAVE_BFDD > 0 @@ -9391,7 +9496,8 @@ DEFUN_HIDDEN ( igmp_enable_dnode = yang_dnode_getf(vty->candidate_config->dnode, - "%s/frr-igmp:igmp/igmp-enable", VTY_CURR_XPATH); + FRR_GMP_ENABLE_XPATH, VTY_CURR_XPATH, + "frr-routing:ipv4"); if (!igmp_enable_dnode) nb_cli_enqueue_change(vty, "./pim-enable", NB_OP_MODIFY, "true"); @@ -9409,7 +9515,8 @@ DEFUN_HIDDEN ( nb_cli_enqueue_change(vty, "./bfd/detect_mult", NB_OP_MODIFY, argv[idx_number]->arg); - return nb_cli_apply_changes(vty, "./frr-pim:pim"); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); } #if HAVE_BFDD == 0 @@ -9424,6 +9531,7 @@ ALIAS(no_ip_pim_bfd, no_ip_pim_bfd_param_cmd, "Desired min transmit interval\n") #endif /* !HAVE_BFDD */ +#if PIM_IPV != 6 DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, "ip msdp peer A.B.C.D$peer source A.B.C.D$source", IP_STR @@ -9442,7 +9550,7 @@ DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, return CMD_WARNING_CONFIG_FAILED; snprintf(msdp_peer_source_xpath, sizeof(msdp_peer_source_xpath), - FRR_PIM_AF_XPATH, "frr-pim:pimd", "pim", vrfname, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); snprintf(temp_xpath, sizeof(temp_xpath), "/msdp-peer[peer-ip='%s']/source-ip", peer_str); @@ -9452,7 +9560,8 @@ DEFPY(ip_msdp_peer, ip_msdp_peer_cmd, nb_cli_enqueue_change(vty, msdp_peer_source_xpath, NB_OP_MODIFY, source_str); - return nb_cli_apply_changes(vty, NULL); + return nb_cli_apply_changes(vty, + FRR_PIM_INTERFACE_XPATH, "frr-routing:ipv4"); } DEFPY(ip_msdp_timers, ip_msdp_timers_cmd, @@ -9534,7 +9643,7 @@ DEFUN (no_ip_msdp_peer, return CMD_WARNING_CONFIG_FAILED; snprintf(msdp_peer_xpath, sizeof(msdp_peer_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4"); snprintf(temp_xpath, sizeof(temp_xpath), "/msdp-peer[peer-ip='%s']", @@ -9566,7 +9675,7 @@ DEFPY(ip_msdp_mesh_group_member, /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']", + FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); @@ -9600,7 +9709,7 @@ DEFPY(no_ip_msdp_mesh_group_member, /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']", + FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) { @@ -9650,7 +9759,7 @@ DEFPY(ip_msdp_mesh_group_source, /* Create mesh group. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']", + FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); @@ -9681,7 +9790,7 @@ DEFPY(no_ip_msdp_mesh_group_source, /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']", + FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); nb_cli_enqueue_change(vty, xpath_value, NB_OP_CREATE, NULL); @@ -9716,7 +9825,7 @@ DEFPY(no_ip_msdp_mesh_group, /* Get mesh group base XPath. */ snprintf(xpath_value, sizeof(xpath_value), - FRR_PIM_AF_XPATH "/msdp-mesh-groups[name='%s']", + FRR_PIM_VRF_XPATH "/msdp-mesh-groups[name='%s']", "frr-pim:pimd", "pim", vrfname, "frr-routing:ipv4", gname); if (!yang_dnode_exists(vty->candidate_config->dnode, xpath_value)) return CMD_SUCCESS; @@ -10465,6 +10574,7 @@ DEFUN (show_ip_msdp_sa_sg_vrf_all, return CMD_SUCCESS; } +#endif /* PIM_IPV != 6 */ struct pim_sg_cache_walk_data { struct vty *vty; @@ -10596,7 +10706,7 @@ static void pim_show_vxlan_sg_one(struct pim_instance *pim, bool uj) { json_object *json = NULL; - struct prefix_sg sg; + pim_sgaddr sg; int result = 0; struct pim_vxlan_sg *vxlan_sg; const char *iif_name; @@ -10616,8 +10726,6 @@ static void pim_show_vxlan_sg_one(struct pim_instance *pim, return; } - sg.family = AF_INET; - sg.prefixlen = IPV4_MAX_BITLEN; if (uj) json = json_object_new_object(); @@ -10758,7 +10866,7 @@ DEFUN_HIDDEN (no_ip_pim_mlag, { char mlag_xpath[XPATH_MAXLEN]; - snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_AF_XPATH, + snprintf(mlag_xpath, sizeof(mlag_xpath), FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); strlcat(mlag_xpath, "/mlag", sizeof(mlag_xpath)); @@ -10791,7 +10899,7 @@ DEFUN_HIDDEN (ip_pim_mlag, char mlag_reg_address_xpath[XPATH_MAXLEN]; snprintf(mlag_peerlink_rif_xpath, sizeof(mlag_peerlink_rif_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); strlcat(mlag_peerlink_rif_xpath, "/mlag/peerlink-rif", sizeof(mlag_peerlink_rif_xpath)); @@ -10801,7 +10909,7 @@ DEFUN_HIDDEN (ip_pim_mlag, argv[idx]->arg); snprintf(mlag_my_role_xpath, sizeof(mlag_my_role_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); strlcat(mlag_my_role_xpath, "/mlag/my-role", sizeof(mlag_my_role_xpath)); @@ -10821,7 +10929,7 @@ DEFUN_HIDDEN (ip_pim_mlag, } snprintf(mlag_peer_state_xpath, sizeof(mlag_peer_state_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); strlcat(mlag_peer_state_xpath, "/mlag/peer-state", sizeof(mlag_peer_state_xpath)); @@ -10841,7 +10949,7 @@ DEFUN_HIDDEN (ip_pim_mlag, } snprintf(mlag_reg_address_xpath, sizeof(mlag_reg_address_xpath), - FRR_PIM_AF_XPATH, + FRR_PIM_VRF_XPATH, "frr-pim:pimd", "pim", "default", "frr-routing:ipv4"); strlcat(mlag_reg_address_xpath, "/mlag/reg-address", sizeof(mlag_reg_address_xpath)); @@ -10908,10 +11016,12 @@ void pim_cmd_init(void) install_element(VRF_NODE, &ip_ssmpingd_cmd); install_element(CONFIG_NODE, &no_ip_ssmpingd_cmd); install_element(VRF_NODE, &no_ip_ssmpingd_cmd); +#if PIM_IPV != 6 install_element(CONFIG_NODE, &ip_msdp_peer_cmd); install_element(VRF_NODE, &ip_msdp_peer_cmd); install_element(CONFIG_NODE, &no_ip_msdp_peer_cmd); install_element(VRF_NODE, &no_ip_msdp_peer_cmd); +#endif /* PIM_IPV != 6 */ install_element(CONFIG_NODE, &ip_pim_ecmp_cmd); install_element(VRF_NODE, &ip_pim_ecmp_cmd); install_element(CONFIG_NODE, &no_ip_pim_ecmp_cmd); @@ -11080,12 +11190,14 @@ void pim_cmd_init(void) install_element(ENABLE_NODE, &no_debug_pim_mlag_cmd); install_element(ENABLE_NODE, &debug_pim_vxlan_cmd); install_element(ENABLE_NODE, &no_debug_pim_vxlan_cmd); +#if PIM_IPV != 6 install_element(ENABLE_NODE, &debug_msdp_cmd); install_element(ENABLE_NODE, &no_debug_msdp_cmd); install_element(ENABLE_NODE, &debug_msdp_events_cmd); install_element(ENABLE_NODE, &no_debug_msdp_events_cmd); install_element(ENABLE_NODE, &debug_msdp_packets_cmd); install_element(ENABLE_NODE, &no_debug_msdp_packets_cmd); +#endif /* PIM_IPV != 6 */ install_element(ENABLE_NODE, &debug_mtrace_cmd); install_element(ENABLE_NODE, &no_debug_mtrace_cmd); install_element(ENABLE_NODE, &debug_bsm_cmd); @@ -11127,17 +11239,20 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd); install_element(CONFIG_NODE, &debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd); +#if PIM_IPV != 6 install_element(CONFIG_NODE, &debug_msdp_cmd); install_element(CONFIG_NODE, &no_debug_msdp_cmd); install_element(CONFIG_NODE, &debug_msdp_events_cmd); install_element(CONFIG_NODE, &no_debug_msdp_events_cmd); install_element(CONFIG_NODE, &debug_msdp_packets_cmd); install_element(CONFIG_NODE, &no_debug_msdp_packets_cmd); +#endif /* PIM_IPV != 6 */ install_element(CONFIG_NODE, &debug_mtrace_cmd); install_element(CONFIG_NODE, &no_debug_mtrace_cmd); install_element(CONFIG_NODE, &debug_bsm_cmd); install_element(CONFIG_NODE, &no_debug_bsm_cmd); +#if PIM_IPV != 6 install_element(CONFIG_NODE, &ip_msdp_timers_cmd); install_element(VRF_NODE, &ip_msdp_timers_cmd); install_element(CONFIG_NODE, &no_ip_msdp_timers_cmd); @@ -11160,6 +11275,7 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_msdp_sa_sg_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_msdp_mesh_group_cmd); install_element(VIEW_NODE, &show_ip_msdp_mesh_group_vrf_all_cmd); +#endif /* PIM_IPV != 6 */ install_element(VIEW_NODE, &show_ip_pim_ssm_range_cmd); install_element(VIEW_NODE, &show_ip_pim_group_type_cmd); install_element(VIEW_NODE, &show_ip_pim_vxlan_sg_cmd); 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 60152f355e..8b27809c7c 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -125,15 +125,14 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, pim_ifp->mroute_vif_index = -1; pim_ifp->igmp_version = IGMP_DEFAULT_VERSION; - pim_ifp->igmp_default_robustness_variable = + pim_ifp->gm_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; - pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; - pim_ifp->igmp_query_max_response_time_dsec = + pim_ifp->gm_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; + pim_ifp->gm_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC; - pim_ifp->igmp_specific_query_max_response_time_dsec = + pim_ifp->gm_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC; - pim_ifp->igmp_last_member_query_count = - IGMP_DEFAULT_ROBUSTNESS_VARIABLE; + pim_ifp->gm_last_member_query_count = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; /* BSM config on interface: true by default */ pim_ifp->bsm_enable = true; @@ -145,8 +144,8 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, The number of seconds represented by the [Query Response Interval] must be less than the [Query Interval]. */ - assert(pim_ifp->igmp_query_max_response_time_dsec - < pim_ifp->igmp_default_query_interval); + assert(pim_ifp->gm_query_max_response_time_dsec < + pim_ifp->gm_default_query_interval); if (pim) PIM_IF_DO_PIM(pim_ifp->options); @@ -155,12 +154,12 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options); - pim_ifp->igmp_join_list = NULL; + pim_ifp->gm_join_list = NULL; pim_ifp->pim_neighbor_list = NULL; 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 */ @@ -200,7 +199,7 @@ void pim_if_delete(struct interface *ifp) pim_ifp = ifp->info; assert(pim_ifp); - if (pim_ifp->igmp_join_list) { + if (pim_ifp->gm_join_list) { pim_if_igmp_join_del_all(ifp); } @@ -289,7 +288,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,30 +531,30 @@ 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, + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr); if (!igmp) { /* if addr new, add IGMP socket */ if (ifc->address->family == AF_INET) - pim_igmp_sock_add(pim_ifp->igmp_socket_list, + pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp, false); } else if (igmp->mtrace_only) { igmp_sock_delete(igmp); - pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, - ifp, false); + pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp, + false); } /* Replay Static IGMP groups */ - if (pim_ifp->igmp_join_list) { + if (pim_ifp->gm_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, + for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij)) { /* Close socket and reopen with Source and Group */ @@ -583,17 +582,17 @@ 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, + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr); if (ifc->address->family == AF_INET) { if (igmp) igmp_sock_delete(igmp); /* if addr new, add IGMP socket */ - pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, - ifp, true); + pim_igmp_sock_add(pim_ifp->gm_socket_list, ifaddr, ifp, + true); } } /* igmp mtrace only */ @@ -648,7 +647,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) { @@ -664,7 +663,7 @@ static void pim_if_addr_del_igmp(struct connected *ifc) ifaddr = ifc->address->u.prefix4; /* lookup IGMP socket */ - igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr); + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, ifaddr); if (igmp) { /* if addr found, del IGMP socket */ igmp_sock_delete(igmp); @@ -828,26 +827,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; @@ -1179,17 +1158,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); @@ -1231,12 +1210,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; @@ -1265,7 +1244,7 @@ static struct igmp_join *igmp_join_new(struct interface *ifp, ij->source_addr = source_addr; ij->sock_creation = pim_time_monotonic_sec(); - listnode_add(pim_ifp->igmp_join_list, ij); + listnode_add(pim_ifp->gm_join_list, ij); return ij; } @@ -1274,7 +1253,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) { @@ -1282,12 +1261,12 @@ ferr_r pim_if_igmp_join_add(struct interface *ifp, struct in_addr group_addr, ifp->name); } - if (!pim_ifp->igmp_join_list) { - pim_ifp->igmp_join_list = list_new(); - pim_ifp->igmp_join_list->del = (void (*)(void *))igmp_join_free; + if (!pim_ifp->gm_join_list) { + pim_ifp->gm_join_list = list_new(); + pim_ifp->gm_join_list->del = (void (*)(void *))igmp_join_free; } - ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); + ij = igmp_join_find(pim_ifp->gm_join_list, group_addr, source_addr); /* This interface has already been configured to join this IGMP group */ @@ -1317,7 +1296,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) { @@ -1326,13 +1305,13 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, return -1; } - if (!pim_ifp->igmp_join_list) { + if (!pim_ifp->gm_join_list) { zlog_warn("%s: no IGMP join on interface %s", __func__, ifp->name); return -2; } - ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr); + ij = igmp_join_find(pim_ifp->gm_join_list, group_addr, source_addr); if (!ij) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -1359,11 +1338,11 @@ int pim_if_igmp_join_del(struct interface *ifp, struct in_addr group_addr, errno, safe_strerror(errno)); /* warning only */ } - listnode_delete(pim_ifp->igmp_join_list, ij); + listnode_delete(pim_ifp->gm_join_list, ij); igmp_join_free(ij); - if (listcount(pim_ifp->igmp_join_list) < 1) { - list_delete(&pim_ifp->igmp_join_list); - pim_ifp->igmp_join_list = 0; + if (listcount(pim_ifp->gm_join_list) < 1) { + list_delete(&pim_ifp->gm_join_list); + pim_ifp->gm_join_list = 0; } return 0; @@ -1374,7 +1353,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) { @@ -1383,10 +1362,10 @@ static void pim_if_igmp_join_del_all(struct interface *ifp) return; } - if (!pim_ifp->igmp_join_list) + if (!pim_ifp->gm_join_list) return; - for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij)) + for (ALL_LIST_ELEMENTS(pim_ifp->gm_join_list, node, nextnode, ij)) pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr); } @@ -1694,8 +1673,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; } diff --git a/pimd/pim_iface.h b/pimd/pim_iface.h index 55c278d6e2..f251c55e72 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -32,6 +32,7 @@ #include "pim_upstream.h" #include "pim_instance.h" #include "bfd.h" +#include "pim_str.h" #define PIM_IF_MASK_PIM (1 << 0) #define PIM_IF_MASK_IGMP (1 << 1) @@ -61,8 +62,22 @@ #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; + pim_addr address; struct list *us; }; @@ -80,31 +95,32 @@ struct pim_interface { uint32_t options; /* bit vector */ ifindex_t mroute_vif_index; struct pim_instance *pim; - - struct in_addr primary_address; /* remember addr to detect change */ + pim_addr primary_address; /* remember addr to detect change */ struct list *sec_addr_list; /* list of struct pim_secondary_addr */ - struct in_addr update_source; /* user can statically set the primary + pim_addr update_source; /* user can statically set the primary * address of the interface */ - int igmp_version; /* IGMP version */ - int igmp_default_robustness_variable; /* IGMPv3 QRV */ - int igmp_default_query_interval; /* IGMPv3 secs between general + int igmp_version; /* IGMP version */ + int gm_default_robustness_variable; /* IGMP or MLD QRV */ + int gm_default_query_interval; /* IGMP or MLD secs between general queries */ - int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in + int gm_query_max_response_time_dsec; /* IGMP or MLD Max Response Time in dsecs for general queries */ - int igmp_specific_query_max_response_time_dsec; /* IGMPv3 Max Response - Time in dsecs called - as last member query - interval, defines the - maximum response time - advertised in IGMP - group-specific - queries */ - int igmp_last_member_query_count; /* IGMP last member query count */ - struct list *igmp_socket_list; /* list of struct igmp_sock */ - struct list *igmp_join_list; /* list of struct igmp_join */ - struct list *igmp_group_list; /* list of struct igmp_group */ - struct hash *igmp_group_hash; + int gm_specific_query_max_response_time_dsec; /* IGMP or MLD Max + Response Time in dsecs + called as last member + query interval, defines + the maximum response + time advertised in IGMP + group-specific + queries */ + int gm_last_member_query_count; /* IGMP or MLD last member + query count + */ + struct list *gm_socket_list; /* list of struct IGMP or MLD sock */ + struct list *gm_join_list; /* list of struct IGMP or MLD join */ + struct list *gm_group_list; /* list of struct IGMP or MLD group */ + struct hash *gm_group_hash; int pim_sock_fd; /* PIM socket file descriptor */ struct thread *t_pim_sock_read; /* thread for reading PIM socket */ @@ -130,7 +146,7 @@ struct pim_interface { int64_t pim_dr_election_last; /* timestamp */ int pim_dr_election_count; int pim_dr_election_changes; - struct in_addr pim_dr_addr; + pim_addr pim_dr_addr; uint32_t pim_dr_priority; /* config */ int pim_dr_num_nondrpri_neighbors; /* neighbors without dr_pri */ @@ -161,6 +177,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 */ @@ -174,8 +191,8 @@ struct pim_interface { }; /* - if default_holdtime is set (>= 0), use it; - otherwise default_holdtime is 3.5 * hello_period + * if default_holdtime is set (>= 0), use it; + * otherwise default_holdtime is 3.5 * hello_period */ #define PIM_IF_DEFAULT_HOLDTIME(pim_ifp) \ (((pim_ifp)->pim_default_holdtime < 0) \ @@ -193,7 +210,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 3163f7f548..c0d693071f 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -446,8 +446,7 @@ void reset_ifassert_state(struct pim_ifchannel *ch) router->infinite_assert_metric); } -struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, - struct prefix_sg *sg) +struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, pim_sgaddr *sg) { struct pim_interface *pim_ifp; struct pim_ifchannel *ch; @@ -524,7 +523,7 @@ void pim_ifchannel_delete_on_noinfo(struct interface *ifp) */ static struct pim_ifchannel *pim_ifchannel_find_parent(struct pim_ifchannel *ch) { - struct prefix_sg parent_sg = ch->sg; + pim_sgaddr parent_sg = ch->sg; struct pim_ifchannel *parent = NULL; // (S,G) @@ -541,8 +540,7 @@ static struct pim_ifchannel *pim_ifchannel_find_parent(struct pim_ifchannel *ch) return NULL; } -struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, - struct prefix_sg *sg, +struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, uint8_t source_flags, int up_flags) { struct pim_interface *pim_ifp; @@ -752,7 +750,7 @@ static int on_ifjoin_prune_pending_timer(struct thread *t) } static void check_recv_upstream(int is_join, struct interface *recv_ifp, - struct in_addr upstream, struct prefix_sg *sg, + struct in_addr upstream, pim_sgaddr *sg, uint8_t source_flags, int holdtime) { struct pim_upstream *up; @@ -817,7 +815,7 @@ static void check_recv_upstream(int is_join, struct interface *recv_ifp, } static int nonlocal_upstream(int is_join, struct interface *recv_ifp, - struct in_addr upstream, struct prefix_sg *sg, + struct in_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *recv_pim_ifp; @@ -871,7 +869,7 @@ static void pim_ifchannel_ifjoin_handler(struct pim_ifchannel *ch, void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, - struct in_addr upstream, struct prefix_sg *sg, + struct in_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime) { struct pim_interface *pim_ifp; @@ -1036,7 +1034,7 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, } void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, - struct prefix_sg *sg, uint8_t source_flags, + pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime) { struct pim_ifchannel *ch; @@ -1172,8 +1170,8 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, } } -int pim_ifchannel_local_membership_add(struct interface *ifp, - struct prefix_sg *sg, bool is_vxlan) +int pim_ifchannel_local_membership_add(struct interface *ifp, pim_sgaddr *sg, + bool is_vxlan) { struct pim_ifchannel *ch, *starch; struct pim_interface *pim_ifp; @@ -1278,8 +1276,7 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, return 1; } -void pim_ifchannel_local_membership_del(struct interface *ifp, - struct prefix_sg *sg) +void pim_ifchannel_local_membership_del(struct interface *ifp, pim_sgaddr *sg) { struct pim_ifchannel *starch, *ch, *orig; struct pim_interface *pim_ifp; @@ -1567,10 +1564,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..ab405202e3 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -89,7 +89,7 @@ struct pim_ifchannel { struct pim_ifchannel *parent; struct list *sources; - struct prefix_sg sg; + pim_sgaddr sg; char sg_str[PIM_SG_LEN]; struct interface *interface; /* backpointer to interface */ uint32_t flags; @@ -106,7 +106,7 @@ struct pim_ifchannel { /* Per-interface (S,G) Assert State (Section 4.6.1 of RFC4601) */ enum pim_ifassert_state ifassert_state; struct thread *t_ifassert_timer; - struct in_addr ifassert_winner; + pim_addr ifassert_winner; struct pim_assert_metric ifassert_winner_metric; int64_t ifassert_creation; /* Record uptime of ifassert state */ struct pim_assert_metric ifassert_my_metric; @@ -123,21 +123,18 @@ void pim_ifchannel_delete(struct pim_ifchannel *ch); void pim_ifchannel_delete_all(struct interface *ifp); void pim_ifchannel_membership_clear(struct interface *ifp); void pim_ifchannel_delete_on_noinfo(struct interface *ifp); -struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, - struct prefix_sg *sg); -struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, - struct prefix_sg *sg, uint8_t ch_flags, - int up_flags); +struct pim_ifchannel *pim_ifchannel_find(struct interface *ifp, pim_sgaddr *sg); +struct pim_ifchannel *pim_ifchannel_add(struct interface *ifp, pim_sgaddr *sg, + uint8_t ch_flags, int up_flags); void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, - struct in_addr upstream, struct prefix_sg *sg, + struct in_addr upstream, pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime); void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, - struct prefix_sg *sg, uint8_t source_flags, + pim_sgaddr *sg, uint8_t source_flags, uint16_t holdtime); -int pim_ifchannel_local_membership_add(struct interface *ifp, - struct prefix_sg *sg, bool is_vxlan); -void pim_ifchannel_local_membership_del(struct interface *ifp, - struct prefix_sg *sg); +int pim_ifchannel_local_membership_add(struct interface *ifp, pim_sgaddr *sg, + bool is_vxlan); +void pim_ifchannel_local_membership_del(struct interface *ifp, pim_sgaddr *sg); void pim_ifchannel_ifjoin_switch(const char *caller, struct pim_ifchannel *ch, enum pim_ifjoin_state new_state); @@ -160,6 +157,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 68b3af72a7..cf7613f4e4 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; @@ -238,7 +226,7 @@ void pim_igmp_other_querier_timer_on(struct igmp_sock *igmp) */ other_querier_present_interval_msec = PIM_IGMP_OQPI_MSEC( igmp->querier_robustness_variable, igmp->querier_query_interval, - pim_ifp->igmp_query_max_response_time_dsec); + pim_ifp->gm_query_max_response_time_dsec); if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[INET_ADDRSTRLEN]; @@ -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) @@ -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; @@ -648,14 +636,14 @@ void pim_igmp_general_query_on(struct igmp_sock *igmp) * newly configured igmp interface send it out in 1 second * just to give the entire world a tiny bit of time to settle * else the query interval is: - * query_interval = pim_ifp->igmp_default_query_interval >> 2; + * query_interval = pim_ifp->gm_default_query_interval >> 2; */ - if (igmp->startup_query_count - == igmp->querier_robustness_variable) + if (igmp->startup_query_count == + igmp->querier_robustness_variable) query_interval = 1; else query_interval = PIM_IGMP_SQI( - pim_ifp->igmp_default_query_interval); + pim_ifp->gm_default_query_interval); --igmp->startup_query_count; } else { @@ -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; @@ -741,7 +729,7 @@ static int pim_igmp_general_query(struct thread *t) igmp_send_query(pim_ifp->igmp_version, 0 /* igmp_group */, igmp->fd, igmp->interface->name, query_buf, sizeof(query_buf), 0 /* num_sources */, dst_addr, group_addr, - pim_ifp->igmp_query_max_response_time_dsec, + pim_ifp->gm_query_max_response_time_dsec, 1 /* s_flag: always set for general queries */, igmp->querier_robustness_variable, igmp->querier_query_interval); @@ -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; @@ -799,10 +787,10 @@ void igmp_startup_mode_on(struct igmp_sock *igmp) /* Since we're (re)starting, reset QQI to default Query Interval */ - igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; + igmp->querier_query_interval = pim_ifp->gm_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) { @@ -856,13 +844,13 @@ void igmp_group_delete(struct igmp_group *group) group_timer_off(group); igmp_group_count_decr(pim_ifp); - listnode_delete(pim_ifp->igmp_group_list, group); - hash_release(pim_ifp->igmp_group_hash, group); + listnode_delete(pim_ifp->gm_group_list, group); + hash_release(pim_ifp->gm_group_hash, 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; @@ -887,11 +875,11 @@ void igmp_sock_delete(struct igmp_sock *igmp) pim_ifp = igmp->interface->info; - listnode_delete(pim_ifp->igmp_socket_list, igmp); + listnode_delete(pim_ifp->gm_socket_list, igmp); igmp_sock_free(igmp); - if (!listcount(pim_ifp->igmp_socket_list)) + if (!listcount(pim_ifp->gm_socket_list)) pim_igmp_if_reset(pim_ifp); } @@ -899,11 +887,11 @@ 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; - for (ALL_LIST_ELEMENTS(pim_ifp->igmp_socket_list, igmp_node, + for (ALL_LIST_ELEMENTS(pim_ifp->gm_socket_list, igmp_node, igmp_nextnode, igmp)) { igmp_sock_delete(igmp); } @@ -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; @@ -931,23 +919,23 @@ void pim_igmp_if_init(struct pim_interface *pim_ifp, struct interface *ifp) { char hash_name[64]; - pim_ifp->igmp_socket_list = list_new(); - pim_ifp->igmp_socket_list->del = (void (*)(void *))igmp_sock_free; + pim_ifp->gm_socket_list = list_new(); + pim_ifp->gm_socket_list->del = (void (*)(void *))igmp_sock_free; - pim_ifp->igmp_group_list = list_new(); - pim_ifp->igmp_group_list->del = (void (*)(void *))igmp_group_free; + pim_ifp->gm_group_list = list_new(); + pim_ifp->gm_group_list->del = (void (*)(void *))igmp_group_free; snprintf(hash_name, sizeof(hash_name), "IGMP %s hash", ifp->name); - pim_ifp->igmp_group_hash = hash_create( - igmp_group_hash_key, igmp_group_hash_equal, hash_name); + pim_ifp->gm_group_hash = hash_create(igmp_group_hash_key, + igmp_group_hash_equal, hash_name); } 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, + for (ALL_LIST_ELEMENTS(pim_ifp->gm_group_list, grp_node, grp_nextnode, grp)) { igmp_group_delete(grp); } @@ -957,20 +945,20 @@ void pim_igmp_if_fini(struct pim_interface *pim_ifp) { pim_igmp_if_reset(pim_ifp); - assert(pim_ifp->igmp_group_list); - assert(!listcount(pim_ifp->igmp_group_list)); + assert(pim_ifp->gm_group_list); + assert(!listcount(pim_ifp->gm_group_list)); - list_delete(&pim_ifp->igmp_group_list); - hash_free(pim_ifp->igmp_group_hash); + list_delete(&pim_ifp->gm_group_list); + hash_free(pim_ifp->gm_group_hash); - list_delete(&pim_ifp->igmp_socket_list); + list_delete(&pim_ifp->gm_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; @@ -990,7 +978,7 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, igmp->t_igmp_query_timer = NULL; igmp->t_other_querier_timer = NULL; /* no other querier present */ igmp->querier_robustness_variable = - pim_ifp->igmp_default_robustness_variable; + pim_ifp->gm_default_robustness_variable; igmp->sock_creation = pim_time_monotonic_sec(); igmp_stats_init(&igmp->rx_stats); @@ -1005,7 +993,7 @@ static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, /* igmp_startup_mode_on() will reset QQI: - igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; + igmp->querier_query_interval = pim_ifp->gm_default_query_interval; */ igmp_startup_mode_on(igmp); pim_igmp_general_query_on(igmp); @@ -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,21 +1180,21 @@ 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; - return hash_lookup(pim_ifp->igmp_group_hash, &lookup); + return hash_lookup(pim_ifp->gm_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); @@ -1259,8 +1246,8 @@ struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, /* initialize new group as INCLUDE {empty} */ group->group_filtermode_isexcl = 0; /* 0=INCLUDE, 1=EXCLUDE */ - listnode_add(pim_ifp->igmp_group_list, group); - group = hash_get(pim_ifp->igmp_group_hash, group, hash_alloc_intern); + listnode_add(pim_ifp->gm_group_list, group); + group = hash_get(pim_ifp->gm_group_hash, group, hash_alloc_intern); if (PIM_DEBUG_IGMP_TRACE) { char group_str[INET_ADDRSTRLEN]; @@ -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; @@ -1330,10 +1317,9 @@ void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver) group_addr.s_addr = PIM_NET_INADDR_ANY; if (PIM_DEBUG_IGMP_TRACE) - zlog_debug("Issuing general query on request on %s", - ifp->name); + zlog_debug("Issuing general query on request on %s", ifp->name); - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) { char query_buf[query_buf_size]; @@ -1341,7 +1327,7 @@ void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver) igmp->interface->name, query_buf, sizeof(query_buf), 0 /* num_sources */, dst_addr, group_addr, - pim_ifp->igmp_query_max_response_time_dsec, + pim_ifp->gm_query_max_response_time_dsec, 1 /* s_flag: always set for general queries */, igmp->querier_robustness_variable, igmp->querier_query_interval); diff --git a/pimd/pim_igmp.h b/pimd/pim_igmp.h index dfe986e8f5..b82b62ea74 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -26,6 +26,7 @@ #include "vty.h" #include "linklist.h" #include "pim_igmp_stats.h" +#include "pim_str.h" /* The following sizes are likely to support @@ -75,24 +76,24 @@ output |= *((ptr) + 1); \ } while (0) -struct igmp_join { - struct in_addr group_addr; - struct in_addr source_addr; +struct gm_join { + pim_addr group_addr; + pim_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; + pim_addr ifaddr; time_t sock_creation; struct thread *t_igmp_read; /* read: IGMP sockets */ struct thread *t_igmp_query_timer; /* timer: issue IGMP general queries */ struct thread *t_other_querier_timer; /* timer: other querier present */ - struct in_addr querier_addr; /* IP address of the querier */ + pim_addr querier_addr; /* IP address of the querier */ int querier_query_interval; /* QQI */ int querier_robustness_variable; /* QRV */ int startup_query_count; @@ -108,22 +109,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 +139,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 in_addr source_addr; +struct gm_source { + pim_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 +154,7 @@ struct igmp_source { int source_query_retransmit_count; }; -struct igmp_group { +struct gm_group { /* RFC 3376: 6.2.2. Definition of Group Timers @@ -176,40 +175,39 @@ struct igmp_group { /* compatibility mode - igmp v1, v2 or v3 */ int igmp_version; - - struct in_addr group_addr; + pim_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 42101bc48e..1518ef2322 100644 --- a/pimd/pim_igmp_mtrace.c +++ b/pimd/pim_igmp_mtrace.c @@ -106,13 +106,13 @@ static bool mtrace_fwd_info(struct pim_instance *pim, struct igmp_mtrace_rsp *rspp, struct interface **ifpp) { - struct prefix_sg sg; + pim_sgaddr sg; struct pim_upstream *up; struct interface *ifp_in; struct in_addr nh_addr; uint32_t total; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = mtracep->src_addr; sg.grp = mtracep->grp_addr; @@ -426,14 +426,14 @@ static int mtrace_un_forward_packet(struct pim_instance *pim, struct ip *ip_hdr, static int mtrace_mc_forward_packet(struct pim_instance *pim, struct ip *ip_hdr) { - struct prefix_sg sg; + pim_sgaddr sg; struct channel_oil *c_oil; struct listnode *chnode; struct listnode *chnextnode; struct pim_ifchannel *ch = NULL; int ret = -1; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.grp = ip_hdr->ip_dst; c_oil = pim_find_channel_oil(pim, &sg); @@ -477,14 +477,14 @@ static int mtrace_send_mc_response(struct pim_instance *pim, struct igmp_mtrace *mtracep, size_t mtrace_len) { - struct prefix_sg sg; + pim_sgaddr sg; struct channel_oil *c_oil; struct listnode *chnode; struct listnode *chnextnode; struct pim_ifchannel *ch = NULL; int ret = -1; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.grp = mtracep->rsp_addr; c_oil = pim_find_channel_oil(pim, &sg); @@ -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) { @@ -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..a7c7c99ebf 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; @@ -115,10 +115,11 @@ int igmp_v2_recv_report(struct igmp_sock *igmp, struct in_addr from, return 0; if (igmp_msg_len != IGMP_V12_MSG_SIZE) { - zlog_warn( - "Recv IGMPv2 REPORT from %s on %s: size=%d other than correct=%d", - from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); - return -1; + if (PIM_DEBUG_IGMP_PACKETS) + zlog_debug( + "Recv IGMPv2 REPORT from %s on %s: size=%d other than correct=%d", + from_str, ifp->name, igmp_msg_len, + IGMP_V12_MSG_SIZE); } if (igmp_validate_checksum(igmp_msg, igmp_msg_len) == -1) { @@ -158,7 +159,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; @@ -172,10 +173,11 @@ int igmp_v2_recv_leave(struct igmp_sock *igmp, struct ip *ip_hdr, return 0; if (igmp_msg_len != IGMP_V12_MSG_SIZE) { - zlog_warn( - "Recv IGMPv2 LEAVE from %s on %s: size=%d other than correct=%d", - from_str, ifp->name, igmp_msg_len, IGMP_V12_MSG_SIZE); - return -1; + if (PIM_DEBUG_IGMP_PACKETS) + zlog_debug( + "Recv IGMPv2 LEAVE from %s on %s: size=%d other than correct=%d", + from_str, ifp->name, igmp_msg_len, + IGMP_V12_MSG_SIZE); } if (igmp_validate_checksum(igmp_msg, igmp_msg_len) == -1) { 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..492af5f2d2 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,23 +57,23 @@ 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; - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) { qrv = MAX(qrv, igmp->querier_robustness_variable); qqi = MAX(qqi, igmp->querier_query_interval); } return PIM_IGMP_GMI_MSEC(qrv, qqi, - pim_ifp->igmp_query_max_response_time_dsec); + pim_ifp->gm_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,21 +975,21 @@ 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)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) { igmp_send_query( pim_ifp->igmp_version, group, igmp->fd, ifp->name, query_buf, query_buf_size, num_sources, group->group_addr, group->group_addr, - pim_ifp->igmp_specific_query_max_response_time_dsec, + pim_ifp->gm_specific_query_max_response_time_dsec, s_flag, igmp->querier_robustness_variable, igmp->querier_query_interval); } @@ -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 */ @@ -1022,8 +1021,8 @@ static void group_retransmit_group(struct igmp_group *group) char query_buf[query_buf_size]; - lmqc = pim_ifp->igmp_last_member_query_count; - lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; + lmqc = pim_ifp->gm_last_member_query_count; + lmqi_msec = 100 * pim_ifp->gm_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* @@ -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); @@ -1092,8 +1091,8 @@ static int group_retransmit_sources(struct igmp_group *group, pim_ifp = group->interface->info; - lmqc = pim_ifp->igmp_last_member_query_count; - lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; + lmqc = pim_ifp->gm_last_member_query_count; + lmqi_msec = 100 * pim_ifp->gm_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* Scan all group sources */ @@ -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 */ @@ -1284,7 +1283,7 @@ static void group_retransmit_timer_on(struct igmp_group *group) pim_ifp = group->interface->info; - lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; + lmqi_msec = 100 * pim_ifp->gm_specific_query_max_response_time_dsec; if (PIM_DEBUG_IGMP_TRACE) { char group_str[INET_ADDRSTRLEN]; @@ -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,13 +1313,13 @@ 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 */ pim_ifp = group->interface->info; - lmqc = pim_ifp->igmp_last_member_query_count; + lmqc = pim_ifp->gm_last_member_query_count; /* lower group timer to lmqt */ igmp_group_timer_lower_to_lmqt(group); @@ -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 */ @@ -1353,8 +1352,8 @@ static void source_query_send_by_flag(struct igmp_group *group, pim_ifp = group->interface->info; - lmqc = pim_ifp->igmp_last_member_query_count; - lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec; + lmqc = pim_ifp->gm_last_member_query_count; + lmqi_msec = 100 * pim_ifp->gm_specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* @@ -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; @@ -1510,8 +1509,8 @@ void igmp_group_timer_lower_to_lmqt(struct igmp_group *group) pim_ifp = ifp->info; ifname = ifp->name; - lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec; - lmqc = pim_ifp->igmp_last_member_query_count; + lmqi_dsec = pim_ifp->gm_specific_query_max_response_time_dsec; + lmqc = pim_ifp->gm_last_member_query_count; lmqt_msec = PIM_IGMP_LMQT_MSEC( lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ @@ -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; @@ -1545,8 +1544,8 @@ void igmp_source_timer_lower_to_lmqt(struct igmp_source *source) pim_ifp = ifp->info; ifname = ifp->name; - lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec; - lmqc = pim_ifp->igmp_last_member_query_count; + lmqi_dsec = pim_ifp->gm_specific_query_max_response_time_dsec; + lmqc = pim_ifp->gm_last_member_query_count; lmqt_msec = PIM_IGMP_LMQT_MSEC( lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ @@ -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; @@ -1718,7 +1717,7 @@ void igmp_v3_recv_query(struct igmp_sock *igmp, const char *from_str, resv_s_qrv = igmp_msg[8]; qrv = 7 & resv_s_qrv; igmp->querier_robustness_variable = - qrv ? qrv : pim_ifp->igmp_default_robustness_variable; + qrv ? qrv : pim_ifp->gm_default_robustness_variable; /* * RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code) @@ -1735,7 +1734,7 @@ void igmp_v3_recv_query(struct igmp_sock *igmp, const char *from_str, qqic = igmp_msg[9]; qqi = igmp_msg_decode8to16(qqic); igmp->querier_query_interval = - qqi ? qqi : pim_ifp->igmp_default_query_interval; + qqi ? qqi : pim_ifp->gm_default_query_interval; if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[INET_ADDRSTRLEN]; @@ -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_instance.c b/pimd/pim_instance.c index 5322c48f67..14f984508d 100644 --- a/pimd/pim_instance.c +++ b/pimd/pim_instance.c @@ -228,8 +228,7 @@ static int pim_vrf_config_write(struct vty *vty) void pim_vrf_init(void) { - vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, - pim_vrf_delete, NULL); + vrf_init(pim_vrf_new, pim_vrf_enable, pim_vrf_disable, pim_vrf_delete); vrf_cmd_init(pim_vrf_config_write); } diff --git a/pimd/pim_join.c b/pimd/pim_join.c index 4606aec6a1..5e96d39e8f 100644 --- a/pimd/pim_join.c +++ b/pimd/pim_join.c @@ -55,7 +55,7 @@ static void on_trace(const char *label, struct interface *ifp, static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, uint16_t holdtime, struct in_addr upstream, - struct prefix_sg *sg, uint8_t source_flags) + pim_sgaddr *sg, uint8_t source_flags) { struct pim_interface *pim_ifp = NULL; @@ -87,7 +87,7 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, struct pim_rpf *rp = RP(pim_ifp->pim, sg->grp); if (!rp) { - zlog_warn("%s: Lookup of RP failed for %pSG4", __func__, + zlog_warn("%s: Lookup of RP failed for %pSG", __func__, sg); return; } @@ -125,7 +125,7 @@ static void recv_join(struct interface *ifp, struct pim_neighbor *neigh, static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, uint16_t holdtime, struct in_addr upstream, - struct prefix_sg *sg, uint8_t source_flags) + pim_sgaddr *sg, uint8_t source_flags) { struct pim_interface *pim_ifp = NULL; @@ -160,7 +160,7 @@ static void recv_prune(struct interface *ifp, struct pim_neighbor *neigh, pim_inet4_dump("<received?>", sg->src, received_rp, sizeof(received_rp)); - zlog_debug("%s: Prune received with RP(%s) for %pSG4", + zlog_debug("%s: Prune received with RP(%s) for %pSG", __func__, received_rp, sg); } @@ -247,7 +247,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, /* Scan groups */ for (group = 0; group < msg_num_groups; ++group) { - struct prefix_sg sg; + pim_sgaddr sg; uint8_t msg_source_flags; uint16_t msg_num_joined_sources; uint16_t msg_num_pruned_sources; @@ -255,7 +255,7 @@ int pim_joinprune_recv(struct interface *ifp, struct pim_neighbor *neigh, struct pim_ifchannel *starg_ch = NULL, *sg_ch = NULL; bool filtered = false; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); addr_offset = pim_parse_addr_group(&sg, buf, pastend - buf); if (addr_offset < 1) { return -5; diff --git a/pimd/pim_jp_agg.h b/pimd/pim_jp_agg.h index d88ff8892b..506bf2d5ac 100644 --- a/pimd/pim_jp_agg.h +++ b/pimd/pim_jp_agg.h @@ -26,7 +26,7 @@ struct pim_jp_sources { }; struct pim_jp_agg_group { - struct in_addr group; + pim_addr group; struct list *sources; }; diff --git a/pimd/pim_macro.c b/pimd/pim_macro.c index c6961d30c2..81ef6962de 100644 --- a/pimd/pim_macro.c +++ b/pimd/pim_macro.c @@ -261,7 +261,7 @@ int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch) } */ struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf, - struct in_addr ifaddr) + pim_addr ifaddr) { struct pim_assert_metric metric; diff --git a/pimd/pim_macro.h b/pimd/pim_macro.h index f310e244e8..b88a84e2d2 100644 --- a/pimd/pim_macro.h +++ b/pimd/pim_macro.h @@ -33,7 +33,7 @@ int pim_macro_chisin_pim_include(const struct pim_ifchannel *ch); int pim_macro_chisin_joins_or_include(const struct pim_ifchannel *ch); int pim_macro_ch_could_assert_eval(const struct pim_ifchannel *ch); struct pim_assert_metric pim_macro_spt_assert_metric(const struct pim_rpf *rpf, - struct in_addr ifaddr); + pim_addr ifaddr); struct pim_assert_metric pim_macro_ch_my_assert_metric_eval(const struct pim_ifchannel *ch); int pim_macro_chisin_oiflist(const struct pim_ifchannel *ch); diff --git a/pimd/pim_main.c b/pimd/pim_main.c index 780595ca11..eb1cedd90d 100644 --- a/pimd/pim_main.c +++ b/pimd/pim_main.c @@ -81,7 +81,7 @@ static const struct frr_yang_module_info *const pimd_yang_modules[] = { &frr_routing_info, &frr_pim_info, &frr_pim_rp_info, - &frr_igmp_info, + &frr_gmp_info, }; FRR_DAEMON_INFO(pimd, PIM, .vty_port = PIMD_VTY_PORT, diff --git a/pimd/pim_mlag.c b/pimd/pim_mlag.c index 55d6e7e0fd..1f38b1c93d 100644 --- a/pimd/pim_mlag.c +++ b/pimd/pim_mlag.c @@ -253,11 +253,11 @@ static void pim_mlag_up_peer_add(struct mlag_mroute_add *msg) struct pim_upstream *up; struct pim_instance *pim; int flags = 0; - struct prefix_sg sg; + pim_sgaddr sg; struct vrf *vrf; char sg_str[PIM_SG_LEN]; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src.s_addr = htonl(msg->source_ip); sg.grp.s_addr = htonl(msg->group_ip); if (PIM_DEBUG_MLAG) @@ -327,11 +327,11 @@ static void pim_mlag_up_peer_del(struct mlag_mroute_del *msg) { struct pim_upstream *up; struct pim_instance *pim; - struct prefix_sg sg; + pim_sgaddr sg; struct vrf *vrf; char sg_str[PIM_SG_LEN]; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src.s_addr = htonl(msg->source_ip); sg.grp.s_addr = htonl(msg->group_ip); if (PIM_DEBUG_MLAG) @@ -737,17 +737,17 @@ static void pim_mlag_process_vxlan_update(struct mlag_vxlan *msg) static void pim_mlag_process_mroute_add(struct mlag_mroute_add msg) { if (PIM_DEBUG_MLAG) { - struct prefix_sg sg; + pim_sgaddr sg; sg.grp.s_addr = ntohl(msg.group_ip); sg.src.s_addr = ntohl(msg.source_ip); zlog_debug( - "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x (%pSG4) cost: %u", + "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x (%pSG) cost: %u", __func__, msg.vrf_name, msg.source_ip, msg.group_ip, &sg, msg.cost_to_rp); zlog_debug( - "(%pSG4)owner_id: %d, DR: %d, Dual active: %d, vrf_id: 0x%x intf_name: %s", + "(%pSG)owner_id: %d, DR: %d, Dual active: %d, vrf_id: 0x%x intf_name: %s", &sg, msg.owner_id, msg.am_i_dr, msg.am_i_dual_active, msg.vrf_id, msg.intf_name); } @@ -767,15 +767,15 @@ static void pim_mlag_process_mroute_add(struct mlag_mroute_add msg) static void pim_mlag_process_mroute_del(struct mlag_mroute_del msg) { if (PIM_DEBUG_MLAG) { - struct prefix_sg sg; + pim_sgaddr sg; sg.grp.s_addr = ntohl(msg.group_ip); sg.src.s_addr = ntohl(msg.source_ip); zlog_debug( - "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x(%pSG4)", + "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x(%pSG)", __func__, msg.vrf_name, msg.source_ip, msg.group_ip, &sg); - zlog_debug("(%pSG4)owner_id: %d, vrf_id: 0x%x intf_name: %s", + zlog_debug("(%pSG)owner_id: %d, vrf_id: 0x%x intf_name: %s", &sg, msg.owner_id, msg.vrf_id, msg.intf_name); } diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 7743bcc510..a01256dfb1 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -154,7 +154,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, struct pim_interface *pim_ifp = ifp->info; struct pim_upstream *up; struct pim_rpf *rpg; - struct prefix_sg sg; + pim_sgaddr sg; rpg = pim_ifp ? RP(pim_ifp->pim, msg->im_dst) : NULL; /* @@ -183,7 +183,7 @@ static int pim_mroute_msg_nocache(int fd, struct interface *ifp, return 0; } - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = msg->im_src; sg.grp = msg->im_dst; @@ -242,7 +242,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, const char *buf) { struct pim_interface *pim_ifp; - struct prefix_sg sg; + pim_sgaddr sg; struct pim_rpf *rpg; const struct ip *ip_hdr; struct pim_upstream *up; @@ -251,13 +251,13 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, ip_hdr = (const struct ip *)buf; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = ip_hdr->ip_src; sg.grp = ip_hdr->ip_dst; up = pim_upstream_find(pim_ifp->pim, &sg); if (!up) { - struct prefix_sg star = sg; + pim_sgaddr star = sg; star.src.s_addr = INADDR_ANY; up = pim_upstream_find(pim_ifp->pim, &star); @@ -342,9 +342,9 @@ static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, { struct pim_ifchannel *ch; struct pim_interface *pim_ifp; - struct prefix_sg sg; + pim_sgaddr sg; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = msg->im_src; sg.grp = msg->im_dst; @@ -378,7 +378,7 @@ static int pim_mroute_msg_wrongvif(int fd, struct interface *ifp, ch = pim_ifchannel_find(ifp, &sg); if (!ch) { - struct prefix_sg star_g = sg; + pim_sgaddr star_g = sg; if (PIM_DEBUG_MROUTE) zlog_debug( "%s: WRONGVIF (S,G)=%s could not find channel on interface %s", @@ -448,12 +448,12 @@ static int pim_mroute_msg_wrvifwhole(int fd, struct interface *ifp, struct pim_instance *pim; struct pim_ifchannel *ch; struct pim_upstream *up; - struct prefix_sg star_g; - struct prefix_sg sg; + pim_sgaddr star_g; + pim_sgaddr sg; pim_ifp = ifp->info; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = ip_hdr->ip_src; sg.grp = ip_hdr->ip_dst; @@ -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)) @@ -626,7 +626,8 @@ static int pim_mroute_msg(struct pim_instance *pim, const char *buf, pim_ifp = ifp->info; ifaddr = connected_src->u.prefix4; - igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, ifaddr); + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->gm_socket_list, + ifaddr); if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug( @@ -1213,7 +1214,7 @@ void pim_mroute_update_counters(struct channel_oil *c_oil) if (!c_oil->installed) { c_oil->cc.lastused = 100 * pim->keep_alive_time; if (PIM_DEBUG_MROUTE) { - struct prefix_sg sg; + pim_sgaddr sg; sg.src = c_oil->oil.mfcc_origin; sg.grp = c_oil->oil.mfcc_mcastgrp; @@ -1230,7 +1231,7 @@ void pim_mroute_update_counters(struct channel_oil *c_oil) pim_zlookup_sg_statistics(c_oil); if (ioctl(pim->mroute_socket, SIOCGETSGCNT, &sgreq)) { - struct prefix_sg sg; + pim_sgaddr sg; sg.src = c_oil->oil.mfcc_origin; sg.grp = c_oil->oil.mfcc_mcastgrp; diff --git a/pimd/pim_msdp.c b/pimd/pim_msdp.c index fa7f1da79a..40d864d1da 100644 --- a/pimd/pim_msdp.c +++ b/pimd/pim_msdp.c @@ -152,7 +152,7 @@ static bool pim_msdp_sa_upstream_add_ok(struct pim_msdp_sa *sa, /* check if we have a (*, G) with a non-empty immediate OIL */ if (!xg_up) { - struct prefix_sg sg; + pim_sgaddr sg; memset(&sg, 0, sizeof(sg)); sg.grp = sa->sg.grp; @@ -237,8 +237,7 @@ static void pim_msdp_sa_free(struct pim_msdp_sa *sa) } static struct pim_msdp_sa *pim_msdp_sa_new(struct pim_instance *pim, - struct prefix_sg *sg, - struct in_addr rp) + pim_sgaddr *sg, struct in_addr rp) { struct pim_msdp_sa *sa; @@ -262,7 +261,7 @@ static struct pim_msdp_sa *pim_msdp_sa_new(struct pim_instance *pim, } static struct pim_msdp_sa *pim_msdp_sa_find(struct pim_instance *pim, - struct prefix_sg *sg) + pim_sgaddr *sg) { struct pim_msdp_sa lookup; @@ -271,8 +270,7 @@ static struct pim_msdp_sa *pim_msdp_sa_find(struct pim_instance *pim, } static struct pim_msdp_sa *pim_msdp_sa_add(struct pim_instance *pim, - struct prefix_sg *sg, - struct in_addr rp) + pim_sgaddr *sg, struct in_addr rp) { struct pim_msdp_sa *sa; @@ -386,7 +384,7 @@ static void pim_msdp_sa_deref(struct pim_msdp_sa *sa, } void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, - struct prefix_sg *sg, struct in_addr rp) + pim_sgaddr *sg, struct in_addr rp) { struct pim_msdp_sa *sa; @@ -467,15 +465,14 @@ static bool pim_msdp_sa_local_add_ok(struct pim_upstream *up) return false; } -static void pim_msdp_sa_local_add(struct pim_instance *pim, - struct prefix_sg *sg) +static void pim_msdp_sa_local_add(struct pim_instance *pim, pim_sgaddr *sg) { struct in_addr rp; rp.s_addr = INADDR_ANY; pim_msdp_sa_ref(pim, NULL /* mp */, sg, rp); } -void pim_msdp_sa_local_del(struct pim_instance *pim, struct prefix_sg *sg) +void pim_msdp_sa_local_del(struct pim_instance *pim, pim_sgaddr *sg) { struct pim_msdp_sa *sa; @@ -488,7 +485,7 @@ void pim_msdp_sa_local_del(struct pim_instance *pim, struct prefix_sg *sg) /* we need to be very cautious with this API as SA del too can trigger an * upstream del and we will get stuck in a simple loop */ static void pim_msdp_sa_local_del_on_up_del(struct pim_instance *pim, - struct prefix_sg *sg) + pim_sgaddr *sg) { struct pim_msdp_sa *sa; @@ -643,7 +640,7 @@ void pim_msdp_up_join_state_changed(struct pim_instance *pim, } } -static void pim_msdp_up_xg_del(struct pim_instance *pim, struct prefix_sg *sg) +static void pim_msdp_up_xg_del(struct pim_instance *pim, pim_sgaddr *sg) { struct listnode *sanode; struct pim_msdp_sa *sa; @@ -667,7 +664,7 @@ static void pim_msdp_up_xg_del(struct pim_instance *pim, struct prefix_sg *sg) } } -void pim_msdp_up_del(struct pim_instance *pim, struct prefix_sg *sg) +void pim_msdp_up_del(struct pim_instance *pim, pim_sgaddr *sg) { if (PIM_DEBUG_MSDP_INTERNAL) { zlog_debug("MSDP up %s del", pim_str_sg_dump(sg)); diff --git a/pimd/pim_msdp.h b/pimd/pim_msdp.h index a074f21b47..d2501adc4e 100644 --- a/pimd/pim_msdp.h +++ b/pimd/pim_msdp.h @@ -78,7 +78,7 @@ enum pim_msdp_sa_flags { struct pim_msdp_sa { struct pim_instance *pim; - struct prefix_sg sg; + pim_sgaddr sg; char sg_str[PIM_SG_LEN]; struct in_addr rp; /* Last RP address associated with this SA */ struct in_addr peer; /* last peer from who we heard this SA */ @@ -227,6 +227,7 @@ struct pim_msdp { #define PIM_MSDP_PEER_READ_OFF(mp) thread_cancel(&mp->t_read) #define PIM_MSDP_PEER_WRITE_OFF(mp) thread_cancel(&mp->t_write) +#if PIM_IPV != 6 // struct pim_msdp *msdp; struct pim_instance; void pim_msdp_init(struct pim_instance *pim, struct thread_master *master); @@ -246,14 +247,14 @@ bool pim_msdp_peer_config_write(struct vty *vty, struct pim_instance *pim, const char *spaces); void pim_msdp_peer_pkt_txed(struct pim_msdp_peer *mp); void pim_msdp_sa_ref(struct pim_instance *pim, struct pim_msdp_peer *mp, - struct prefix_sg *sg, struct in_addr rp); + pim_sgaddr *sg, struct in_addr rp); void pim_msdp_sa_local_update(struct pim_upstream *up); -void pim_msdp_sa_local_del(struct pim_instance *pim, struct prefix_sg *sg); +void pim_msdp_sa_local_del(struct pim_instance *pim, pim_sgaddr *sg); void pim_msdp_i_am_rp_changed(struct pim_instance *pim); bool pim_msdp_peer_rpf_check(struct pim_msdp_peer *mp, struct in_addr rp); void pim_msdp_up_join_state_changed(struct pim_instance *pim, struct pim_upstream *xg_up); -void pim_msdp_up_del(struct pim_instance *pim, struct prefix_sg *sg); +void pim_msdp_up_del(struct pim_instance *pim, pim_sgaddr *sg); enum pim_msdp_err pim_msdp_mg_del(struct pim_instance *pim, const char *mesh_group_name); @@ -318,4 +319,50 @@ void pim_msdp_peer_del(struct pim_msdp_peer **mp); void pim_msdp_peer_change_source(struct pim_msdp_peer *mp, const struct in_addr *addr); +#else /* PIM_IPV == 6 */ +static inline void pim_msdp_init(struct pim_instance *pim, + struct thread_master *master) +{ +} + +static inline void pim_msdp_exit(struct pim_instance *pim) +{ +} + +static inline void pim_msdp_i_am_rp_changed(struct pim_instance *pim) +{ +} + +static inline void pim_msdp_up_join_state_changed(struct pim_instance *pim, + struct pim_upstream *xg_up) +{ +} + +static inline void pim_msdp_up_del(struct pim_instance *pim, pim_sgaddr *sg) +{ +} + +static inline void pim_msdp_sa_local_update(struct pim_upstream *up) +{ +} + +static inline void pim_msdp_sa_local_del(struct pim_instance *pim, + pim_sgaddr *sg) +{ +} + +static inline int pim_msdp_config_write(struct pim_instance *pim, + struct vty *vty, const char *spaces) +{ + return 0; +} + +static inline bool pim_msdp_peer_config_write(struct vty *vty, + struct pim_instance *pim, + const char *spaces) +{ + return false; +} +#endif /* PIM_IPV == 6 */ + #endif diff --git a/pimd/pim_msdp_packet.c b/pimd/pim_msdp_packet.c index eb5f46951e..64fdbaa89b 100644 --- a/pimd/pim_msdp_packet.c +++ b/pimd/pim_msdp_packet.c @@ -66,14 +66,14 @@ static char *pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf, static void pim_msdp_pkt_sa_dump_one(struct stream *s) { - struct prefix_sg sg; + pim_sgaddr sg; /* just throw away the three reserved bytes */ stream_get3(s); /* throw away the prefix length also */ stream_getc(s); - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.grp.s_addr = stream_get_ipv4(s); sg.src.s_addr = stream_get_ipv4(s); @@ -458,7 +458,7 @@ void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp) } void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, - struct in_addr rp, struct prefix_sg sg) + struct in_addr rp, pim_sgaddr sg) { struct pim_msdp_sa sa; @@ -493,7 +493,7 @@ static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len) static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) { int prefix_len; - struct prefix_sg sg; + pim_sgaddr sg; struct listnode *peer_node; struct pim_msdp_peer *peer; @@ -501,7 +501,7 @@ static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp) stream_get3(mp->ibuf); prefix_len = stream_getc(mp->ibuf); - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.grp.s_addr = stream_get_ipv4(mp->ibuf); sg.src.s_addr = stream_get_ipv4(mp->ibuf); diff --git a/pimd/pim_msdp_packet.h b/pimd/pim_msdp_packet.h index 10b7ca4198..e2c4b0e6b5 100644 --- a/pimd/pim_msdp_packet.h +++ b/pimd/pim_msdp_packet.h @@ -69,6 +69,6 @@ void pim_msdp_pkt_sa_tx(struct pim_instance *pim); void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa); void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp); void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp, - struct in_addr rp, struct prefix_sg sg); + struct in_addr rp, pim_sgaddr sg); #endif diff --git a/pimd/pim_nb.c b/pimd/pim_nb.c index 6fe078bd8e..86dd8c490c 100644 --- a/pimd/pim_nb.c +++ b/pimd/pim_nb.c @@ -29,52 +29,59 @@ const struct frr_yang_module_info frr_pim_info = { .name = "frr-pim", .nodes = { { - .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp", + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family", .cbs = { - .modify = routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify, + .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_create, + .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy, } }, { - .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp-rebalance", + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ecmp", .cbs = { - .modify = routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify, + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ecmp_modify, } }, { - .xpath = "/frr-pim:pim/join-prune-interval", + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ecmp-rebalance", .cbs = { - .modify = pim_join_prune_interval_modify, + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_ecmp_rebalance_modify, } }, { - .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/keep-alive-timer", + .xpath = "/frr-pim:pim/address-family/join-prune-interval", .cbs = { - .modify = routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify, + .modify = pim_address_family_join_prune_interval_modify, } }, { - .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/rp-keep-alive-timer", + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/keep-alive-timer", .cbs = { - .modify = routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify, + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_keep_alive_timer_modify, } }, { - .xpath = "/frr-pim:pim/packets", + .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/rp-keep-alive-timer", .cbs = { - .modify = pim_packets_modify, + .modify = routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_keep_alive_timer_modify, } }, { - .xpath = "/frr-pim:pim/register-suppress-time", + .xpath = "/frr-pim:pim/address-family", .cbs = { - .modify = pim_register_suppress_time_modify, + .create = pim_address_family_create, + .destroy = pim_address_family_destroy, } }, { - .xpath = "/frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family", + .xpath = "/frr-pim:pim/address-family/packets", .cbs = { - .create = routing_control_plane_protocols_control_plane_protocol_pim_address_family_create, - .destroy = routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy, + .modify = pim_address_family_packets_modify, + } + }, + { + .xpath = "/frr-pim:pim/address-family/register-suppress-time", + .cbs = { + .modify = pim_address_family_register_suppress_time_modify, } }, { @@ -211,93 +218,86 @@ const struct frr_yang_module_info frr_pim_info = { } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim", - .cbs = { - .create = lib_interface_pim_create, - .destroy = lib_interface_pim_destroy, - } - }, - { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/pim-enable", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family", .cbs = { - .modify = lib_interface_pim_pim_enable_modify, + .create = lib_interface_pim_address_family_create, + .destroy = lib_interface_pim_address_family_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/dr-priority", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/pim-enable", .cbs = { - .modify = lib_interface_pim_dr_priority_modify, + .modify = lib_interface_pim_address_family_pim_enable_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/hello-interval", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/dr-priority", .cbs = { - .modify = lib_interface_pim_hello_interval_modify, + .modify = lib_interface_pim_address_family_dr_priority_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/hello-holdtime", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/hello-interval", .cbs = { - .modify = lib_interface_pim_hello_holdtime_modify, - .destroy = lib_interface_pim_hello_holdtime_destroy, + .modify = lib_interface_pim_address_family_hello_interval_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/hello-holdtime", .cbs = { - .create = lib_interface_pim_bfd_create, - .destroy = lib_interface_pim_bfd_destroy, - .apply_finish = lib_interface_pim_bfd_apply_finish, + .modify = lib_interface_pim_address_family_hello_holdtime_modify, + .destroy = lib_interface_pim_address_family_hello_holdtime_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/min-rx-interval", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/bfd", .cbs = { - .modify = lib_interface_pim_bfd_min_rx_interval_modify, + .create = lib_interface_pim_address_family_bfd_create, + .destroy = lib_interface_pim_address_family_bfd_destroy, + .apply_finish = lib_interface_pim_address_family_bfd_apply_finish, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/min-tx-interval", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/bfd/min-rx-interval", .cbs = { - .modify = lib_interface_pim_bfd_min_tx_interval_modify, + .modify = lib_interface_pim_address_family_bfd_min_rx_interval_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/detect_mult", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/bfd/min-tx-interval", .cbs = { - .modify = lib_interface_pim_bfd_detect_mult_modify, + .modify = lib_interface_pim_address_family_bfd_min_tx_interval_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/bfd/profile", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/bfd/detect_mult", .cbs = { - .modify = lib_interface_pim_bfd_profile_modify, - .destroy = lib_interface_pim_bfd_profile_destroy, + .modify = lib_interface_pim_address_family_bfd_detect_mult_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/bsm", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/bfd/profile", .cbs = { - .modify = lib_interface_pim_bsm_modify, + .modify = lib_interface_pim_address_family_bfd_profile_modify, + .destroy = lib_interface_pim_address_family_bfd_profile_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/unicast-bsm", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/bsm", .cbs = { - .modify = lib_interface_pim_unicast_bsm_modify, + .modify = lib_interface_pim_address_family_bsm_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/active-active", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/unicast-bsm", .cbs = { - .modify = lib_interface_pim_active_active_modify, + .modify = lib_interface_pim_address_family_unicast_bsm_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family", + .xpath = "/frr-interface:lib/interface/frr-pim:pim/address-family/active-active", .cbs = { - .create = lib_interface_pim_address_family_create, - .destroy = lib_interface_pim_address_family_destroy, + .modify = lib_interface_pim_address_family_active_active_modify, } }, { @@ -366,65 +366,65 @@ const struct frr_yang_module_info frr_pim_rp_info = { }; /* clang-format off */ -const struct frr_yang_module_info frr_igmp_info = { - .name = "frr-igmp", +const struct frr_yang_module_info frr_gmp_info = { + .name = "frr-gmp", .nodes = { { - .xpath = "/frr-interface:lib/interface/frr-igmp:igmp", + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family", .cbs = { - .create = lib_interface_igmp_create, - .destroy = lib_interface_igmp_destroy, + .create = lib_interface_gmp_address_family_create, + .destroy = lib_interface_gmp_address_family_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/igmp-enable", + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/enable", .cbs = { - .modify = lib_interface_igmp_igmp_enable_modify, + .modify = lib_interface_gmp_address_family_enable_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/version", + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/igmp-version", .cbs = { - .modify = lib_interface_igmp_version_modify, - .destroy = lib_interface_igmp_version_destroy, + .modify = lib_interface_gmp_address_family_igmp_version_modify, + .destroy = lib_interface_gmp_address_family_igmp_version_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/query-interval", + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/mld-version", .cbs = { - .modify = lib_interface_igmp_query_interval_modify, + .modify = lib_interface_gmp_address_family_mld_version_modify, + .destroy = lib_interface_gmp_address_family_mld_version_destroy, } }, { - .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/query-max-response-time", + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/query-interval", .cbs = { - .modify = lib_interface_igmp_query_max_response_time_modify, + .modify = lib_interface_gmp_address_family_query_interval_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/last-member-query-interval", + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/query-max-response-time", .cbs = { - .modify = lib_interface_igmp_last_member_query_interval_modify, + .modify = lib_interface_gmp_address_family_query_max_response_time_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/robustness-variable", + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/last-member-query-interval", .cbs = { - .modify = lib_interface_igmp_robustness_variable_modify, + .modify = lib_interface_gmp_address_family_last_member_query_interval_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/address-family", + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/robustness-variable", .cbs = { - .create = lib_interface_igmp_address_family_create, - .destroy = lib_interface_igmp_address_family_destroy, + .modify = lib_interface_gmp_address_family_robustness_variable_modify, } }, { - .xpath = "/frr-interface:lib/interface/frr-igmp:igmp/address-family/static-group", + .xpath = "/frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group", .cbs = { - .create = lib_interface_igmp_address_family_static_group_create, - .destroy = lib_interface_igmp_address_family_static_group_destroy, + .create = lib_interface_gmp_address_family_static_group_create, + .destroy = lib_interface_gmp_address_family_static_group_destroy, } }, { @@ -432,3 +432,4 @@ const struct frr_yang_module_info frr_igmp_info = { }, } }; + diff --git a/pimd/pim_nb.h b/pimd/pim_nb.h index f5ebbceb33..72c96d7d73 100644 --- a/pimd/pim_nb.h +++ b/pimd/pim_nb.h @@ -22,20 +22,23 @@ extern const struct frr_yang_module_info frr_pim_info; extern const struct frr_yang_module_info frr_pim_rp_info; -extern const struct frr_yang_module_info frr_igmp_info; +extern const struct frr_yang_module_info frr_gmp_info; /* frr-pim prototypes*/ -int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ecmp_modify( struct nb_cb_modify_args *args); -int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ecmp_rebalance_modify( struct nb_cb_modify_args *args); -int pim_join_prune_interval_modify(struct nb_cb_modify_args *args); -int routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify( +int pim_address_family_join_prune_interval_modify(struct nb_cb_modify_args *args); +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_keep_alive_timer_modify( struct nb_cb_modify_args *args); -int routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_keep_alive_timer_modify( + struct nb_cb_modify_args *args); +int pim_address_family_create(struct nb_cb_create_args *args); +int pim_address_family_destroy(struct nb_cb_destroy_args *args); +int pim_address_family_packets_modify(struct nb_cb_modify_args *args); +int pim_address_family_register_suppress_time_modify( struct nb_cb_modify_args *args); -int pim_packets_modify(struct nb_cb_modify_args *args); -int pim_register_suppress_time_modify(struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_create( struct nb_cb_create_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_destroy( @@ -97,28 +100,38 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_re struct nb_cb_modify_args *args); int routing_control_plane_protocols_control_plane_protocol_pim_address_family_register_accept_list_destroy( struct nb_cb_destroy_args *args); -int lib_interface_pim_dr_priority_modify( - struct nb_cb_modify_args *args); -int lib_interface_pim_create(struct nb_cb_create_args *args); -int lib_interface_pim_destroy(struct nb_cb_destroy_args *args); -int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args); -int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args); -int lib_interface_pim_hello_holdtime_modify(struct nb_cb_modify_args *args); -int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args); -int lib_interface_pim_bfd_create(struct nb_cb_create_args *args); -int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args); -void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args); -int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args); -int lib_interface_pim_bfd_min_tx_interval_modify( - struct nb_cb_modify_args *args); -int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args); -int lib_interface_pim_bfd_profile_modify(struct nb_cb_modify_args *args); -int lib_interface_pim_bfd_profile_destroy(struct nb_cb_destroy_args *args); -int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args); -int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args); -int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_dr_priority_modify( + struct nb_cb_modify_args *args); int lib_interface_pim_address_family_create(struct nb_cb_create_args *args); int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_pim_enable_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_hello_interval_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_hello_holdtime_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_hello_holdtime_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_bfd_create(struct nb_cb_create_args *args); +int lib_interface_pim_address_family_bfd_destroy( + struct nb_cb_destroy_args *args); +void lib_interface_pim_address_family_bfd_apply_finish( + struct nb_cb_apply_finish_args *args); +int lib_interface_pim_address_family_bfd_min_rx_interval_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_bfd_min_tx_interval_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_bfd_detect_mult_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_bfd_profile_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_bfd_profile_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_pim_address_family_bsm_modify(struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_unicast_bsm_modify( + struct nb_cb_modify_args *args); +int lib_interface_pim_address_family_active_active_modify( + struct nb_cb_modify_args *args); int lib_interface_pim_address_family_use_source_modify( struct nb_cb_modify_args *args); int lib_interface_pim_address_family_use_source_destroy( @@ -150,25 +163,33 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_static_rp_rp_list_prefix_list_destroy( struct nb_cb_destroy_args *args); -/* frr-igmp prototypes*/ -int lib_interface_igmp_create(struct nb_cb_create_args *args); -int lib_interface_igmp_destroy(struct nb_cb_destroy_args *args); -int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args); -int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args); -int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args); -int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args); -int lib_interface_igmp_query_max_response_time_modify( - struct nb_cb_modify_args *args); -int lib_interface_igmp_last_member_query_interval_modify( - struct nb_cb_modify_args *args); -int lib_interface_igmp_robustness_variable_modify( - struct nb_cb_modify_args *args); -int lib_interface_igmp_address_family_create(struct nb_cb_create_args *args); -int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args); -int lib_interface_igmp_address_family_static_group_create( +/* frr-gmp prototypes*/ +int lib_interface_gmp_address_family_create( struct nb_cb_create_args *args); -int lib_interface_igmp_address_family_static_group_destroy( +int lib_interface_gmp_address_family_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_gmp_address_family_enable_modify( + struct nb_cb_modify_args *args); +int lib_interface_gmp_address_family_igmp_version_modify( + struct nb_cb_modify_args *args); +int lib_interface_gmp_address_family_igmp_version_destroy( struct nb_cb_destroy_args *args); +int lib_interface_gmp_address_family_mld_version_modify( + struct nb_cb_modify_args *args); +int lib_interface_gmp_address_family_mld_version_destroy( + struct nb_cb_destroy_args *args); +int lib_interface_gmp_address_family_query_interval_modify( + struct nb_cb_modify_args *args); +int lib_interface_gmp_address_family_query_max_response_time_modify( + struct nb_cb_modify_args *args); +int lib_interface_gmp_address_family_last_member_query_interval_modify( + struct nb_cb_modify_args *args); +int lib_interface_gmp_address_family_robustness_variable_modify( + struct nb_cb_modify_args *args); +int lib_interface_gmp_address_family_static_group_create( + struct nb_cb_create_args *args); +int lib_interface_gmp_address_family_static_group_destroy( + struct nb_cb_destroy_args *args); /* * Callback registered with routing_nb lib to validate only @@ -177,22 +198,31 @@ int lib_interface_igmp_address_family_static_group_destroy( int routing_control_plane_protocols_name_validate( struct nb_cb_create_args *args); -#define FRR_PIM_XPATH \ - "/frr-routing:routing/control-plane-protocols/" \ - "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ - "frr-pim:pim" -#define FRR_PIM_AF_XPATH \ +#define FRR_PIM_VRF_XPATH \ "/frr-routing:routing/control-plane-protocols/" \ "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ "frr-pim:pim/address-family[address-family='%s']" +#define FRR_PIM_INTERFACE_XPATH \ + "./frr-pim:pim/address-family[address-family='%s']" +#define FRR_PIM_ENABLE_XPATH \ + "%s/frr-pim:pim/address-family[address-family='%s']/pim-enable" +#define FRR_PIM_ROUTER_XPATH \ + "/frr-pim:pim/address-family[address-family='%s']" +#define FRR_PIM_MROUTE_XPATH \ + "./frr-pim:pim/address-family[address-family='%s']/" \ + "mroute[source-addr='%s'][group-addr='%s']" #define FRR_PIM_STATIC_RP_XPATH \ "/frr-routing:routing/control-plane-protocols/" \ "control-plane-protocol[type='%s'][name='%s'][vrf='%s']/" \ "frr-pim:pim/address-family[address-family='%s']/" \ "frr-pim-rp:rp/static-rp/rp-list[rp-address='%s']" -#define FRR_IGMP_JOIN_XPATH \ - "./frr-igmp:igmp/address-family[address-family='%s']/" \ +#define FRR_GMP_INTERFACE_XPATH \ + "./frr-gmp:gmp/address-family[address-family='%s']" +#define FRR_GMP_ENABLE_XPATH \ + "%s/frr-gmp:gmp/address-family[address-family='%s']/enable" +#define FRR_GMP_JOIN_XPATH \ + "./frr-gmp:gmp/address-family[address-family='%s']/" \ "static-group[group-addr='%s'][source-addr='%s']" -#define FRR_PIM_MSDP_XPATH FRR_PIM_AF_XPATH "/msdp" +#define FRR_PIM_MSDP_XPATH FRR_PIM_VRF_XPATH "/msdp" #endif /* _FRR_PIM_NB_H_ */ diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index b9da8ec068..3766157295 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -34,6 +34,22 @@ #include "log.h" #include "lib_errors.h" +#if PIM_IPV == 6 +#define pim6_msdp_err(funcname, argtype) \ +int funcname(struct argtype *args) \ +{ \ + snprintf(args->errmsg, args->errmsg_len, \ + "Trying to configure MSDP in pim6d. " \ + "MSDP does not exist for IPv6."); \ + return NB_ERR_VALIDATION; \ +} \ +MACRO_REQUIRE_SEMICOLON() + +#else /* PIM_IPV != 6 */ +#define pim6_msdp_err(funcname, argtype) \ +MACRO_REQUIRE_SEMICOLON() +#endif /* PIM_IPV != 6 */ + static void pim_if_membership_clear(struct interface *ifp) { struct pim_interface *pim_ifp; @@ -62,7 +78,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; @@ -86,18 +102,18 @@ static void pim_if_membership_refresh(struct interface *ifp) */ /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, grp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_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)) { if (IGMP_SOURCE_TEST_FORWARDING(src->source_flags)) { - struct prefix_sg sg; + pim_sgaddr sg; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = src->source_addr; sg.grp = grp->group_addr; pim_ifchannel_local_membership_add( @@ -105,7 +121,7 @@ static void pim_if_membership_refresh(struct interface *ifp) } } /* scan group sources */ - } /* scan igmp groups */ + } /* scan igmp groups */ /* * Finally delete every PIM (S,G) entry lacking all state info @@ -318,9 +334,12 @@ static bool is_pim_interface(const struct lyd_node *dnode) yang_dnode_get_path(dnode, if_xpath, sizeof(if_xpath)); pim_enable_dnode = - yang_dnode_getf(dnode, "%s/frr-pim:pim/pim-enable", if_xpath); - igmp_enable_dnode = yang_dnode_getf( - dnode, "%s/frr-igmp:igmp/igmp-enable", if_xpath); + yang_dnode_getf(dnode, + "%s/frr-pim:pim/address-family[address-family='%s']/pim-enable", + if_xpath, "frr-routing:ipv4"); + igmp_enable_dnode = yang_dnode_getf(dnode, + "%s/frr-gmp:gmp/address-family[address-family='%s']/enable", + if_xpath, "frr-routing:ipv4"); if (((pim_enable_dnode) && (yang_dnode_get_bool(pim_enable_dnode, "."))) || @@ -365,20 +384,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); @@ -389,21 +400,21 @@ static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) char ifaddr_str[INET_ADDRSTRLEN]; pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, - sizeof(ifaddr_str)); + sizeof(ifaddr_str)); zlog_debug("%s: Querier %s on %s reconfig query_interval=%d", - __func__, ifaddr_str, ifp->name, - pim_ifp->igmp_default_query_interval); + __func__, ifaddr_str, ifp->name, + pim_ifp->gm_default_query_interval); } /* * igmp_startup_mode_on() will reset QQI: - * igmp->querier_query_interval = pim_ifp->igmp_default_query_interval; + * igmp->querier_query_interval = pim_ifp->gm_default_query_interval; */ 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,11 +447,11 @@ 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; + pim_ifp->gm_default_query_interval = query_interval; - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) { igmp_sock_query_interval_reconfig(igmp); igmp_sock_query_reschedule(igmp); } @@ -450,16 +461,15 @@ 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) + if (pim_ifp->gm_query_max_response_time_dsec == + query_max_response_time_dsec) return; - pim_ifp->igmp_query_max_response_time_dsec = - query_max_response_time_dsec; + pim_ifp->gm_query_max_response_time_dsec = query_max_response_time_dsec; /* * Below we modify socket/group/source timers in order to quickly @@ -468,15 +478,15 @@ static void change_query_max_response_time(struct pim_interface *pim_ifp, */ /* scan all sockets */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, igmp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_socket_list, sock_node, igmp)) { /* reschedule socket general query */ igmp_sock_query_reschedule(igmp); } /* scan socket groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grp_node, grp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_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) @@ -510,9 +520,38 @@ int routing_control_plane_protocols_name_validate( } /* - * XPath: /frr-pim:pim/packets + * XPath: /frr-pim:pim/address-family */ -int pim_packets_modify(struct nb_cb_modify_args *args) +int pim_address_family_create(struct nb_cb_create_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int pim_address_family_destroy(struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-pim:pim/address-family/packets + */ +int pim_address_family_packets_modify(struct nb_cb_modify_args *args) { switch (args->event) { case NB_EV_VALIDATE: @@ -529,9 +568,10 @@ int pim_packets_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-pim:pim/join-prune-interval + * XPath: /frr-pim:pim/address-family/join-prune-interval */ -int pim_join_prune_interval_modify(struct nb_cb_modify_args *args) +int pim_address_family_join_prune_interval_modify( + struct nb_cb_modify_args *args) { switch (args->event) { case NB_EV_VALIDATE: @@ -547,9 +587,10 @@ int pim_join_prune_interval_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-pim:pim/register-suppress-time + * XPath: /frr-pim:pim/address-family/register-suppress-time */ -int pim_register_suppress_time_modify(struct nb_cb_modify_args *args) +int pim_address_family_register_suppress_time_modify( + struct nb_cb_modify_args *args) { uint16_t value; switch (args->event) { @@ -585,9 +626,9 @@ int pim_register_suppress_time_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ecmp */ -int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ecmp_modify( struct nb_cb_modify_args *args) { struct vrf *vrf; @@ -608,9 +649,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_modify( } /* - * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/ecmp-rebalance + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/ecmp-rebalance */ -int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ecmp_rebalance_modify( struct nb_cb_modify_args *args) { struct vrf *vrf; @@ -632,9 +673,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_ecmp_rebalance_mo } /* - * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/keep-alive-timer + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/keep-alive-timer */ -int routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_keep_alive_timer_modify( struct nb_cb_modify_args *args) { struct vrf *vrf; @@ -656,9 +697,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_keep_alive_timer_ } /* - * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/rp-keep-alive-timer + * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/rp-keep-alive-timer */ -int routing_control_plane_protocols_control_plane_protocol_pim_rp_keep_alive_timer_modify( +int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp_keep_alive_timer_modify( struct nb_cb_modify_args *args) { struct vrf *vrf; @@ -705,7 +746,6 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_de case NB_EV_PREPARE: case NB_EV_ABORT: case NB_EV_APPLY: - /* TODO: implement me. */ break; } @@ -1032,6 +1072,20 @@ int pim_msdp_connection_retry_modify(struct nb_cb_modify_args *args) return NB_OK; } +pim6_msdp_err(pim_msdp_mesh_group_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_mesh_group_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_mesh_group_source_modify, nb_cb_modify_args); +pim6_msdp_err(pim_msdp_mesh_group_source_destroy, nb_cb_destroy_args); +pim6_msdp_err(pim_msdp_mesh_group_members_create, nb_cb_create_args); +pim6_msdp_err(pim_msdp_mesh_group_members_destroy, nb_cb_destroy_args); +pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_source_ip_modify, + nb_cb_modify_args); +pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_destroy, + nb_cb_destroy_args); +pim6_msdp_err(routing_control_plane_protocols_control_plane_protocol_pim_address_family_msdp_peer_create, + nb_cb_create_args); + +#if PIM_IPV != 6 /* * XPath: * /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/msdp-mesh-groups @@ -1261,6 +1315,7 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_ms return NB_OK; } +#endif /* PIM_IPV != 6 */ /* * XPath: /frr-routing:routing/control-plane-protocols/control-plane-protocol/frr-pim:pim/address-family/mlag @@ -1476,9 +1531,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_re } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family */ -int lib_interface_pim_create(struct nb_cb_create_args *args) +int lib_interface_pim_address_family_create(struct nb_cb_create_args *args) { switch (args->event) { case NB_EV_VALIDATE: @@ -1491,7 +1546,7 @@ int lib_interface_pim_create(struct nb_cb_create_args *args) return NB_OK; } -int lib_interface_pim_destroy(struct nb_cb_destroy_args *args) +int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1519,9 +1574,9 @@ int lib_interface_pim_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/pim-enable + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/pim-enable */ -int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_pim_enable_modify(struct nb_cb_modify_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1573,9 +1628,10 @@ int lib_interface_pim_pim_enable_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/hello-interval + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/hello-interval */ -int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_hello_interval_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1598,9 +1654,10 @@ int lib_interface_pim_hello_interval_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/hello-holdtime + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/hello-holdtime */ -int lib_interface_pim_hello_holdtime_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_hello_holdtime_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1622,7 +1679,8 @@ int lib_interface_pim_hello_holdtime_modify(struct nb_cb_modify_args *args) } -int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args) +int lib_interface_pim_address_family_hello_holdtime_destroy( + struct nb_cb_destroy_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1642,9 +1700,9 @@ int lib_interface_pim_hello_holdtime_destroy(struct nb_cb_destroy_args *args) return NB_OK; } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd */ -int lib_interface_pim_bfd_create(struct nb_cb_create_args *args) +int lib_interface_pim_address_family_bfd_create(struct nb_cb_create_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1665,7 +1723,8 @@ int lib_interface_pim_bfd_create(struct nb_cb_create_args *args) return NB_OK; } -int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args) +int lib_interface_pim_address_family_bfd_destroy( + struct nb_cb_destroy_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1695,9 +1754,10 @@ int lib_interface_pim_bfd_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd */ -void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args) +void lib_interface_pim_address_family_bfd_apply_finish( + struct nb_cb_apply_finish_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1721,9 +1781,10 @@ void lib_interface_pim_bfd_apply_finish(struct nb_cb_apply_finish_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/min-rx-interval + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd/min-rx-interval */ -int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_bfd_min_rx_interval_modify( + struct nb_cb_modify_args *args) { switch (args->event) { case NB_EV_VALIDATE: @@ -1737,9 +1798,10 @@ int lib_interface_pim_bfd_min_rx_interval_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/min-tx-interval + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd/min-tx-interval */ -int lib_interface_pim_bfd_min_tx_interval_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_bfd_min_tx_interval_modify( + struct nb_cb_modify_args *args) { switch (args->event) { case NB_EV_VALIDATE: @@ -1753,9 +1815,10 @@ int lib_interface_pim_bfd_min_tx_interval_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/detect_mult + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd/detect_mult */ -int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_bfd_detect_mult_modify( + struct nb_cb_modify_args *args) { switch (args->event) { case NB_EV_VALIDATE: @@ -1769,9 +1832,10 @@ int lib_interface_pim_bfd_detect_mult_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/bfd/profile + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bfd/profile */ -int lib_interface_pim_bfd_profile_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_bfd_profile_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1794,7 +1858,8 @@ int lib_interface_pim_bfd_profile_modify(struct nb_cb_modify_args *args) return NB_OK; } -int lib_interface_pim_bfd_profile_destroy(struct nb_cb_destroy_args *args) +int lib_interface_pim_address_family_bfd_profile_destroy( + struct nb_cb_destroy_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1816,9 +1881,9 @@ int lib_interface_pim_bfd_profile_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/bsm + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/bsm */ -int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_bsm_modify(struct nb_cb_modify_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1840,9 +1905,10 @@ int lib_interface_pim_bsm_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/unicast-bsm + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/unicast-bsm */ -int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_unicast_bsm_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1865,9 +1931,10 @@ int lib_interface_pim_unicast_bsm_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/active-active + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/active-active */ -int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_active_active_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1902,9 +1969,10 @@ int lib_interface_pim_active_active_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/dr-priority + * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/dr-priority */ -int lib_interface_pim_dr_priority_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_dr_priority_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -1916,7 +1984,7 @@ int lib_interface_pim_dr_priority_modify(struct nb_cb_modify_args *args) if_dnode = yang_dnode_get_parent(args->dnode, "interface"); if (!is_pim_interface(if_dnode)) { snprintf(args->errmsg, args->errmsg_len, - "Pim not enabled on this interface"); + "Pim not enabled on this interface"); return NB_ERR_VALIDATION; } break; @@ -1941,38 +2009,10 @@ int lib_interface_pim_dr_priority_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family - */ -int lib_interface_pim_address_family_create(struct nb_cb_create_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - case NB_EV_APPLY: - break; - } - - return NB_OK; -} - -int lib_interface_pim_address_family_destroy(struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - case NB_EV_APPLY: - break; - } - - return NB_OK; -} - -/* * XPath: /frr-interface:lib/interface/frr-pim:pim/address-family/use-source */ -int lib_interface_pim_address_family_use_source_modify(struct nb_cb_modify_args *args) +int lib_interface_pim_address_family_use_source_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; struct ipaddr source_addr; @@ -2021,7 +2061,7 @@ int lib_interface_pim_address_family_use_source_destroy( if_dnode = yang_dnode_get_parent(args->dnode, "interface"); if (!is_pim_interface(if_dnode)) { snprintf(args->errmsg, args->errmsg_len, - "Pim not enabled on this interface"); + "Pim not enabled on this interface"); return NB_ERR_VALIDATION; } break; @@ -2473,9 +2513,9 @@ int routing_control_plane_protocols_control_plane_protocol_pim_address_family_rp } /* - * XPath: /frr-interface:lib/interface/frr-igmp:igmp + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family */ -int lib_interface_igmp_create(struct nb_cb_create_args *args) +int lib_interface_gmp_address_family_create(struct nb_cb_create_args *args) { switch (args->event) { case NB_EV_VALIDATE: @@ -2488,7 +2528,7 @@ int lib_interface_igmp_create(struct nb_cb_create_args *args) return NB_OK; } -int lib_interface_igmp_destroy(struct nb_cb_destroy_args *args) +int lib_interface_gmp_address_family_destroy(struct nb_cb_destroy_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -2519,9 +2559,10 @@ int lib_interface_igmp_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-igmp:igmp/igmp-enable + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/enable */ -int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args) +int lib_interface_gmp_address_family_enable_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; bool igmp_enable; @@ -2575,9 +2616,10 @@ int lib_interface_igmp_igmp_enable_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-igmp:igmp/version + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/igmp-version */ -int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args) +int lib_interface_gmp_address_family_igmp_version_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -2611,7 +2653,8 @@ int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args) return NB_OK; } -int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args) +int lib_interface_gmp_address_family_igmp_version_destroy( + struct nb_cb_destroy_args *args) { struct interface *ifp; struct pim_interface *pim_ifp; @@ -2632,9 +2675,41 @@ int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-igmp:igmp/query-interval + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/mld-version + */ +int lib_interface_gmp_address_family_mld_version_modify( + struct nb_cb_modify_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +int lib_interface_gmp_address_family_mld_version_destroy( + struct nb_cb_destroy_args *args) +{ + switch (args->event) { + case NB_EV_VALIDATE: + case NB_EV_PREPARE: + case NB_EV_ABORT: + case NB_EV_APPLY: + break; + } + + return NB_OK; +} + +/* + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/query-interval */ -int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args) +int lib_interface_gmp_address_family_query_interval_modify( + struct nb_cb_modify_args *args) { struct interface *ifp; int query_interval; @@ -2654,9 +2729,9 @@ int lib_interface_igmp_query_interval_modify(struct nb_cb_modify_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-igmp:igmp/query-max-response-time + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/query-max-response-time */ -int lib_interface_igmp_query_max_response_time_modify( +int lib_interface_gmp_address_family_query_max_response_time_modify( struct nb_cb_modify_args *args) { struct interface *ifp; @@ -2679,9 +2754,9 @@ int lib_interface_igmp_query_max_response_time_modify( } /* - * XPath: /frr-interface:lib/interface/frr-igmp:igmp/last-member-query-interval + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/last-member-query-interval */ -int lib_interface_igmp_last_member_query_interval_modify( +int lib_interface_gmp_address_family_last_member_query_interval_modify( struct nb_cb_modify_args *args) { struct interface *ifp; @@ -2698,7 +2773,7 @@ int lib_interface_igmp_last_member_query_interval_modify( pim_ifp = ifp->info; last_member_query_interval = yang_dnode_get_uint16(args->dnode, NULL); - pim_ifp->igmp_specific_query_max_response_time_dsec = + pim_ifp->gm_specific_query_max_response_time_dsec = last_member_query_interval; break; @@ -2708,9 +2783,9 @@ int lib_interface_igmp_last_member_query_interval_modify( } /* - * XPath: /frr-interface:lib/interface/frr-igmp:igmp/robustness-variable + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/robustness-variable */ -int lib_interface_igmp_robustness_variable_modify( +int lib_interface_gmp_address_family_robustness_variable_modify( struct nb_cb_modify_args *args) { struct interface *ifp; @@ -2725,39 +2800,10 @@ int lib_interface_igmp_robustness_variable_modify( case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; - last_member_query_count = yang_dnode_get_uint8(args->dnode, - NULL); - pim_ifp->igmp_last_member_query_count = last_member_query_count; - - break; - } - - return NB_OK; -} - -/* - * XPath: /frr-interface:lib/interface/frr-igmp:igmp/address-family - */ -int lib_interface_igmp_address_family_create(struct nb_cb_create_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - case NB_EV_APPLY: - break; - } - - return NB_OK; -} + last_member_query_count = + yang_dnode_get_uint8(args->dnode, NULL); + pim_ifp->gm_last_member_query_count = last_member_query_count; -int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args) -{ - switch (args->event) { - case NB_EV_VALIDATE: - case NB_EV_PREPARE: - case NB_EV_ABORT: - case NB_EV_APPLY: break; } @@ -2765,9 +2811,9 @@ int lib_interface_igmp_address_family_destroy(struct nb_cb_destroy_args *args) } /* - * XPath: /frr-interface:lib/interface/frr-igmp:igmp/address-family/static-group + * XPath: /frr-interface:lib/interface/frr-gmp:gmp/address-family/static-group */ -int lib_interface_igmp_address_family_static_group_create( +int lib_interface_gmp_address_family_static_group_create( struct nb_cb_create_args *args) { struct interface *ifp; @@ -2808,7 +2854,7 @@ int lib_interface_igmp_address_family_static_group_create( return NB_OK; } -int lib_interface_igmp_address_family_static_group_destroy( +int lib_interface_gmp_address_family_static_group_destroy( struct nb_cb_destroy_args *args) { struct interface *ifp; 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_neighbor.h b/pimd/pim_neighbor.h index d71b2b87c3..12c469ae2a 100644 --- a/pimd/pim_neighbor.h +++ b/pimd/pim_neighbor.h @@ -28,10 +28,11 @@ #include "pim_tlv.h" #include "pim_iface.h" +#include "pim_str.h" struct pim_neighbor { int64_t creation; /* timestamp of creation */ - struct in_addr source_addr; + pim_addr source_addr; pim_hello_options hello_options; uint16_t holdtime; uint16_t propagation_delay_msec; diff --git a/pimd/pim_oil.c b/pimd/pim_oil.c index a3ca44bb50..c094e99a71 100644 --- a/pimd/pim_oil.c +++ b/pimd/pim_oil.c @@ -39,7 +39,7 @@ char *pim_channel_oil_dump(struct channel_oil *c_oil, char *buf, size_t size) { char *out; struct interface *ifp; - struct prefix_sg sg; + pim_sgaddr sg; int i; sg.src = c_oil->oil.mfcc_origin; @@ -104,7 +104,7 @@ void pim_channel_oil_free(struct channel_oil *c_oil) } struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, - struct prefix_sg *sg) + pim_sgaddr *sg) { struct channel_oil *c_oil = NULL; struct channel_oil lookup; @@ -118,8 +118,7 @@ struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, } struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, - struct prefix_sg *sg, - const char *name) + pim_sgaddr *sg, const char *name) { struct channel_oil *c_oil; @@ -145,7 +144,7 @@ struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, if (PIM_DEBUG_MROUTE) zlog_debug( - "%s(%s): Existing oil for %pSG4 Ref Count: %d (Post Increment)", + "%s(%s): Existing oil for %pSG Ref Count: %d (Post Increment)", __func__, name, sg, c_oil->oil_ref_count); return c_oil; } @@ -174,11 +173,11 @@ struct channel_oil *pim_channel_oil_del(struct channel_oil *c_oil, const char *name) { if (PIM_DEBUG_MROUTE) { - struct prefix_sg sg = {.src = c_oil->oil.mfcc_mcastgrp, - .grp = c_oil->oil.mfcc_origin}; + pim_sgaddr sg = {.src = c_oil->oil.mfcc_mcastgrp, + .grp = c_oil->oil.mfcc_origin}; zlog_debug( - "%s(%s): Del oil for %pSG4, Ref Count: %d (Predecrement)", + "%s(%s): Del oil for %pSG, Ref Count: %d (Predecrement)", __func__, name, &sg, c_oil->oil_ref_count); } --c_oil->oil_ref_count; @@ -490,23 +489,21 @@ int pim_channel_add_oif(struct channel_oil *channel_oil, struct interface *oif, /* Check the OIF really exists before returning, and only log warning otherwise */ if (channel_oil->oil.mfcc_ttls[pim_ifp->mroute_vif_index] < 1) { - { - char group_str[INET_ADDRSTRLEN]; - char source_str[INET_ADDRSTRLEN]; - pim_inet4_dump("<group?>", - channel_oil->oil.mfcc_mcastgrp, - group_str, sizeof(group_str)); - pim_inet4_dump("<source?>", - channel_oil->oil.mfcc_origin, - source_str, sizeof(source_str)); - zlog_warn( - "%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", - __FILE__, __func__, proto_mask, - oif->name, pim_ifp->mroute_vif_index, - channel_oil->oil.mfcc_ttls - [pim_ifp->mroute_vif_index], - source_str, group_str); - } + char group_str[INET_ADDRSTRLEN]; + char source_str[INET_ADDRSTRLEN]; + pim_inet4_dump("<group?>", + channel_oil->oil.mfcc_mcastgrp, + group_str, sizeof(group_str)); + pim_inet4_dump("<source?>", + channel_oil->oil.mfcc_origin, source_str, + sizeof(source_str)); + zlog_warn( + "%s %s: new protocol mask %u requested nonexistent OIF %s (vif_index=%d, min_ttl=%d) for channel (S,G)=(%s,%s)", + __FILE__, __func__, proto_mask, oif->name, + pim_ifp->mroute_vif_index, + channel_oil->oil + .mfcc_ttls[pim_ifp->mroute_vif_index], + source_str, group_str); } if (PIM_DEBUG_MROUTE) { diff --git a/pimd/pim_oil.h b/pimd/pim_oil.h index af8ac84594..696ef70645 100644 --- a/pimd/pim_oil.h +++ b/pimd/pim_oil.h @@ -123,10 +123,9 @@ void pim_oil_terminate(struct pim_instance *pim); void pim_channel_oil_free(struct channel_oil *c_oil); struct channel_oil *pim_find_channel_oil(struct pim_instance *pim, - struct prefix_sg *sg); + pim_sgaddr *sg); struct channel_oil *pim_channel_oil_add(struct pim_instance *pim, - struct prefix_sg *sg, - const char *name); + pim_sgaddr *sg, const char *name); void pim_channel_oil_change_iif(struct pim_instance *pim, struct channel_oil *c_oil, int input_vif_index, const char *name); diff --git a/pimd/pim_pim.c b/pimd/pim_pim.c index 30dc6b3e92..2142d9010b 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) @@ -555,8 +570,8 @@ static int pim_msg_send_frame(int fd, char *buf, size_t len, return 0; } -int pim_msg_send(int fd, struct in_addr src, struct in_addr dst, - uint8_t *pim_msg, int pim_msg_size, const char *ifname) +int pim_msg_send(int fd, pim_addr src, struct in_addr dst, uint8_t *pim_msg, + int pim_msg_size, const char *ifname) { struct sockaddr_in to; socklen_t tolen; @@ -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; } diff --git a/pimd/pim_register.c b/pimd/pim_register.c index cc0dace7c2..e7bbeb4f62 100644 --- a/pimd/pim_register.c +++ b/pimd/pim_register.c @@ -64,7 +64,7 @@ void pim_register_join(struct pim_upstream *up) pim_vxlan_update_sg_reg_state(pim, up, true /*reg_join*/); } -void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg, +void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, struct in_addr src, struct in_addr originator) { struct pim_interface *pinfo; @@ -119,12 +119,12 @@ int pim_register_stop_recv(struct interface *ifp, uint8_t *buf, int buf_size) struct pim_instance *pim = pim_ifp->pim; struct pim_upstream *upstream = NULL; struct prefix source; - struct prefix_sg sg; + pim_sgaddr sg; int l; ++pim_ifp->pim_ifstat_reg_stop_recv; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); l = pim_parse_addr_group(&sg, buf, buf_size); buf += l; buf_size -= l; @@ -318,7 +318,7 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, { int sentRegisterStop = 0; struct ip *ip_hdr; - struct prefix_sg sg; + pim_sgaddr sg; uint32_t *bits; int i_am_rp = 0; struct pim_interface *pim_ifp = ifp->info; @@ -367,7 +367,7 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, * Line above. So we need to add 4 bytes to get to the * start of the actual Encapsulated data. */ - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = ip_hdr->ip_src; sg.grp = ip_hdr->ip_dst; @@ -415,8 +415,9 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); - zlog_debug("%s: Sending register-stop to %s for %pSG4 due to prefix-list denial, dropping packet", - __func__, src_str, &sg); + zlog_debug( + "%s: Sending register-stop to %s for %pSG due to prefix-list denial, dropping packet", + __func__, src_str, &sg); } return 0; diff --git a/pimd/pim_register.h b/pimd/pim_register.h index caaacd9d54..fd4284b802 100644 --- a/pimd/pim_register.h +++ b/pimd/pim_register.h @@ -39,7 +39,7 @@ int pim_register_recv(struct interface *ifp, struct in_addr dest_addr, void pim_register_send(const uint8_t *buf, int buf_size, struct in_addr src, struct pim_rpf *rpg, int null_register, struct pim_upstream *up); -void pim_register_stop_send(struct interface *ifp, struct prefix_sg *sg, +void pim_register_stop_send(struct interface *ifp, pim_sgaddr *sg, struct in_addr src, struct in_addr originator); void pim_register_join(struct pim_upstream *up); void pim_null_register_send(struct pim_upstream *up); diff --git a/pimd/pim_rp.c b/pimd/pim_rp.c index 4865b0ed46..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" @@ -1273,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); @@ -1321,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); } } diff --git a/pimd/pim_rpf.h b/pimd/pim_rpf.h index 006aa1b636..d6a8880ffb 100644 --- a/pimd/pim_rpf.h +++ b/pimd/pim_rpf.h @@ -21,6 +21,7 @@ #define PIM_RPF_H #include <zebra.h> +#include "pim_str.h" /* RFC 4601: @@ -35,7 +36,7 @@ units applicable to the unicast routing protocol used. */ struct pim_nexthop { - struct in_addr last_lookup; + pim_addr last_lookup; long long last_lookup_time; struct interface *interface; /* RPF_interface(S) */ struct prefix mrib_nexthop_addr; /* MRIB.next_hop(S) */ diff --git a/pimd/pim_str.c b/pimd/pim_str.c index f6acd08739..180ed69fd2 100644 --- a/pimd/pim_str.c +++ b/pimd/pim_str.c @@ -42,7 +42,7 @@ void pim_addr_dump(const char *onfail, struct prefix *p, char *buf, errno = save_errno; } -char *pim_str_sg_dump(const struct prefix_sg *sg) +char *pim_str_sg_dump(const pim_sgaddr *sg) { static char sg_str[PIM_SG_LEN]; diff --git a/pimd/pim_str.h b/pimd/pim_str.h index 94ba324154..f6d209b79b 100644 --- a/pimd/pim_str.h +++ b/pimd/pim_str.h @@ -24,7 +24,10 @@ #include <sys/socket.h> #include <arpa/inet.h> -#include <prefix.h> +#include "prefix.h" +#include "pim_addr.h" + +#include "pim_addr.h" /* * Longest possible length of a (S,G) string is 36 bytes @@ -35,12 +38,32 @@ */ #define PIM_SG_LEN PREFIX_SG_STR_LEN #define pim_inet4_dump prefix_mcast_inet4_dump -#define pim_str_sg_set prefix_sg2str + +static inline const char *pim_str_sg_set(const pim_sgaddr *sg, char *str) +{ + snprintfrr(str, PREFIX_SG_STR_LEN, "%pSG", sg); + return str; +} + +static inline void pim_addr_copy(pim_addr *dest, pim_addr *source) +{ + dest->s_addr = source->s_addr; +} + +static inline int pim_is_addr_any(pim_addr addr) +{ + return (addr.s_addr == INADDR_ANY); +} + +static inline int pim_addr_cmp(pim_addr addr1, pim_addr addr2) +{ + return IPV4_ADDR_CMP(&addr1, &addr2); +} void pim_addr_dump(const char *onfail, struct prefix *p, char *buf, int buf_size); void pim_inet4_dump(const char *onfail, struct in_addr addr, char *buf, int buf_size); -char *pim_str_sg_dump(const struct prefix_sg *sg); +char *pim_str_sg_dump(const pim_sgaddr *sg); #endif diff --git a/pimd/pim_tlv.c b/pimd/pim_tlv.c index 8e6ff2f3a7..a4f60e5198 100644 --- a/pimd/pim_tlv.c +++ b/pimd/pim_tlv.c @@ -510,7 +510,7 @@ int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size) return addr - buf; } -int pim_parse_addr_group(struct prefix_sg *sg, const uint8_t *buf, int buf_size) +int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size) { const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ @@ -569,8 +569,8 @@ int pim_parse_addr_group(struct prefix_sg *sg, const uint8_t *buf, int buf_size) return addr - buf; } -int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags, - const uint8_t *buf, int buf_size) +int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf, + int buf_size) { const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ diff --git a/pimd/pim_tlv.h b/pimd/pim_tlv.h index ef764656d3..1aa60d5dbb 100644 --- a/pimd/pim_tlv.h +++ b/pimd/pim_tlv.h @@ -111,9 +111,8 @@ int pim_encode_addr_group(uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group); int pim_parse_addr_ucast(struct prefix *p, const uint8_t *buf, int buf_size); -int pim_parse_addr_group(struct prefix_sg *sg, const uint8_t *buf, - int buf_size); -int pim_parse_addr_source(struct prefix_sg *sg, uint8_t *flags, - const uint8_t *buf, int buf_size); +int pim_parse_addr_group(pim_sgaddr *sg, const uint8_t *buf, int buf_size); +int pim_parse_addr_source(pim_sgaddr *sg, uint8_t *flags, const uint8_t *buf, + int buf_size); #endif /* PIM_TLV_H */ diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index e59dbba9de..ef356213e6 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -131,7 +131,7 @@ static void pim_upstream_find_new_children(struct pim_instance *pim, static struct pim_upstream *pim_upstream_find_parent(struct pim_instance *pim, struct pim_upstream *child) { - struct prefix_sg any = child->sg; + pim_sgaddr any = child->sg; struct pim_upstream *up = NULL; // (S,G) @@ -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) @@ -861,7 +860,7 @@ void pim_upstream_fill_static_iif(struct pim_upstream *up, } static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, - struct prefix_sg *sg, + pim_sgaddr *sg, struct interface *incoming, int flags, struct pim_ifchannel *ch) @@ -1013,8 +1012,7 @@ uint32_t pim_up_mlag_peer_cost(struct pim_upstream *up) return up->mlag.peer_mrib_metric; } -struct pim_upstream *pim_upstream_find(struct pim_instance *pim, - struct prefix_sg *sg) +struct pim_upstream *pim_upstream_find(struct pim_instance *pim, pim_sgaddr *sg) { struct pim_upstream lookup; struct pim_upstream *up = NULL; @@ -1024,9 +1022,9 @@ struct pim_upstream *pim_upstream_find(struct pim_instance *pim, return up; } -struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, - struct interface *incoming, - int flags, const char *name) +struct pim_upstream *pim_upstream_find_or_add(pim_sgaddr *sg, + struct interface *incoming, + int flags, const char *name) { struct pim_interface *pim_ifp = incoming->info; @@ -1070,8 +1068,7 @@ void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name) __func__, name, up->sg_str, up->ref_count); } -struct pim_upstream *pim_upstream_add(struct pim_instance *pim, - struct prefix_sg *sg, +struct pim_upstream *pim_upstream_add(struct pim_instance *pim, pim_sgaddr *sg, struct interface *incoming, int flags, const char *name, struct pim_ifchannel *ch) @@ -1585,7 +1582,7 @@ void pim_upstream_msdp_reg_timer_start(struct pim_upstream *up) * received for the source and group. */ int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance *pim, - struct prefix_sg *sg) + pim_sgaddr *sg) { if (I_am_RP(pim, sg->grp)) return 1; diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index ea3b564f8a..25ff3bffe7 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -229,9 +229,9 @@ struct pim_upstream { struct pim_instance *pim; struct rb_pim_upstream_item upstream_rb; struct pim_upstream *parent; - struct in_addr upstream_addr; /* Who we are talking to */ - struct in_addr upstream_register; /*Who we received a register from*/ - struct prefix_sg sg; /* (S,G) group key */ + pim_addr upstream_addr; /* Who we are talking to */ + pim_addr upstream_register; /*Who we received a register from*/ + pim_sgaddr sg; /* (S,G) group key */ char sg_str[PIM_SG_LEN]; uint32_t flags; struct channel_oil *channel_oil; @@ -291,12 +291,11 @@ static inline bool pim_up_mlag_is_local(struct pim_upstream *up) } struct pim_upstream *pim_upstream_find(struct pim_instance *pim, - struct prefix_sg *sg); -struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, + pim_sgaddr *sg); +struct pim_upstream *pim_upstream_find_or_add(pim_sgaddr *sg, struct interface *ifp, int flags, const char *name); -struct pim_upstream *pim_upstream_add(struct pim_instance *pim, - struct prefix_sg *sg, +struct pim_upstream *pim_upstream_add(struct pim_instance *pim, pim_sgaddr *sg, struct interface *ifp, int flags, const char *name, struct pim_ifchannel *ch); @@ -338,7 +337,7 @@ void pim_upstream_keep_alive_timer_start(struct pim_upstream *up, uint32_t time); int pim_upstream_switch_to_spt_desired_on_rp(struct pim_instance *pim, - struct prefix_sg *sg); + pim_sgaddr *sg); #define SwitchToSptDesiredOnRp(pim, sg) pim_upstream_switch_to_spt_desired_on_rp (pim, sg) int pim_upstream_is_sg_rpt(struct pim_upstream *up); diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index e4dec9ee8e..c7411070d3 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -366,47 +366,47 @@ int pim_interface_config_write(struct vty *vty) } /* IF ip igmp query-max-response-time */ - if (pim_ifp->igmp_query_max_response_time_dsec - != IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) { + if (pim_ifp->gm_query_max_response_time_dsec != + IGMP_QUERY_MAX_RESPONSE_TIME_DSEC) { vty_out(vty, " ip igmp query-max-response-time %d\n", - pim_ifp->igmp_query_max_response_time_dsec); + pim_ifp->gm_query_max_response_time_dsec); ++writes; } /* IF ip igmp query-interval */ - if (pim_ifp->igmp_default_query_interval - != IGMP_GENERAL_QUERY_INTERVAL) { + if (pim_ifp->gm_default_query_interval != + IGMP_GENERAL_QUERY_INTERVAL) { vty_out(vty, " ip igmp query-interval %d\n", - pim_ifp->igmp_default_query_interval); + pim_ifp->gm_default_query_interval); ++writes; } /* IF ip igmp last-member_query-count */ - if (pim_ifp->igmp_last_member_query_count - != IGMP_DEFAULT_ROBUSTNESS_VARIABLE) { + if (pim_ifp->gm_last_member_query_count != + IGMP_DEFAULT_ROBUSTNESS_VARIABLE) { vty_out(vty, " ip igmp last-member-query-count %d\n", - pim_ifp->igmp_last_member_query_count); + pim_ifp->gm_last_member_query_count); ++writes; } /* IF ip igmp last-member_query-interval */ - if (pim_ifp->igmp_specific_query_max_response_time_dsec - != IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) { + if (pim_ifp->gm_specific_query_max_response_time_dsec != + IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC) { vty_out(vty, " ip igmp last-member-query-interval %d\n", - pim_ifp->igmp_specific_query_max_response_time_dsec); - ++writes; + pim_ifp->gm_specific_query_max_response_time_dsec); + ++writes; } /* IF ip igmp join */ - if (pim_ifp->igmp_join_list) { + if (pim_ifp->gm_join_list) { struct listnode *node; - struct igmp_join *ij; + struct gm_join *ij; for (ALL_LIST_ELEMENTS_RO( - pim_ifp->igmp_join_list, + pim_ifp->gm_join_list, node, ij)) { char group_str[INET_ADDRSTRLEN]; char source_str diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index 4c8a96a84e..3aa8bacb84 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -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 */ @@ -718,7 +734,7 @@ static bool pim_vxlan_sg_hash_eq(const void *p1, const void *p2) } static struct pim_vxlan_sg *pim_vxlan_sg_new(struct pim_instance *pim, - struct prefix_sg *sg) + pim_sgaddr *sg) { struct pim_vxlan_sg *vxlan_sg; @@ -744,8 +760,7 @@ static struct pim_vxlan_sg *pim_vxlan_sg_new(struct pim_instance *pim, return vxlan_sg; } -struct pim_vxlan_sg *pim_vxlan_sg_find(struct pim_instance *pim, - struct prefix_sg *sg) +struct pim_vxlan_sg *pim_vxlan_sg_find(struct pim_instance *pim, pim_sgaddr *sg) { struct pim_vxlan_sg lookup; @@ -753,8 +768,7 @@ struct pim_vxlan_sg *pim_vxlan_sg_find(struct pim_instance *pim, return hash_lookup(pim->vxlan.sg_hash, &lookup); } -struct pim_vxlan_sg *pim_vxlan_sg_add(struct pim_instance *pim, - struct prefix_sg *sg) +struct pim_vxlan_sg *pim_vxlan_sg_add(struct pim_instance *pim, pim_sgaddr *sg) { struct pim_vxlan_sg *vxlan_sg; @@ -789,7 +803,7 @@ static void pim_vxlan_sg_del_item(struct pim_vxlan_sg *vxlan_sg) XFREE(MTYPE_PIM_VXLAN_SG, vxlan_sg); } -void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg) +void pim_vxlan_sg_del(struct pim_instance *pim, pim_sgaddr *sg) { struct pim_vxlan_sg *vxlan_sg; diff --git a/pimd/pim_vxlan.h b/pimd/pim_vxlan.h index d17de8e3d0..cd3de23e61 100644 --- a/pimd/pim_vxlan.h +++ b/pimd/pim_vxlan.h @@ -41,7 +41,7 @@ struct pim_vxlan_sg { struct pim_instance *pim; /* key */ - struct prefix_sg sg; + pim_sgaddr sg; char sg_str[PIM_SG_LEN]; enum pim_vxlan_sg_flags flags; @@ -127,10 +127,10 @@ static inline bool pim_vxlan_is_term_dev_cfg(struct pim_instance *pim, extern struct pim_vxlan *pim_vxlan_p; extern struct pim_vxlan_sg *pim_vxlan_sg_find(struct pim_instance *pim, - struct prefix_sg *sg); + pim_sgaddr *sg); extern struct pim_vxlan_sg *pim_vxlan_sg_add(struct pim_instance *pim, - struct prefix_sg *sg); -extern void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg); + pim_sgaddr *sg); +extern void pim_vxlan_sg_del(struct pim_instance *pim, pim_sgaddr *sg); extern void pim_vxlan_update_sg_reg_state(struct pim_instance *pim, struct pim_upstream *up, bool reg_join); extern struct pim_interface *pim_vxlan_get_term_ifp(struct pim_instance *pim); diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 3a08c6aee5..05b6f23ed8 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -327,7 +327,8 @@ static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS) { struct stream *s; struct pim_instance *pim; - struct prefix_sg sg; + pim_sgaddr sg; + size_t prefixlen; pim = pim_get_pim_instance(vrf_id); if (!pim) @@ -335,10 +336,9 @@ static int pim_zebra_vxlan_sg_proc(ZAPI_CALLBACK_ARGS) s = zclient->ibuf; - sg.family = AF_INET; - sg.prefixlen = stream_getl(s); - stream_get(&sg.src.s_addr, s, sg.prefixlen); - stream_get(&sg.grp.s_addr, s, sg.prefixlen); + prefixlen = stream_getl(s); + stream_get(&sg.src.s_addr, s, prefixlen); + stream_get(&sg.grp.s_addr, s, prefixlen); if (PIM_DEBUG_ZEBRA) { char sg_str[PIM_SG_LEN]; @@ -472,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); @@ -489,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); @@ -500,17 +500,17 @@ 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; + pim_sgaddr sg; + struct gm_group *group = source->source_group; struct pim_ifchannel *ch; if ((source->source_addr.s_addr != INADDR_ANY) || !IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) return; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = source->source_addr; sg.grp = group->group_addr; @@ -547,17 +547,17 @@ 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; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->gm_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, @@ -577,15 +577,15 @@ void igmp_source_forward_reevaluate_all(struct pim_instance *pim) } 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 prefix_sg sg; + struct gm_group *group; + pim_sgaddr sg; int result; int input_iface_vif_index = 0; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = source->source_addr; sg.grp = source->source_group->group_addr; @@ -758,13 +758,13 @@ 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 prefix_sg sg; + struct gm_group *group; + pim_sgaddr sg; int result; - memset(&sg, 0, sizeof(struct prefix_sg)); + memset(&sg, 0, sizeof(sg)); sg.src = source->source_addr; sg.grp = source->source_group->group_addr; diff --git a/pimd/pim_zebra.h b/pimd/pim_zebra.h index 349903cc67..8656d7563d 100644 --- a/pimd/pim_zebra.h +++ b/pimd/pim_zebra.h @@ -33,12 +33,12 @@ 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); diff --git a/pimd/pim_zlookup.c b/pimd/pim_zlookup.c index abf1119ac5..755b9b1320 100644 --- a/pimd/pim_zlookup.c +++ b/pimd/pim_zlookup.c @@ -524,14 +524,14 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) struct stream *s = zlookup->obuf; uint16_t command = 0; unsigned long long lastused; - struct prefix_sg sg; + pim_sgaddr sg; int count = 0; int ret; struct interface *ifp = pim_if_find_by_vif_index(c_oil->pim, c_oil->oil.mfcc_parent); if (PIM_DEBUG_ZEBRA) { - struct prefix_sg more; + pim_sgaddr more; more.src = c_oil->oil.mfcc_origin; more.grp = c_oil->oil.mfcc_mcastgrp; @@ -587,7 +587,7 @@ int pim_zlookup_sg_statistics(struct channel_oil *c_oil) if (sg.src.s_addr != c_oil->oil.mfcc_origin.s_addr || sg.grp.s_addr != c_oil->oil.mfcc_mcastgrp.s_addr) { if (PIM_DEBUG_ZEBRA) { - struct prefix_sg more; + pim_sgaddr more; more.src = c_oil->oil.mfcc_origin; more.grp = c_oil->oil.mfcc_mcastgrp; diff --git a/pimd/pimd.c b/pimd/pimd.c index 38e7273945..992bb931bd 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -115,7 +115,6 @@ void pim_router_init(void) void pim_router_terminate(void) { - pim_mlag_terminate(); XFREE(MTYPE_ROUTER, router); } @@ -155,6 +154,7 @@ void pim_terminate(void) } pim_free(); + pim_mlag_terminate(); pim_router_terminate(); frr_fini(); diff --git a/pimd/pimd.h b/pimd/pimd.h index 675c0ebc6b..5ba29f9c41 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -27,6 +27,7 @@ #include "vty.h" #include "plist.h" +#include "pim_addr.h" #include "pim_instance.h" #include "pim_str.h" #include "pim_memory.h" diff --git a/pimd/subdir.am b/pimd/subdir.am index f8bc0ff081..6c267f290c 100644 --- a/pimd/subdir.am +++ b/pimd/subdir.am @@ -12,7 +12,8 @@ man8 += $(MANBUILD)/frr-pimd.8 man8 += $(MANBUILD)/mtracebis.8 endif -pimd_pimd_SOURCES = \ +pim_common = \ + pimd/pim_addr.c \ pimd/pim_assert.c \ pimd/pim_bfd.c \ pimd/pim_br.c \ @@ -32,13 +33,9 @@ pimd_pimd_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 \ - pimd/pim_msdp.c \ - pimd/pim_msdp_packet.c \ - pimd/pim_msdp_socket.c \ pimd/pim_msg.c \ pimd/pim_nb.c \ pimd/pim_nb_config.c \ @@ -50,7 +47,6 @@ pimd_pimd_SOURCES = \ pimd/pim_routemap.c \ pimd/pim_rp.c \ pimd/pim_rpf.c \ - pimd/pim_signals.c \ pimd/pim_sock.c \ pimd/pim_ssm.c \ pimd/pim_ssmpingd.c \ @@ -68,13 +64,31 @@ pimd_pimd_SOURCES = \ pimd/pimd.c \ # end +pimd_pimd_SOURCES = \ + $(pim_common) \ + pimd/pim_main.c \ + pimd/pim_msdp.c \ + pimd/pim_msdp_packet.c \ + pimd/pim_msdp_socket.c \ + pimd/pim_signals.c \ + # end + nodist_pimd_pimd_SOURCES = \ yang/frr-pim.yang.c \ yang/frr-pim-rp.yang.c \ - yang/frr-igmp.yang.c \ + yang/frr-gmp.yang.c \ + # end + +pimd_pim6d_SOURCES = \ + $(pim_common) \ + pimd/pim6_main.c \ + # end + +nodist_pimd_pim6d_SOURCES = \ # end noinst_HEADERS += \ + pimd/pim_addr.h \ pimd/pim_assert.h \ pimd/pim_bfd.h \ pimd/pim_br.h \ @@ -134,12 +148,26 @@ clippy_scan += \ pimd/pim_cmd.c \ # end +pimd_pimd_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4 pimd_pimd_LDADD = lib/libfrr.la $(LIBCAP) +if PIMD +if DEV_BUILD +# +# pim6d is only enabled for --enable-dev-build, and NOT installed currently +# (change noinst_ to sbin_ below to install it.) +# +noinst_PROGRAMS += pimd/pim6d +pimd_pim6d_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=6 $(and $(PIM_V6_TEMP_BREAK),-DPIM_V6_TEMP_BREAK) +pimd_pim6d_LDADD = lib/libfrr.la $(LIBCAP) +endif +endif + pimd_test_igmpv3_join_LDADD = lib/libfrr.la pimd_test_igmpv3_join_SOURCES = pimd/test_igmpv3_join.c pimd_mtracebis_LDADD = lib/libfrr.la +pimd_mtracebis_CFLAGS = $(AM_CFLAGS) -DPIM_IPV=4 pimd_mtracebis_SOURCES = pimd/mtracebis.c \ pimd/mtracebis_netlink.c \ pimd/mtracebis_routeget.c \ diff --git a/python/clidef.py b/python/clidef.py index ba7c9072c5..b57a00fc89 100644 --- a/python/clidef.py +++ b/python/clidef.py @@ -173,7 +173,7 @@ handlers = { # common form, without requiring a more advanced template engine (e.g. # jinja2) templ = Template( - """/* $fnname => "$cmddef" */ + """$cond_begin/* $fnname => "$cmddef" */ DEFUN_CMD_FUNC_DECL($fnname) #define funcdecl_$fnname static int ${fnname}_magic(\\ const struct cmd_element *self __attribute__ ((unused)),\\ @@ -211,7 +211,7 @@ $argblocks $argassert return ${fnname}_magic(self, vty, argc, argv$arglist); } - +$cond_end """ ) @@ -265,7 +265,25 @@ def process_file(fn, ofd, dumpfd, all_defun, macros): errors = 0 filedata = clippy.parse(fn) + cond_stack = [] + for entry in filedata["data"]: + if entry["type"] == "PREPROC": + line = entry["line"].lstrip() + tokens = line.split(maxsplit=1) + line = "#" + line + "\n" + + if not tokens: + continue + + if tokens[0] in ["if", "ifdef", "ifndef"]: + cond_stack.append(line) + elif tokens[0] in ["elif", "else"]: + prev_line = cond_stack.pop(-1) + cond_stack.append(prev_line + line) + elif tokens[0] in ["endif"]: + cond_stack.pop(-1) + continue if entry["type"].startswith("DEFPY") or ( all_defun and entry["type"].startswith("DEFUN") ): @@ -385,6 +403,8 @@ def process_file(fn, ofd, dumpfd, all_defun, macros): else: dumpfd.write('"%s":\n\t---- no magic arguments ----\n\n' % (cmddef)) + params["cond_begin"] = "".join(cond_stack) + params["cond_end"] = "".join(["#endif\n"] * len(cond_stack)) params["argdefs"] = "".join(argdefs) params["argdecls"] = "".join(argdecls) params["arglist"] = "".join(arglist) diff --git a/ripd/ripd.c b/ripd/ripd.c index 145b4de0a0..346c11ad30 100644 --- a/ripd/ripd.c +++ b/ripd/ripd.c @@ -3606,43 +3606,6 @@ static int rip_vrf_enable(struct vrf *vrf) int socket; rip = rip_lookup_by_vrf_name(vrf->name); - if (!rip) { - char *old_vrf_name = NULL; - - rip = (struct rip *)vrf->info; - if (!rip) - return 0; - /* update vrf name */ - if (rip->vrf_name) - old_vrf_name = rip->vrf_name; - rip->vrf_name = XSTRDUP(MTYPE_RIP_VRF_NAME, vrf->name); - /* - * HACK: Change the RIP VRF in the running configuration directly, - * bypassing the northbound layer. This is necessary to avoid deleting - * the RIP and readding it in the new VRF, which would have - * several implications. - */ - if (yang_module_find("frr-ripd") && old_vrf_name) { - struct lyd_node *rip_dnode; - char oldpath[XPATH_MAXLEN]; - char newpath[XPATH_MAXLEN]; - - rip_dnode = yang_dnode_getf( - running_config->dnode, - "/frr-ripd:ripd/instance[vrf='%s']/vrf", - old_vrf_name); - if (rip_dnode) { - yang_dnode_get_path(lyd_parent(rip_dnode), - oldpath, sizeof(oldpath)); - yang_dnode_change_leaf(rip_dnode, vrf->name); - yang_dnode_get_path(lyd_parent(rip_dnode), - newpath, sizeof(newpath)); - nb_running_move_tree(oldpath, newpath); - running_config->version++; - } - } - XFREE(MTYPE_RIP_VRF_NAME, old_vrf_name); - } if (!rip || rip->enabled) return 0; @@ -3683,8 +3646,7 @@ static int rip_vrf_disable(struct vrf *vrf) void rip_vrf_init(void) { - vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete, - rip_vrf_enable); + vrf_init(rip_vrf_new, rip_vrf_enable, rip_vrf_disable, rip_vrf_delete); vrf_cmd_init(NULL); } diff --git a/ripngd/ripngd.c b/ripngd/ripngd.c index 86abf1eead..27cffd4321 100644 --- a/ripngd/ripngd.c +++ b/ripngd/ripngd.c @@ -2604,45 +2604,7 @@ static int ripng_vrf_enable(struct vrf *vrf) int socket; ripng = ripng_lookup_by_vrf_name(vrf->name); - if (!ripng) { - char *old_vrf_name = NULL; - - ripng = (struct ripng *)vrf->info; - if (!ripng) - return 0; - /* update vrf name */ - if (ripng->vrf_name) - old_vrf_name = ripng->vrf_name; - ripng->vrf_name = XSTRDUP(MTYPE_RIPNG_VRF_NAME, vrf->name); - /* - * HACK: Change the RIPng VRF in the running configuration directly, - * bypassing the northbound layer. This is necessary to avoid deleting - * the RIPng and readding it in the new VRF, which would have - * several implications. - */ - if (yang_module_find("frr-ripngd") && old_vrf_name) { - struct lyd_node *ripng_dnode; - char oldpath[XPATH_MAXLEN]; - char newpath[XPATH_MAXLEN]; - - ripng_dnode = yang_dnode_getf( - running_config->dnode, - "/frr-ripngd:ripngd/instance[vrf='%s']/vrf", - old_vrf_name); - if (ripng_dnode) { - yang_dnode_get_path(lyd_parent(ripng_dnode), - oldpath, sizeof(oldpath)); - yang_dnode_change_leaf(ripng_dnode, vrf->name); - yang_dnode_get_path(lyd_parent(ripng_dnode), - newpath, sizeof(newpath)); - nb_running_move_tree(oldpath, newpath); - running_config->version++; - } - } - XFREE(MTYPE_RIPNG_VRF_NAME, old_vrf_name); - } - - if (ripng->enabled) + if (!ripng || ripng->enabled) return 0; if (IS_RIPNG_DEBUG_EVENT) @@ -2681,7 +2643,7 @@ static int ripng_vrf_disable(struct vrf *vrf) void ripng_vrf_init(void) { vrf_init(ripng_vrf_new, ripng_vrf_enable, ripng_vrf_disable, - ripng_vrf_delete, ripng_vrf_enable); + ripng_vrf_delete); vrf_cmd_init(NULL); } diff --git a/sharpd/sharp_main.c b/sharpd/sharp_main.c index 8494f479c4..d7783b6fc7 100644 --- a/sharpd/sharp_main.c +++ b/sharpd/sharp_main.c @@ -181,7 +181,7 @@ int main(int argc, char **argv, char **envp) sharp_global_init(); sharp_nhgroup_init(); - vrf_init(NULL, NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL); sharp_zebra_init(); 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/staticd/static_vrf.c b/staticd/static_vrf.c index 6ba0bf4544..37cd199c4f 100644 --- a/staticd/static_vrf.c +++ b/staticd/static_vrf.c @@ -153,8 +153,8 @@ static int static_vrf_config_write(struct vty *vty) void static_vrf_init(void) { - vrf_init(static_vrf_new, static_vrf_enable, - static_vrf_disable, static_vrf_delete, NULL); + vrf_init(static_vrf_new, static_vrf_enable, static_vrf_disable, + static_vrf_delete); vrf_cmd_init(static_vrf_config_write); } diff --git a/staticd/static_zebra.c b/staticd/static_zebra.c index 0e0f61d186..311aeda338 100644 --- a/staticd/static_zebra.c +++ b/staticd/static_zebra.c @@ -84,13 +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 = ifp->vrf->info; - - if (svrf) - static_fixup_vrf_ids(svrf); - } - /* Install any static reliant on this interface coming up */ static_install_intf_nh(ifp); static_ifindex_update(ifp, true); diff --git a/tests/bgpd/test_capability.c b/tests/bgpd/test_capability.c index 153b83897d..3568411387 100644 --- a/tests/bgpd/test_capability.c +++ b/tests/bgpd/test_capability.c @@ -913,7 +913,7 @@ int main(void) qobj_init(); master = thread_master_create(NULL); bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); - vrf_init(NULL, NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); frr_pthread_init(); diff --git a/tests/bgpd/test_mp_attr.c b/tests/bgpd/test_mp_attr.c index f510760913..909930d6bc 100644 --- a/tests/bgpd/test_mp_attr.c +++ b/tests/bgpd/test_mp_attr.c @@ -1087,7 +1087,7 @@ int main(void) bgp_vty_init(); master = thread_master_create("test mp attr"); bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); - vrf_init(NULL, NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); bgp_attr_init(); diff --git a/tests/bgpd/test_mpath.c b/tests/bgpd/test_mpath.c index b93cbd8e5a..c20403f670 100644 --- a/tests/bgpd/test_mpath.c +++ b/tests/bgpd/test_mpath.c @@ -394,7 +394,7 @@ static int global_test_init(void) master = thread_master_create(NULL); 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); + vrf_init(NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); if (fileno(stdout) >= 0) diff --git a/tests/bgpd/test_packet.c b/tests/bgpd/test_packet.c index db5918745d..27afa6a121 100644 --- a/tests/bgpd/test_packet.c +++ b/tests/bgpd/test_packet.c @@ -60,7 +60,7 @@ int main(int argc, char *argv[]) bgp_attr_init(); master = thread_master_create(NULL); bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); - vrf_init(NULL, NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL); bgp_option_set(BGP_OPT_NO_LISTEN); if (bgp_get(&bgp, &asn, NULL, BGP_INSTANCE_TYPE_DEFAULT) < 0) diff --git a/tests/bgpd/test_peer_attr.c b/tests/bgpd/test_peer_attr.c index b168be21c3..c2e86f2339 100644 --- a/tests/bgpd/test_peer_attr.c +++ b/tests/bgpd/test_peer_attr.c @@ -1389,7 +1389,7 @@ static void bgp_startup(void) nb_init(master, NULL, 0, false); bgp_master_init(master, BGP_SOCKET_SNDBUF_SIZE, list_new()); bgp_option_set(BGP_OPT_NO_LISTEN); - vrf_init(NULL, NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL); frr_pthread_init(); bgp_init(0); bgp_pthreads_run(); diff --git a/tests/lib/test_printfrr.c b/tests/lib/test_printfrr.c index 8413b7b372..8f9d637afd 100644 --- a/tests/lib/test_printfrr.c +++ b/tests/lib/test_printfrr.c @@ -186,6 +186,10 @@ int main(int argc, char **argv) test_va("VA [192.168.1.2 1234] --", "%pI4 %u", &ip, 1234); + inet_aton("0.0.0.0", &ip); + printchk("0.0.0.0", "%pI4", &ip); + printchk("*", "%pI4s", &ip); + snprintfrr(buf, sizeof(buf), "test%s", "#1"); csnprintfrr(buf, sizeof(buf), "test%s", "#2"); assert(strcmp(buf, "test#1test#2") == 0); @@ -206,16 +210,16 @@ int main(int argc, char **argv) struct prefix_sg sg; sg.src.s_addr = INADDR_ANY; sg.grp.s_addr = INADDR_ANY; - printchk("(*,*)", "%pSG4", &sg); + printchk("(*,*)", "%pPSG4", &sg); inet_aton("192.168.1.2", &sg.src); - printchk("(192.168.1.2,*)", "%pSG4", &sg); + printchk("(192.168.1.2,*)", "%pPSG4", &sg); inet_aton("224.1.2.3", &sg.grp); - printchk("(192.168.1.2,224.1.2.3)", "%pSG4", &sg); + printchk("(192.168.1.2,224.1.2.3)", "%pPSG4", &sg); sg.src.s_addr = INADDR_ANY; - printchk("(*,224.1.2.3)", "%pSG4", &sg); + printchk("(*,224.1.2.3)", "%pPSG4", &sg); uint8_t randhex[] = { 0x12, 0x34, 0x00, 0xca, 0xfe, 0x00, 0xaa, 0x55 }; @@ -274,5 +278,115 @@ int main(int argc, char **argv) inet_pton(AF_INET6, "fe2c::34", &nh.gate.ipv6); printchk("fe2c::34", "%pNHcg", &nh); + /* time printing */ + + /* need a non-UTC timezone for testing */ + setenv("TZ", "TEST-01:00", 1); + tzset(); + + struct timespec ts; + struct timeval tv; + time_t tt; + + ts.tv_sec = tv.tv_sec = tt = 1642015880; + ts.tv_nsec = 123456789; + tv.tv_usec = 234567; + + printchk("Wed Jan 12 20:31:20 2022", "%pTSR", &ts); + printchk("Wed Jan 12 20:31:20 2022", "%pTVR", &tv); + printchk("Wed Jan 12 20:31:20 2022", "%pTTR", &tt); + + FMT_NSTD(printchk("Wed Jan 12 20:31:20 2022", "%.3pTSR", &ts)); + + printchk("2022-01-12T20:31:20.123", "%pTSRi", &ts); + printchk("2022-01-12 20:31:20.123", "%pTSRip", &ts); + printchk("2022-01-12 20:31:20.123", "%pTSRpi", &ts); + FMT_NSTD(printchk("2022-01-12T20:31:20", "%.0pTSRi", &ts)); + FMT_NSTD(printchk("2022-01-12T20:31:20.123456789", "%.9pTSRi", &ts)); + FMT_NSTD(printchk("2022-01-12T20:31:20", "%.3pTTRi", &tt)); + + ts.tv_sec = tv.tv_sec = tt = 9 * 86400 + 12345; + + printchk("1w 2d 03:25:45.123", "%pTSIp", &ts); + printchk("1w2d03:25:45.123", "%pTSI", &ts); + printchk("1w2d03:25:45.234", "%pTVI", &tv); + printchk("1w2d03:25:45", "%pTTI", &tt); + + printchk("1w 2d 03h", "%pTVItp", &tv); + printchk("1w2d03h", "%pTSIt", &ts); + + printchk("219:25:45", "%pTVIh", &tv); + printchk("13165:45", "%pTVIm", &tv); + + ts.tv_sec = tv.tv_sec = tt = 1 * 86400 + 12345; + + printchk("1d 03:25:45.123", "%pTSIp", &ts); + printchk("1d03:25:45.234", "%pTVI", &tv); + + printchk("1d 03h 25m", "%pTVItp", &tv); + printchk("1d03h25m", "%pTSIt", &ts); + + printchk("98745.234", "%pTVId", &tv); + + printchk("27:25:45", "%pTVIh", &tv); + printchk("1645:45", "%pTVIm", &tv); + + ts.tv_sec = tv.tv_sec = tt = 12345; + + printchk("03:25:45.123", "%pTSIp", &ts); + printchk("03:25:45.123", "%pTSI", &ts); + printchk("03:25:45.234", "%pTVI", &tv); + printchk("03:25:45", "%pTTI", &tt); + + printchk("03:25:45", "%pTSItp", &ts); + printchk("03:25:45", "%pTVIt", &tv); + + printchk("12345.234", "%pTVId", &tv); + + printchk("03:25:45", "%pTVIh", &tv); + printchk("205:45", "%pTVIm", &tv); + + ts.tv_sec = tv.tv_sec = tt = 0; + + printchk("00:00:00.123", "%pTSIp", &ts); + printchk("00:00:00.123", "%pTSI", &ts); + printchk("00:00:00.234", "%pTVI", &tv); + printchk("00:00:00", "%pTTI", &tt); + + printchk("00:00:00", "%pTVItp", &tv); + printchk("00:00:00", "%pTSIt", &ts); + + printchk("0.234", "%pTVId", &tv); + printchk("0.234", "%pTVIdx", &tv); + printchk("-", "%pTTIdx", &tt); + + printchk("00:00:00", "%pTVIhx", &tv); + printchk("--:--:--", "%pTTIhx", &tt); + printchk("00:00", "%pTVImx", &tv); + printchk("--:--", "%pTTImx", &tt); + + ts.tv_sec = tv.tv_sec = tt = -10; + + printchk("-00:00:09.876", "%pTSIp", &ts); + printchk("-00:00:09.876", "%pTSI", &ts); + printchk("-00:00:09.765", "%pTVI", &tv); + printchk("-00:00:10", "%pTTI", &tt); + + printchk("-00:00:09", "%pTSItp", &ts); + printchk("-00:00:09", "%pTSIt", &ts); + printchk("-00:00:09", "%pTVIt", &tv); + printchk("-00:00:10", "%pTTIt", &tt); + + printchk("-9.765", "%pTVId", &tv); + printchk("-", "%pTVIdx", &tv); + + printchk("-00:00:09", "%pTSIh", &ts); + printchk("--:--:--", "%pTVIhx", &tv); + printchk("--:--:--", "%pTTIhx", &tt); + + printchk("-00:09", "%pTSIm", &ts); + printchk("--:--", "%pTVImx", &tv); + printchk("--:--", "%pTTImx", &tt); + return !!errors; } diff --git a/tests/lib/test_resolver.c b/tests/lib/test_resolver.c index 0b3dccc820..6a582cceaf 100644 --- a/tests/lib/test_resolver.c +++ b/tests/lib/test_resolver.c @@ -63,7 +63,7 @@ DEFUN (test_resolve, "DNS resolver\n" "Name to resolve\n") { - resolver_resolve(&query, AF_UNSPEC, argv[1]->arg, resolver_result); + resolver_resolve(&query, AF_UNSPEC, 0, argv[1]->arg, resolver_result); return CMD_SUCCESS; } diff --git a/tests/ospfd/test_ospf_spf.c b/tests/ospfd/test_ospf_spf.c index 7808c3d47d..3562b5f2f8 100644 --- a/tests/ospfd/test_ospf_spf.c +++ b/tests/ospfd/test_ospf_spf.c @@ -34,7 +34,7 @@ static struct ospf *test_init(struct ospf_test_node *root) struct in_addr area_id; struct in_addr router_id; - ospf = ospf_new_alloc(0, NULL); + ospf = ospf_new_alloc(0, VRF_DEFAULT_NAME); area_id.s_addr = OSPF_AREA_BACKBONE; area = ospf_area_new(ospf, area_id); 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/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/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/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/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 982a076bfb..96e4bf6ed3 100644 --- a/tests/topotests/bgp_ecmp_topo1/test_bgp_ecmp_topo1.py +++ b/tests/topotests/bgp_ecmp_topo1/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_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_route_map_match_ipv6_nexthop_access_list/__init__.py b/tests/topotests/bgp_extended_optional_parameters_length/__init__.py index e69de29bb2..e69de29bb2 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/__init__.py +++ 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/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_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py index c1a9499cbe..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 @@ -290,20 +290,100 @@ bgpribRequireVpnRoutes( # to look at the rest of the routes in the vrf luCommand( "r1", - 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 99.0.0.4/32"', - "1 available, best", + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.1.0.0/24"', + "2 available, best", "wait", - "Ensure 99.0.0.4 shows up", - 10 - ) + "Ensure 5.1.0.0 shows up on r1", + 10, +) luCommand( "r1", - 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.1.0.0/24"', + 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.1.1.0/24"', "2 available, best", "wait", - "Ensure 5.1.0.0 shows up", - 10 - ) + "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}, @@ -316,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"}, @@ -332,22 +412,104 @@ bgpribRequireUnicastRoutes( want_r1_remote_cust1_routes, debug=False, ) + + luCommand( "r3", - 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 99.0.0.4/32"', - "1 available, best", + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.1.0.0/24"', + "2 available, best", "wait", - "Ensure 99.0.0.4 shows up", - 10 - ) + "Ensure 5.1.0.0 shows up r3", + 10, +) luCommand( "r3", - 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.1.0.0/24"', + 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.1.1.0/24"', "2 available, best", "wait", - "Ensure 5.1.0.0 shows up", - 10 - ) + "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}, @@ -360,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}, @@ -378,28 +540,68 @@ bgpribRequireUnicastRoutes( luCommand( "r4", - 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 99.0.0.4/32"', - "1 available, best", + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 5.1.0.0/24"', + "2 available, best", "wait", - "Ensure 99.0.0.4 shows up", - 10 - ) + "Ensure 5.1.0.0 shows up on r4", + 10, +) luCommand( "r4", - 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 5.1.0.0/24"', + 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 5.1.1.0/24"', "2 available, best", "wait", - "Ensure 5.1.0.0 shows up", - 10 - ) + "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", - 10 - ) + "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}, @@ -409,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}, @@ -436,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}, @@ -632,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", @@ -641,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", @@ -661,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", ) @@ -670,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_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_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_access_list/r1/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf index 5f35d353f4..c2a49252d6 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r1/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/bgpd.conf @@ -3,6 +3,8 @@ 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 @@ -24,4 +26,7 @@ route-map r2 permit 30 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_access_list/r1/zebra.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/zebra.conf index 1d4374bd8f..1d4374bd8f 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r1/zebra.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r1/zebra.conf diff --git a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r2/bgpd.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf index bca67c5363..19dcf3664b 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r2/bgpd.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/bgpd.conf @@ -13,6 +13,7 @@ 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 @@ -26,4 +27,7 @@ route-map r1 permit 30 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_access_list/r2/zebra.conf b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/zebra.conf index 9039f1dec1..e69345f4f6 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/r2/zebra.conf +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/r2/zebra.conf @@ -4,6 +4,7 @@ int lo 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_access_list/test_bgp_route_map_match_ipv6_nexthop_access_list.py b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py index 3efe1eca76..8c86526bf1 100644 --- a/tests/topotests/bgp_route_map_match_ipv6_nexthop_access_list/test_bgp_route_map_match_ipv6_nexthop_access_list.py +++ b/tests/topotests/bgp_route_map_match_ipv6_nexthop/test_bgp_route_map_match_ipv6_nexthop.py @@ -20,7 +20,7 @@ """ Test if we can match BGP prefixes by next-hop which is -specified by an IPv6 Access-list. +specified by an IPv6 Access-list, prefix-list or just an address. """ import os @@ -103,6 +103,11 @@ def test_bgp_route_map_match_ipv6_next_hop_access_list(): "communities": "65002:4", } ], + "2001:db8:5::1/128": [ + { + "communities": "65002:5", + } + ], } return topotest.json_cmp(output, expected) diff --git a/tests/topotests/bgp_route_server_client/r1/bgpd.conf b/tests/topotests/bgp_route_server_client/r1/bgpd.conf index af05e49bfa..9826b671f9 100644 --- a/tests/topotests/bgp_route_server_client/r1/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r1/bgpd.conf @@ -3,6 +3,8 @@ 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 diff --git a/tests/topotests/bgp_route_server_client/r2/bgpd.conf b/tests/topotests/bgp_route_server_client/r2/bgpd.conf index 6ad7fdf06c..3b0a24b8ba 100644 --- a/tests/topotests/bgp_route_server_client/r2/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r2/bgpd.conf @@ -2,7 +2,11 @@ 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 diff --git a/tests/topotests/bgp_route_server_client/r3/bgpd.conf b/tests/topotests/bgp_route_server_client/r3/bgpd.conf index ea1f73a5dc..60a5ffc559 100644 --- a/tests/topotests/bgp_route_server_client/r3/bgpd.conf +++ b/tests/topotests/bgp_route_server_client/r3/bgpd.conf @@ -3,6 +3,8 @@ 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 diff --git a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py index c11bc119eb..21088f7008 100644 --- a/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py +++ b/tests/topotests/bgp_route_server_client/test_bgp_route_server_client.py @@ -85,6 +85,15 @@ def test_bgp_route_server_client(): 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", @@ -92,7 +101,7 @@ def test_bgp_route_server_client(): } return topotest.json_cmp(output, expected) - test_func = functools.partial(_bgp_converge, r1) + 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" 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_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/isis_topo1_vrf/test_isis_topo1_vrf.py b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py index a0cae0a40b..ff9ad6150a 100644 --- a/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py +++ b/tests/topotests/isis_topo1_vrf/test_isis_topo1_vrf.py @@ -175,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(): @@ -220,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/lib/bgp.py b/tests/topotests/lib/bgp.py index 458ae4b054..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,6 +4444,83 @@ 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 diff --git a/tests/topotests/lib/common_config.py b/tests/topotests/lib/common_config.py index cf8efdea16..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 @@ -2970,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/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 4e613ce8ac..6be644ac00 100644 --- a/tests/topotests/lib/topotest.py +++ b/tests/topotests/lib/topotest.py @@ -1859,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( @@ -1883,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/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py b/tests/topotests/multicast_pim_bsm_topo1/test_mcast_pim_bsmp_01.py index 38560c06e4..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( 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/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/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_helper/test_ospf_gr_helper.py b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py index b7a10d630a..2c7c6df37e 100644 --- a/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py +++ b/tests/topotests/ospf_gr_helper/test_ospf_gr_helper.py @@ -100,8 +100,6 @@ TC8. Verify helper functionality when dut is helping RR and new grace lsa def setup_module(mod): - return pytest.skip("OSPF GR helper mode is currently broken") - """ Sets up the pytest environment 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 4b69d82887..debf7ad766 100755 --- a/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py +++ b/tests/topotests/ospf_gr_topo1/test_ospf_gr_topo1.py @@ -139,8 +139,6 @@ def build_topo(tgen): def setup_module(mod): - return pytest.skip("OSPF GR helper mode is currently broken") - "Sets up the pytest environment" tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() 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/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 1312dc0b63..f96297b927 100644 --- a/tests/topotests/ripng_topo1/r1/ripngd.conf +++ b/tests/topotests/ripng_topo1/r1/ripngd.conf @@ -5,7 +5,7 @@ log file ripngd.log ! 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 8511bdb457..7a6450eab5 100644 --- a/tests/topotests/ripng_topo1/r2/ripngd.conf +++ b/tests/topotests/ripng_topo1/r2/ripngd.conf @@ -5,7 +5,7 @@ log file ripngd.log ! 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 c3cada44af..7a07080f7a 100644 --- a/tests/topotests/ripng_topo1/r3/ripngd.conf +++ b/tests/topotests/ripng_topo1/r3/ripngd.conf @@ -5,7 +5,7 @@ log file ripngd.log ! 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/tools/checkpatch.pl b/tools/checkpatch.pl index d2eb20ce5b..db6460f343 100755 --- a/tools/checkpatch.pl +++ b/tools/checkpatch.pl @@ -5789,7 +5789,7 @@ sub process { } # check for vsprintf extension %p<foo> misuses - if ($^V && $^V ge 5.10.0 && + if (0 && $^V && $^V ge 5.10.0 && defined $stat && $stat =~ /^\+(?![^\{]*\{\s*).*\b(\w+)\s*\(.*$String\s*,/s && $1 !~ /^_*volatile_*$/) { diff --git a/tools/coccinelle/json_object_string_addf.cocci b/tools/coccinelle/json_object_string_addf_inet_ntop.cocci index d9f92e564c..d9f92e564c 100644 --- a/tools/coccinelle/json_object_string_addf.cocci +++ b/tools/coccinelle/json_object_string_addf_inet_ntop.cocci 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/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 acd7a240b3..2be8653519 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -198,6 +198,9 @@ class Context(object): for ligne in lines: self.dlines[ligne] = True + def __str__(self): + return str(self.keys) + " : " + str(self.lines) + def add_lines(self, lines): """ Add lines to specified context @@ -329,7 +332,7 @@ class Config(object): Return the parsed context as strings for display, log etc. """ for (_, ctx) in sorted(iteritems(self.contexts)): - print(str(ctx) + "\n") + print(str(ctx)) def save_contexts(self, key, lines): """ @@ -430,16 +433,12 @@ 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 if lines and key[0].startswith("vrf "): newlines = [] for line in lines: if line.startswith("ip route ") or line.startswith("ipv6 route "): if "null0" in line: - line = re.sub(r"\s+null0(\s*$)", " blackhole", line) - elif "Null0" in line: - line = re.sub(r"\s+Null0(\s*$)", " blackhole", line) + line = re.sub(r"\s+null0(\s*$)", " Null0", line) newlines.append(line) else: newlines.append(line) @@ -762,12 +761,96 @@ 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 +associated with the peer-group and move the peer-group +config line to the end of the lines_to_del list. +""" + + def delete_move_lines(lines_to_add, lines_to_del): - """ - This function handles deletion of bgp peer group config. The objective is - to delete config lines related to peers associated with the peer-group and - move the peer-group config line to the end of the lines_to_del list. - """ + + 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 = [] @@ -860,14 +943,15 @@ def delete_move_lines(lines_to_add, lines_to_del): 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']}} for (ctx_keys, line) in lines_to_del: @@ -1842,7 +1926,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/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/vrrpd/vrrp.c b/vrrpd/vrrp.c index 4e2c12c4e0..5c34c66df5 100644 --- a/vrrpd/vrrp.c +++ b/vrrpd/vrrp.c @@ -2398,7 +2398,7 @@ void vrrp_init(void) vrrp_autoconfig_version = 3; vrrp_vrouters_hash = hash_create(&vrrp_hash_key, vrrp_hash_cmp, "VRRP virtual router hash"); - vrf_init(NULL, NULL, NULL, NULL, NULL); + vrf_init(NULL, NULL, NULL, NULL); } void vrrp_fini(void) diff --git a/vtysh/vtysh.c b/vtysh/vtysh.c index b05ad9e3d8..8e95aaa47c 100644 --- a/vtysh/vtysh.c +++ b/vtysh/vtysh.c @@ -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 = { @@ -2105,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") @@ -2141,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" @@ -4286,6 +4280,7 @@ void vtysh_init_vty(void) #endif /* HAVE_BFDD */ install_node(&segment_routing_node); + install_element(CONFIG_NODE, &segment_routing_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_exit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_quit_sr_cmd); install_element(SEGMENT_ROUTING_NODE, &vtysh_end_all_cmd); @@ -4311,13 +4306,11 @@ void vtysh_init_vty(void) install_element(SR_POLICY_NODE, &vtysh_end_all_cmd); install_element(SR_CANDIDATE_DYN_NODE, &vtysh_end_all_cmd); - install_element(CONFIG_NODE, &segment_routing_cmd); install_element(SEGMENT_ROUTING_NODE, &sr_traffic_eng_cmd); install_element(SR_TRAFFIC_ENG_NODE, &srte_segment_list_cmd); 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); @@ -4341,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 */ 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/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-igmp.yang b/yang/frr-gmp.yang index 8d151e430d..f48fcd45f1 100644 --- a/yang/frr-igmp.yang +++ b/yang/frr-gmp.yang @@ -1,8 +1,8 @@ -module frr-igmp { +module frr-gmp { yang-version "1.1"; - namespace "http://frrouting.org/yang/igmp"; + namespace "http://frrouting.org/yang/gmp"; - prefix frr-igmp; + prefix frr-gmp; import frr-routing { prefix "frr-rt"; @@ -55,26 +55,32 @@ module frr-igmp { (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."; - revision 2019-11-06 { + revision 2021-11-22 { description "Initial revision."; reference "RFC 2236: IGMP v2. - RFC 3376: IGMP v3."; + RFC 3376: IGMP v3. + RFC 2710: MLD. + RFC 3810: MLD v2."; } grouping interface-config-attributes { description - "Configuration attributes applied to the interface level."; + "Configuration IGMP/MLD attributes applied to the interface level."; - leaf igmp-enable { + leaf enable { type boolean; default "false"; description - "Enable IGMP flag on the interface."; + "Enable IGMP/MLD flag on the interface."; } - leaf version { + leaf igmp-version { + when "../frr-gmp:address-family = 'frr-rt:ipv4'" { + description + "Only applicable to IPv4 address family."; + } type uint8 { range "2..3"; } @@ -82,6 +88,18 @@ module frr-igmp { "IGMP version."; } + leaf mld-version { + when "../frr-gmp:address-family = 'frr-rt:ipv6'" { + description + "Only applicable to IPv6 address family."; + } + type uint8 { + range "1..2"; + } + description + "MLD version."; + } + leaf query-interval { type uint16 { range "1..max"; @@ -126,11 +144,6 @@ module frr-igmp { "Querier's Robustness Variable allows tuning for the expected packet loss on a network."; } - } - - grouping per-af-interface-config-attributes { - description - "Configuration attributes applied to the interface level per address family."; list static-group { key "group-addr source-addr"; @@ -149,25 +162,20 @@ module frr-igmp { "Multicast source address."; } } - - } // per-af-interface-config-attributes + } // interface-config-attributes /* * Per-interface configuration data */ augment "/frr-interface:lib/frr-interface:interface" { - container igmp { - presence - "Configure IGMP on an interface."; - uses interface-config-attributes; + container gmp { list address-family { key "address-family"; description "Each list entry for one address family."; uses frr-rt:address-family; - uses per-af-interface-config-attributes; - - } //address-family + uses interface-config-attributes; + } //address-family } } } 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-pim.yang b/yang/frr-pim.yang index 109ce22309..08bc9ce0a6 100644 --- a/yang/frr-pim.yang +++ b/yang/frr-pim.yang @@ -56,7 +56,7 @@ module frr-pim { (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."; - revision 2017-03-09 { + revision 2021-11-22 { description "Initial revision."; reference @@ -77,43 +77,6 @@ module frr-pim { * Groupings */ - grouping global-pim-config-attributes { - description - "A grouping defining pim global attributes."; - - leaf ecmp { - type boolean; - default "false"; - description - "Enable PIM ECMP."; - } - - leaf ecmp-rebalance { - type boolean; - default "false"; - description - "Enable PIM ECMP Rebalance."; - } - - leaf keep-alive-timer { - type uint16 { - range "1..max"; - } - default "210"; - description - "Keep alive Timer in seconds."; - } - - leaf rp-keep-alive-timer { - type uint16 { - range "1..max"; - } - default "210"; - description - "RP keep alive Timer in seconds."; - } - } - grouping msdp-timers { leaf hold-time { type uint16 { @@ -154,10 +117,42 @@ module frr-pim { } } - grouping per-af-global-pim-config-attributes { + grouping global-pim-config-attributes { description "A grouping defining per address family pim global attributes"; + leaf ecmp { + type boolean; + default "false"; + description + "Enable PIM ECMP."; + } + + leaf ecmp-rebalance { + type boolean; + default "false"; + description + "Enable PIM ECMP Rebalance."; + } + + leaf keep-alive-timer { + type uint16 { + range "1..max"; + } + default "210"; + description + "Keep alive Timer in seconds."; + } + + leaf rp-keep-alive-timer { + type uint16 { + range "1..max"; + } + default "210"; + description + "RP keep alive Timer in seconds."; + } + leaf send-v6-secondary { when "../frr-pim:address-family = 'frr-rt:ipv4'" { description @@ -326,11 +321,11 @@ module frr-pim { description "Only accept registers from a specific source prefix list."; } - } // per-af-global-pim-config-attributes + } // global-pim-config-attributes grouping interface-pim-config-attributes { description - "A grouping defining pim interface attributes."; + "A grouping defining pim interface attributes per address family."; leaf pim-enable { type boolean; @@ -426,11 +421,6 @@ module frr-pim { description "DR (Designated Router) priority"; } - } // interface-pim-config-attributes - - grouping per-af-interface-pim-config-attributes { - description - "A grouping defining pim interface attributes per address family."; leaf use-source { type inet:ip-address; @@ -467,7 +457,36 @@ module frr-pim { "Multicast group address."; } } - } // per-af-interface-pim-config-attributes + } // interface-pim-config-attributes + + grouping router-pim-config-attributes { + description + "A grouping defining pim router attributes per address family."; + leaf packets { + type uint8 { + range "1..max"; + } + default "3"; + description + "Number of packets to process at one time per fd."; + } + leaf join-prune-interval { + type uint16 { + range "1..max"; + } + default "60"; + description + "Join Prune Send Interval in seconds."; + } + leaf register-suppress-time { + type uint16 { + range "1..max"; + } + default "60"; + description + "Register Suppress Timer."; + } + } /* * Global Configuration data nodes @@ -482,15 +501,12 @@ module frr-pim { } description "PIM configuration data."; - - uses global-pim-config-attributes; - list address-family { key "address-family"; description "Each list entry for one address family."; uses frr-rt:address-family; - uses per-af-global-pim-config-attributes; + uses global-pim-config-attributes; } //address-family } // pim @@ -501,45 +517,28 @@ module frr-pim { */ augment "/frr-interface:lib/frr-interface:interface" { container pim { - presence - "Configure PIM on an interface."; - uses interface-pim-config-attributes; list address-family { key "address-family"; description "Each list entry for one address family."; uses frr-rt:address-family; - uses per-af-interface-pim-config-attributes; + uses interface-pim-config-attributes; } } } + /* + * Router configuration data + */ container pim { description "PIM router parameters."; - leaf packets { - type uint8 { - range "1..max"; - } - default "3"; + list address-family { + key "address-family"; description - "Number of packets to process at one time per fd."; - } - leaf join-prune-interval { - type uint16 { - range "1..max"; - } - default "60"; - description - "Join Prune Send Interval in seconds."; - } - leaf register-suppress-time { - type uint16 { - range "1..max"; - } - default "60"; - description - "Register Suppress Timer."; + "Each list entry for one address family."; + uses frr-rt:address-family; + uses router-pim-config-attributes; } } } diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index fa55a8c7cb..1e8c04bc6f 100644 --- a/yang/frr-route-map.yang +++ b/yang/frr-route-map.yang @@ -112,6 +112,12 @@ module frr-route-map { "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 @@ -207,6 +213,7 @@ module frr-route-map { + "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..80028fcb18 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -70,7 +70,7 @@ dist_yangmodels_DATA += yang/frr-zebra.yang endif if PIMD -dist_yangmodels_DATA += yang/frr-igmp.yang +dist_yangmodels_DATA += yang/frr-gmp.yang dist_yangmodels_DATA += yang/frr-pim.yang dist_yangmodels_DATA += yang/frr-pim-rp.yang endif @@ -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/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/interface.c b/zebra/interface.c index d300397b4e..8b5dbabb92 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1310,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; @@ -1318,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); } @@ -1327,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); } @@ -2348,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; } @@ -2395,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; } @@ -2448,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; } @@ -2513,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; } diff --git a/zebra/main.c b/zebra/main.c index 275d9af5d2..079751af0a 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -93,7 +93,6 @@ const struct option longopts[] = { {"socket", required_argument, NULL, 'z'}, {"ecmp", required_argument, NULL, 'e'}, {"retain", no_argument, NULL, 'r'}, - {"vrfdefaultname", required_argument, NULL, 'o'}, {"graceful_restart", required_argument, NULL, 'K'}, {"asic-offload", optional_argument, NULL, OPTION_ASIC_OFFLOAD}, #ifdef HAVE_NETLINK @@ -284,7 +283,6 @@ int main(int argc, char **argv) { // int batch_mode = 0; char *zserv_path = NULL; - char *vrf_default_name_configured = NULL; struct sockaddr_storage dummy; socklen_t dummylen; bool asic_offload = false; @@ -296,7 +294,7 @@ int main(int argc, char **argv) frr_preinit(&zebra_di, argc, argv); frr_opt_add( - "baz:e:o:rK:" + "baz:e:rK:" #ifdef HAVE_NETLINK "s:n" #endif @@ -307,7 +305,6 @@ int main(int argc, char **argv) " -z, --socket Set path of zebra socket\n" " -e, --ecmp Specify ECMP to use.\n" " -r, --retain When program terminates, retain added route by zebra.\n" - " -o, --vrfdefaultname Set default VRF name.\n" " -K, --graceful_restart Graceful restart at the kernel level, timer in seconds for expiration\n" " -A, --asic-offload FRR is interacting with an asic underneath the linux kernel\n" #ifdef HAVE_NETLINK @@ -347,9 +344,6 @@ int main(int argc, char **argv) zrouter.multipath_num = parsed_multipath; break; } - case 'o': - vrf_default_name_configured = optarg; - break; case 'z': zserv_path = optarg; if (!frr_zclient_addr(&dummy, &dummylen, optarg)) { @@ -400,7 +394,7 @@ int main(int argc, char **argv) /* * Initialize NS( and implicitly the VRF module), and make kernel * routing socket. */ - zebra_ns_init((const char *)vrf_default_name_configured); + zebra_ns_init(); router_id_cmd_init(); zebra_vty_init(); access_list_init(); @@ -443,8 +437,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/rib.h b/zebra/rib.h index 076608bb0f..b7416322f9 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -108,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; @@ -487,7 +490,8 @@ extern struct route_table *rib_tables_iter_next(rib_tables_iter_t *iter); extern uint8_t route_distance(int type); -extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq); +extern void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, + bool rt_delete); /* * Inline functions. diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 4000272544..bf34fb54a9 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -2448,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 */ diff --git a/zebra/zebra_evpn_mac.c b/zebra/zebra_evpn_mac.c index e285c206b8..d3791f3e58 100644 --- a/zebra/zebra_evpn_mac.c +++ b/zebra/zebra_evpn_mac.c @@ -2034,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? */ @@ -2182,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) @@ -2486,15 +2471,8 @@ int zebra_evpn_mac_gw_macip_add(struct interface *ifp, struct zebra_evpn *zevpn, 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 9b3ea220f7..af4629e41c 100644 --- a/zebra/zebra_evpn_mh.c +++ b/zebra/zebra_evpn_mh.c @@ -418,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) @@ -446,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 */ @@ -998,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) @@ -1021,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) @@ -1045,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 @@ -1363,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) @@ -3217,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) @@ -3243,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) @@ -3271,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_neigh.c b/zebra/zebra_evpn_neigh.c index 5fb4e07665..7299391ef6 100644 --- a/zebra/zebra_evpn_neigh.c +++ b/zebra/zebra_evpn_neigh.c @@ -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); diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index 5373f27882..b153ac1d81 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -649,19 +649,17 @@ static void zebra_gr_process_client_stale_routes(struct zserv *client, return; /* Check if route update completed for all AFI, SAFI */ - for (afi = AFI_IP; afi < AFI_MAX; afi++) - for (safi = SAFI_UNICAST; safi <= SAFI_MPLS_VPN; safi++) { - if (info->af_enabled[afi][safi]) { - if (!info->route_sync[afi][safi]) { - LOG_GR( - "%s: Client %s route update not completed for AFI %d, SAFI %d", - __func__, zebra_route_string( - client->proto), - afi, safi); - return; - } + FOREACH_AFI_SAFI_NSF (afi, safi) { + if (info->af_enabled[afi][safi]) { + if (!info->route_sync[afi][safi]) { + LOG_GR("%s: Client %s route update not completed for AFI %d, SAFI %d", + __func__, + zebra_route_string(client->proto), afi, + safi); + return; } } + } /* * Route update completed for all AFI, SAFI diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index 46f60a85c4..924a43049b 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -3725,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); } @@ -3754,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 391f28d18f..8cc7724f05 100644 --- a/zebra/zebra_netns_notify.c +++ b/zebra/zebra_netns_notify.c @@ -266,8 +266,8 @@ static int zebra_ns_ready_read(struct thread *t) } if (zebra_ns_notify_is_default_netns(basename(netnspath))) { zlog_warn( - "NS notify : NS %s is default VRF. Updating VRF Name", basename(netnspath)); - vrf_set_default_name(basename(netnspath), false); + "NS notify : NS %s is default VRF. Ignore VRF creation", + basename(netnspath)); return zebra_ns_continue_read(zns_info, 1); } @@ -367,8 +367,8 @@ void zebra_ns_notify_parse(void) } if (zebra_ns_notify_is_default_netns(dent->d_name)) { zlog_warn( - "NS notify : NS %s is default VRF. Updating VRF Name", dent->d_name); - vrf_set_default_name(dent->d_name, false); + "NS notify : NS %s is default VRF. Ignore VRF creation", + dent->d_name); continue; } zebra_ns_notify_create_context_from_entry_name(dent->d_name); diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 50e1d0f389..13fd972499 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -180,7 +180,7 @@ int zebra_ns_final_shutdown(struct ns *ns, return NS_WALK_CONTINUE; } -int zebra_ns_init(const char *optional_default_name) +int zebra_ns_init(void) { struct ns *default_ns; ns_id_t ns_id; @@ -213,10 +213,6 @@ int zebra_ns_init(const char *optional_default_name) /* Default NS is activated */ zebra_ns_enable(ns_id_external, (void **)&dzns); - if (optional_default_name) - vrf_set_default_name(optional_default_name, - true); - if (vrf_is_backend_netns()) { ns_add_hook(NS_NEW_HOOK, zebra_ns_new); ns_add_hook(NS_ENABLE_HOOK, zebra_ns_enabled); diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index 8237de7dde..0519e1d5b3 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -69,7 +69,7 @@ struct zebra_ns { struct zebra_ns *zebra_ns_lookup(ns_id_t ns_id); -int zebra_ns_init(const char *optional_default_name); +int zebra_ns_init(void); int zebra_ns_enable(ns_id_t ns_id, void **info); int zebra_ns_disabled(struct ns *ns); int zebra_ns_early_shutdown(struct ns *ns, diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index c237133130..32edb78c7d 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -1380,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 3df70a3b56..1279c7c9a9 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -305,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; } @@ -692,7 +698,8 @@ static int rib_can_delete_dest(rib_dest_t *dest) return 1; } -void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) +void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq, + bool rt_delete) { rib_dest_t *dest = rib_dest_from_rnode(rn); struct rnh *rnh; @@ -713,6 +720,12 @@ void zebra_rib_evaluate_rn_nexthops(struct route_node *rn, uint32_t seq) __func__, rn, dest ? rnh_list_count(&dest->nht) : 0); + if (rt_delete && (!dest || !rnh_list_count(&dest->nht))) { + if (IS_ZEBRA_DEBUG_NHT_DETAILED) + zlog_debug("%pRN has no tracking NHTs. Bailing", + rn); + break; + } if (!dest) { rn = rn->parent; if (rn) @@ -792,7 +805,8 @@ int rib_gc_dest(struct route_node *rn) rnode_debug(rn, zvrf_id(zvrf), "removing dest from table"); } - zebra_rib_evaluate_rn_nexthops(rn, zebra_router_get_next_sequence()); + zebra_rib_evaluate_rn_nexthops(rn, zebra_router_get_next_sequence(), + true); dest->rnode = NULL; rnh_list_fini(&dest->nht); @@ -1797,6 +1811,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) rib_dest_t *dest; bool fib_changed = false; struct rib_table_info *info; + bool rt_delete = false; zvrf = vrf_info_lookup(dplane_ctx_get_vrf(ctx)); vrf = vrf_lookup_by_id(dplane_ctx_get_vrf(ctx)); @@ -1984,6 +1999,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) } break; case DPLANE_OP_ROUTE_DELETE: + rt_delete = true; if (re) SET_FLAG(re->status, ROUTE_ENTRY_FAILED); /* @@ -2026,7 +2042,7 @@ static void rib_process_result(struct zebra_dplane_ctx *ctx) break; } - zebra_rib_evaluate_rn_nexthops(rn, seq); + zebra_rib_evaluate_rn_nexthops(rn, seq, rt_delete); zebra_rib_evaluate_mpls(rn); done: @@ -2262,8 +2278,8 @@ static void rib_process_dplane_notify(struct zebra_dplane_ctx *ctx) } /* Make any changes visible for lsp and nexthop-tracking processing */ - zebra_rib_evaluate_rn_nexthops( - rn, zebra_router_get_next_sequence()); + zebra_rib_evaluate_rn_nexthops(rn, zebra_router_get_next_sequence(), + false); zebra_rib_evaluate_mpls(rn); @@ -3093,7 +3109,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); diff --git a/zebra/zebra_router.c b/zebra/zebra_router.c index a80c573855..92a3b9424b 100644 --- a/zebra/zebra_router.c +++ b/zebra/zebra_router.c @@ -232,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); 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_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 1cc7e8932b..5913936d57 100644 --- a/zebra/zebra_vrf.c +++ b/zebra/zebra_vrf.c @@ -337,18 +337,6 @@ static int zebra_vrf_delete(struct vrf *vrf) return 0; } -static int zebra_vrf_update(struct vrf *vrf) -{ - struct zebra_vrf *zvrf = vrf->info; - - assert(zvrf); - if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("VRF %s id %u, name updated", vrf->name, - zvrf_id(zvrf)); - zebra_vrf_add_update(zvrf); - return 0; -} - /* Lookup the routing table in a VRF based on both VRF-Id and table-id. * NOTE: Table-id is relevant on two modes: * - case VRF backend is default : on default VRF only @@ -703,7 +691,7 @@ int zebra_vrf_netns_handler_create(struct vty *vty, struct vrf *vrf, void zebra_vrf_init(void) { vrf_init(zebra_vrf_new, zebra_vrf_enable, zebra_vrf_disable, - zebra_vrf_delete, zebra_vrf_update); + zebra_vrf_delete); hook_register(zserv_client_close, release_daemon_table_chunks); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 39695a148c..f35c9f65fb 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -76,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, @@ -158,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, @@ -565,8 +566,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 */ @@ -914,7 +921,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; @@ -1002,6 +1009,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)) { @@ -1075,6 +1087,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) { @@ -1147,16 +1162,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, @@ -1165,7 +1176,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; @@ -1256,7 +1268,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) { @@ -1266,14 +1279,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, @@ -1281,7 +1288,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; @@ -1300,7 +1307,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); } } @@ -1310,7 +1317,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; @@ -1343,7 +1350,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; } @@ -1827,7 +1834,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" @@ -1856,7 +1863,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; @@ -1892,18 +1900,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; @@ -1922,13 +1930,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; @@ -2505,10 +2513,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", @@ -2656,10 +2661,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", @@ -2700,7 +2702,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; } @@ -2732,7 +2734,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; @@ -3031,9 +3034,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; diff --git a/zebra/zebra_vxlan.c b/zebra/zebra_vxlan.c index 84ab4a718d..b6da445e38 100644 --- a/zebra/zebra_vxlan.c +++ b/zebra/zebra_vxlan.c @@ -2315,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) @@ -2359,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) @@ -2387,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, @@ -2432,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) @@ -2476,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) @@ -2504,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); } /* @@ -2542,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, @@ -2633,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); } /* @@ -2663,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); } /* @@ -2694,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); } /* @@ -2735,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); } /* @@ -2783,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); } /* @@ -2849,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); } /* @@ -2907,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); } } @@ -2936,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); } /* @@ -2968,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); } /* @@ -2998,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); } /* @@ -3042,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 */ @@ -3100,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); } } @@ -3442,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); } } @@ -3493,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); } } @@ -3564,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); } /* @@ -3604,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) @@ -3693,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); } /* @@ -4660,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) |
