diff options
169 files changed, 14521 insertions, 8809 deletions
diff --git a/bfdd/bfdd_vty.c b/bfdd/bfdd_vty.c index 4091ab9caa..fc3a178703 100644 --- a/bfdd/bfdd_vty.c +++ b/bfdd/bfdd_vty.c @@ -282,8 +282,7 @@ static void _display_peer_json(struct vty *vty, struct bfd_session *bs) { struct json_object *jo = __display_peer_json(bs); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } struct bfd_vrf_tuple { @@ -353,8 +352,7 @@ static void _display_all_peers(struct vty *vty, char *vrfname, bool use_json) bvt.jo = jo; bfd_id_iterate(_display_peer_json_iter, &bvt); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } static void _display_peer_counter(struct vty *vty, struct bfd_session *bs) @@ -407,8 +405,7 @@ static void _display_peer_counters_json(struct vty *vty, struct bfd_session *bs) { struct json_object *jo = __display_peer_counters_json(bs); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } static void _display_peer_counter_iter(struct hash_bucket *hb, void *arg) @@ -472,8 +469,7 @@ static void _display_peers_counter(struct vty *vty, char *vrfname, bool use_json bvt.jo = jo; bfd_id_iterate(_display_peer_counter_json_iter, &bvt); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } static void _clear_peer_counter(struct bfd_session *bs) @@ -556,8 +552,7 @@ static void _display_peers_brief(struct vty *vty, const char *vrfname, bool use_ bfd_id_iterate(_display_peer_json_iter, &bvt); - vty_out(vty, "%s\n", json_object_to_json_string_ext(jo, 0)); - json_object_free(jo); + vty_json(vty, jo); } static struct bfd_session * 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_damp.c b/bgpd/bgp_damp.c index 6726dd6160..90b7958c43 100644 --- a/bgpd/bgp_damp.c +++ b/bgpd/bgp_damp.c @@ -653,21 +653,42 @@ const char *bgp_damp_reuse_time_vty(struct vty *vty, struct bgp_path_info *path, } static int bgp_print_dampening_parameters(struct bgp *bgp, struct vty *vty, - afi_t afi, safi_t safi) + afi_t afi, safi_t safi, bool use_json) { if (CHECK_FLAG(bgp->af_flags[afi][safi], BGP_CONFIG_DAMPENING)) { - vty_out(vty, "Half-life time: %lld min\n", - (long long)damp[afi][safi].half_life / 60); - vty_out(vty, "Reuse penalty: %d\n", - damp[afi][safi].reuse_limit); - vty_out(vty, "Suppress penalty: %d\n", - damp[afi][safi].suppress_value); - vty_out(vty, "Max suppress time: %lld min\n", - (long long)damp[afi][safi].max_suppress_time / 60); - vty_out(vty, "Max suppress penalty: %u\n", - damp[afi][safi].ceiling); - vty_out(vty, "\n"); - } else + struct bgp_damp_config *bdc = &damp[afi][safi]; + + if (use_json) { + json_object *json = json_object_new_object(); + + json_object_int_add(json, "halfLifeSecs", + bdc->half_life); + json_object_int_add(json, "reusePenalty", + bdc->reuse_limit); + json_object_int_add(json, "suppressPenalty", + bdc->suppress_value); + json_object_int_add(json, "maxSuppressTimeSecs", + bdc->max_suppress_time); + json_object_int_add(json, "maxSuppressPenalty", + bdc->ceiling); + + vty_out(vty, "%s\n", + json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } else { + vty_out(vty, "Half-life time: %lld min\n", + (long long)bdc->half_life / 60); + vty_out(vty, "Reuse penalty: %d\n", bdc->reuse_limit); + vty_out(vty, "Suppress penalty: %d\n", + bdc->suppress_value); + vty_out(vty, "Max suppress time: %lld min\n", + (long long)bdc->max_suppress_time / 60); + vty_out(vty, "Max suppress penalty: %u\n", + bdc->ceiling); + vty_out(vty, "\n"); + } + } else if (!use_json) vty_out(vty, "dampening not enabled for %s\n", get_afi_safi_str(afi, safi, false)); @@ -678,6 +699,8 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, uint16_t show_flags) { struct bgp *bgp; + bool use_json = CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON); + bgp = bgp_get_default(); if (bgp == NULL) { @@ -686,7 +709,8 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, } if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_ALL)) - return bgp_print_dampening_parameters(bgp, vty, afi, safi); + return bgp_print_dampening_parameters(bgp, vty, afi, safi, + use_json); if (CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP) || CHECK_FLAG(show_flags, BGP_SHOW_OPT_AFI_IP6)) { @@ -697,11 +721,12 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, "Unknown")) continue; - if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON)) + if (!use_json) vty_out(vty, "\nFor address family: %s\n\n", get_afi_safi_str(afi, safi, false)); - bgp_print_dampening_parameters(bgp, vty, afi, safi); + bgp_print_dampening_parameters(bgp, vty, afi, safi, + use_json); } } else { FOREACH_AFI_SAFI (afi, safi) { @@ -709,11 +734,12 @@ int bgp_show_dampening_parameters(struct vty *vty, afi_t afi, safi_t safi, "Unknown")) continue; - if (!CHECK_FLAG(show_flags, BGP_SHOW_OPT_JSON)) + if (!use_json) vty_out(vty, "\nFor address family: %s\n", get_afi_safi_str(afi, safi, false)); - bgp_print_dampening_parameters(bgp, vty, afi, safi); + bgp_print_dampening_parameters(bgp, vty, afi, safi, + use_json); } } return CMD_SUCCESS; diff --git a/bgpd/bgp_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_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_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..a05921e7b6 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 @@ -1088,7 +1091,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 +1107,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 +1115,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 +1165,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 +1185,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 +1197,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 +1308,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 +1325,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 +1374,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 +1401,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 +1457,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 +1479,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 +1506,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 +1524,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 +1554,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 +1576,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 +1603,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 +1637,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 +1657,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 +1708,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 +1720,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 +1738,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 +1761,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 +1774,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..cc0ee9e8f2 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; 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..cd9893fd91 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -548,6 +548,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 +606,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 +618,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 +633,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, @@ -859,6 +882,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); @@ -3629,6 +3660,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 +3675,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 +3766,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 +3809,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++; @@ -8384,7 +8420,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 +8430,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 +8454,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 +9133,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); @@ -10635,21 +10667,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 +11264,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 +11317,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); } @@ -11674,10 +11689,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 +12024,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 +12062,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 +12078,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 +12111,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 +12128,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 +12207,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 +12287,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 +12317,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 +12355,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 +12387,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 +12577,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 +12599,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 +13154,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 @@ -13765,10 +13714,6 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi, json_object_int_add(json, "filteredPrefixCounter", filtered_count); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - /* * These fields only give up ownership to `json` when `header1` * is used (set to zero). See code in `show_adj_route` and @@ -13779,7 +13724,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, @@ -15102,10 +15047,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..4cc56c8649 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -633,6 +633,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); 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_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..8a63030181 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, @@ -6308,6 +6302,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 +9742,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 +10274,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 +10843,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) @@ -12363,10 +12375,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 +12521,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,6 +12601,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json, vty_out(vty, " Configured tcp-mss is %d", p->tcp_mss); vty_out(vty, ", synced tcp-mss is %d\n", sync_tcp_mss); } + + /* Extended Optional Parameters Length for BGP OPEN Message */ + if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(p)) + vty_out(vty, + " Extended Optional Parameters Length is enabled\n"); } /* Capability. */ if (peer_established(p)) { @@ -14178,13 +14203,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 +14445,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 +14754,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 +14826,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 +14938,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 +14983,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 +15416,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 +15439,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 +16673,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 +18635,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 a9d9b8d393..bbb7d5469d 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1252,6 +1252,7 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, uint8_t distance; struct peer *peer; struct bgp_path_info *mpinfo; + struct bgp *bgp_orig; uint32_t metric; struct attr local_attr; struct bgp_path_info local_info; @@ -1415,13 +1416,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, } } + BGP_ORIGINAL_UPDATE(bgp_orig, mpinfo, bgp); + if (nh_family == AF_INET) { nh_updated = update_ipv4nh_for_route_install( - nh_othervrf, - nh_othervrf ? - info->extra->bgp_orig : bgp, - &mpinfo_cp->attr->nexthop, - mpinfo_cp->attr, is_evpn, api_nh); + nh_othervrf, bgp_orig, + &mpinfo_cp->attr->nexthop, mpinfo_cp->attr, + is_evpn, api_nh); } else { ifindex_t ifindex = IFINDEX_INTERNAL; struct in6_addr *nexthop; @@ -1431,18 +1432,13 @@ void bgp_zebra_announce(struct bgp_dest *dest, const struct prefix *p, if (!nexthop) nh_updated = update_ipv4nh_for_route_install( - nh_othervrf, - nh_othervrf ? info->extra->bgp_orig - : bgp, + nh_othervrf, bgp_orig, &mpinfo_cp->attr->nexthop, mpinfo_cp->attr, is_evpn, api_nh); else nh_updated = update_ipv6nh_for_route_install( - nh_othervrf, - nh_othervrf ? info->extra->bgp_orig - : bgp, - nexthop, ifindex, mpinfo, info, is_evpn, - api_nh); + nh_othervrf, bgp_orig, nexthop, ifindex, + mpinfo, info, is_evpn, api_nh); } /* Did we get proper nexthop info to update zebra? */ 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..5cc5feba3a 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -4181,6 +4181,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[] = { @@ -7903,11 +7904,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 +7923,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..7c91065601 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]; diff --git a/configure.ac b/configure.ac index 42b3b659a7..c153e4c261 100644 --- a/configure.ac +++ b/configure.ac @@ -1915,6 +1915,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/frr-release-procedure.rst b/doc/developer/frr-release-procedure.rst index 08e3057ae6..7c10e6a8fc 100644 --- a/doc/developer/frr-release-procedure.rst +++ b/doc/developer/frr-release-procedure.rst @@ -6,27 +6,29 @@ FRR Release Procedure ``<version>`` - version to be released, e.g. 7.3 ``origin`` - FRR upstream repository -1. Checkout ``dev/<version>``. +Stage 1 - Preparation +--------------------- + +#. 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 +49,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 +82,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> - - Edit :file:`configure.ac` and change version in the ``AC_INIT`` command - to ``<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``. -7. Commit the changes, adding the changelog to the commit message. Follow all - existing commit guidelines. -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. +Stage 2 - Staging +----------------- -9. Create a git tag for the version: +#. Push the stable branch to a new remote branch prefixed with ``rc``:: + + git push origin stable/<version>:rc/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: + + https://ci1.netdef.org/browse/FRR-FRR + + 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. + +#. 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/user/bgp.rst b/doc/user/bgp.rst index db59c42773..2f8c5c01da 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -1423,6 +1423,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 @@ -3553,6 +3562,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 +3601,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 +3675,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/overview.rst b/doc/user/overview.rst index efe64b72f0..acae3eb27b 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -371,7 +371,8 @@ 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:`9072` + :t:`Extended Optional Parameters Length for BGP OPEN Message. E. Chen, J. Scudder. July 2021` OSPF ---- 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/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/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); } @@ -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/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..046ccadc09 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( @@ -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/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 552ba565b4..2685bd2d79 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -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( 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/srv6.c b/lib/srv6.c index ccb94b2f76..aacd30a7af 100644 --- a/lib/srv6.c +++ b/lib/srv6.c @@ -161,12 +161,10 @@ 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)); @@ -175,7 +173,6 @@ json_object *srv6_locator_chunk_json(const struct srv6_locator_chunk *chunk) 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 +185,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", @@ -690,15 +690,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); } 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_area.c b/ospf6d/ospf6_area.c index f35971ba8c..7e8e34a221 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; } diff --git a/ospf6d/ospf6_asbr.c b/ospf6d/ospf6_asbr.c index b439f947de..99f30a4a06 100644 --- a/ospf6d/ospf6_asbr.c +++ b/ospf6d/ospf6_asbr.c @@ -1410,7 +1410,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, struct ospf6_route *route, *match; struct ospf6_external_info *info; struct prefix prefix_id; - struct route_node *node; char ibuf[16]; struct ospf6_redist *red; @@ -1497,13 +1496,6 @@ void ospf6_asbr_redistribute_add(int type, ifindex_t ifindex, else ospf6_route_add_nexthop(match, ifindex, NULL); - /* create/update binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = IPV4_MAX_BITLEN; - prefix_id.u.prefix4.s_addr = htonl(info->id); - node = route_node_get(ospf6->external_id_table, &prefix_id); - node->info = match; - if (IS_OSPF6_DEBUG_ASBR) { inet_ntop(AF_INET, &prefix_id.u.prefix4, ibuf, sizeof(ibuf)); @@ -2553,10 +2545,7 @@ DEFUN(show_ipv6_ospf6_redistribute, show_ipv6_ospf6_redistribute_cmd, if (uj) { json_object_object_add(json, "routes", json_array_routes); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } if (!all_vrf) @@ -2787,7 +2776,6 @@ static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6, struct ospf6_external_aggr_rt *aggr) { struct prefix prefix_id; - struct route_node *node; struct ospf6_lsa *lsa = NULL; if (IS_OSPF6_DEBUG_AGGR) @@ -2796,13 +2784,6 @@ static void ospf6_originate_new_aggr_lsa(struct ospf6 *ospf6, aggr->id = ospf6->external_id++; - /* create/update binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = 32; - prefix_id.u.prefix4.s_addr = htonl(aggr->id); - node = route_node_get(ospf6->external_id_table, &prefix_id); - node->info = aggr; - if (IS_OSPF6_DEBUG_AGGR) zlog_debug( "Advertise AS-External Id:%pI4 prefix %pFX metric %u", @@ -3014,8 +2995,6 @@ static void ospf6_aggr_handle_external_info(void *data) struct ospf6_lsa *lsa = NULL; struct ospf6_external_info *info; struct ospf6 *ospf6 = NULL; - struct prefix prefix_id; - struct route_node *node; rt->aggr_route = NULL; @@ -3055,13 +3034,6 @@ static void ospf6_aggr_handle_external_info(void *data) info->id = ospf6->external_id++; rt->path.origin.id = htonl(info->id); - /* create/update binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = 32; - prefix_id.u.prefix4.s_addr = htonl(info->id); - node = route_node_get(ospf6->external_id_table, &prefix_id); - node->info = rt; - (void)ospf6_originate_type5_type7_lsas(rt, ospf6); } @@ -3642,7 +3614,6 @@ void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6, struct ospf6_external_aggr_rt *aggr; struct ospf6_external_info *info; struct prefix prefix_id; - struct route_node *node; if (!is_default_prefix(p)) { aggr = ospf6_external_aggr_match(ospf6, @@ -3678,14 +3649,6 @@ void ospf6_handle_external_lsa_origination(struct ospf6 *ospf6, */ if (!info->id) { info->id = ospf6->external_id++; - - /* create/update binding in external_id_table */ - prefix_id.family = AF_INET; - prefix_id.prefixlen = 32; - prefix_id.u.prefix4.s_addr = htonl(info->id); - node = route_node_get(ospf6->external_id_table, &prefix_id); - node->info = rt; - } else { prefix_id.family = AF_INET; prefix_id.prefixlen = 32; diff --git a/ospf6d/ospf6_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..a0c921f419 100644 --- a/ospf6d/ospf6_interface.c +++ b/ospf6d/ospf6_interface.c @@ -1277,10 +1277,7 @@ static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id, if (ifp == NULL) { json_object_string_add(json, "noSuchInterface", argv[idx_ifname]->arg); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); json_object_free(json_int); return CMD_WARNING; } @@ -1294,10 +1291,7 @@ static int show_ospf6_interface_common(struct vty *vty, vrf_id_t vrf_id, json_int); } } - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { if (argc == intf_idx) { ifp = if_lookup_by_name(argv[idx_ifname]->arg, vrf_id); @@ -1484,10 +1478,7 @@ static int ospf6_interface_show_traffic_common(struct vty *vty, int argc, "No Such Interface"); json_object_string_add(json, "interface", intf_name); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); return CMD_WARNING; } if (ifp->info == NULL) { @@ -1496,10 +1487,7 @@ static int ospf6_interface_show_traffic_common(struct vty *vty, int argc, "OSPF not enabled on this interface"); json_object_string_add(json, "interface", intf_name); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); return 0; } } else { @@ -1519,12 +1507,8 @@ static int ospf6_interface_show_traffic_common(struct vty *vty, int argc, ospf6_interface_show_traffic(vty, ifp, display_once, json, uj, vrf_id); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } 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..1a8fedea0c 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); } } @@ -1148,12 +1145,8 @@ static int ospf6_neighbor_show_common(struct vty *vty, int argc, (*showfunc)(vty, on, json, uj); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } 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 6c79dcfb71..6bff52fc56 100644 --- a/ospf6d/ospf6_top.c +++ b/ospf6d/ospf6_top.c @@ -423,7 +423,6 @@ static struct ospf6 *ospf6_create(const char *name) * 1::1, this happened because of LS ID 0. */ o->external_id = OSPF6_EXT_INIT_LS_ID; - o->external_id_table = route_table_init(); o->write_oi_count = OSPF6_WRITE_INTERFACE_COUNT_DEFAULT; o->ref_bandwidth = OSPF6_REFERENCE_BANDWIDTH; @@ -515,7 +514,6 @@ void ospf6_delete(struct ospf6 *o) ospf6_route_table_delete(o->brouter_table); ospf6_route_table_delete(o->external_table); - route_table_finish(o->external_id_table); ospf6_distance_reset(o); route_table_finish(o->distance_table); @@ -1498,10 +1496,7 @@ DEFUN(show_ipv6_ospf6_vrfs, show_ipv6_ospf6_vrfs_cmd, json_object_object_add(json, "vrfs", json_vrfs); json_object_int_add(json, "totalVrfs", count); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else { if (count) vty_out(vty, "\nTotal number of OSPF VRFs: %d\n", @@ -2093,9 +2088,7 @@ DEFPY (show_ipv6_ospf6_external_aggregator, } if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } return CMD_SUCCESS; @@ -2103,9 +2096,8 @@ DEFPY (show_ipv6_ospf6_external_aggregator, static void ospf6_stub_router_config_write(struct vty *vty, struct ospf6 *ospf6) { - if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) { + if (CHECK_FLAG(ospf6->flag, OSPF6_STUB_ROUTER)) vty_out(vty, " stub-router administrative\n"); - } return; } diff --git a/ospf6d/ospf6_top.h b/ospf6d/ospf6_top.h index 55cab72307..4cc0923e93 100644 --- a/ospf6d/ospf6_top.h +++ b/ospf6d/ospf6_top.h @@ -136,7 +136,6 @@ struct ospf6 { struct ospf6_route_table *brouter_table; struct ospf6_route_table *external_table; - struct route_table *external_id_table; #define OSPF6_EXT_INIT_LS_ID 1 uint32_t external_id; diff --git a/ospf6d/ospf6d.c b/ospf6d/ospf6d.c index 5e6dcde991..d9f730586b 100644 --- a/ospf6d/ospf6d.c +++ b/ospf6d/ospf6d.c @@ -292,10 +292,7 @@ static void ospf6_lsdb_show_wrapper(struct vty *vty, json_object_array_add(json_array, json_obj); json_object_object_add(json, "asScopedLinkStateDb", json_array); - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); + vty_json(vty, json); } else vty_out(vty, "\n"); } @@ -386,12 +383,9 @@ static void ospf6_lsdb_type_show_wrapper(struct vty *vty, assert(0); break; } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "\n"); } diff --git a/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_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_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 84469160d3..6979b34196 100644 --- a/ospfd/ospf_vty.c +++ b/ospfd/ospf_vty.c @@ -3386,23 +3386,17 @@ DEFUN (show_ip_ospf, ret = show_ip_ospf_common(vty, ospf, json, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else if (!ospf_output) + if (uj) + vty_json(vty, json); + else if (!ospf_output) vty_out(vty, "%% OSPF instance not found\n"); return ret; } ospf = ospf_lookup_by_inst_name(inst, vrf_name); if ((ospf == NULL) || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -3411,12 +3405,9 @@ DEFUN (show_ip_ospf, ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); /* Display default ospf (instance 0) info */ if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -3466,11 +3457,8 @@ DEFUN (show_ip_ospf_instance, ret = show_ip_ospf_common(vty, ospf, json, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4130,24 +4118,18 @@ DEFUN (show_ip_ospf_interface, uj); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else if (!ospf) + if (uj) + vty_json(vty, json); + else if (!ospf) vty_out(vty, "%% OSPF instance not found\n"); return ret; } ospf = ospf_lookup_by_inst_name(inst, vrf_name); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -4159,12 +4141,9 @@ DEFUN (show_ip_ospf_interface, /* Display default ospf (instance 0) info */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -4173,11 +4152,8 @@ DEFUN (show_ip_ospf_interface, use_vrf, json, uj); } - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4218,11 +4194,8 @@ DEFUN (show_ip_ospf_instance_interface, ret = show_ip_ospf_interface_common(vty, ospf, intf_name, 0, json, uj); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4273,12 +4246,8 @@ DEFUN (show_ip_ospf_interface_traffic, display_once = 1; } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4303,11 +4272,8 @@ DEFUN (show_ip_ospf_interface_traffic, vty, ospf, intf_name, json, display_once, use_vrf, uj); } - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4560,12 +4526,9 @@ DEFUN (show_ip_ospf_neighbor, vty, ospf, json, uj, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else if (!ospf) + if (uj) + vty_json(vty, json); + else if (!ospf) vty_out(vty, "OSPF instance not found\n"); return ret; @@ -4573,12 +4536,9 @@ DEFUN (show_ip_ospf_neighbor, ospf = ospf_lookup_by_inst_name(inst, vrf_name); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -4587,12 +4547,9 @@ DEFUN (show_ip_ospf_neighbor, /* Display default ospf (instance 0) info */ ospf = ospf_lookup_by_vrf_id(VRF_DEFAULT); if (ospf == NULL || !ospf->oi_running) { - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (uj) + vty_json(vty, json); + else vty_out(vty, "%% OSPF instance not found\n"); return CMD_SUCCESS; @@ -4647,11 +4604,8 @@ DEFUN (show_ip_ospf_instance_neighbor, ret = show_ip_ospf_neighbor_common(vty, ospf, json, uj, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4785,12 +4739,8 @@ DEFUN (show_ip_ospf_neighbor_all, vty, ospf, json, uj, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4857,11 +4807,8 @@ DEFUN (show_ip_ospf_instance_neighbor_all, ret = show_ip_ospf_neighbor_all_common(vty, ospf, json, uj, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -4906,11 +4853,9 @@ static int show_ip_ospf_neighbor_int_common(struct vty *vty, struct ospf *ospf, show_ip_ospf_neighbor_sub(vty, oi, json, use_json); } - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (use_json) + vty_json(vty, json); + else vty_out(vty, "\n"); return CMD_SUCCESS; @@ -5410,11 +5355,9 @@ static int show_ip_ospf_neighbor_id_common(struct vty *vty, struct ospf *ospf, } } - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (use_json) + vty_json(vty, json); + else vty_out(vty, "\n"); return CMD_SUCCESS; @@ -5565,12 +5508,8 @@ DEFUN (show_ip_ospf_neighbor_detail, ret = show_ip_ospf_neighbor_detail_common( vty, ospf, json, uj, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -5637,11 +5576,8 @@ DEFUN (show_ip_ospf_instance_neighbor_detail, ret = show_ip_ospf_neighbor_detail_common(vty, ospf, json, uj, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -5754,12 +5690,8 @@ DEFUN (show_ip_ospf_neighbor_detail_all, vty, ospf, json, uj, use_vrf); } - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -5827,11 +5759,8 @@ DEFUN (show_ip_ospf_instance_neighbor_detail_all, ret = show_ip_ospf_neighbor_detail_all_common(vty, ospf, json, uj, 0); - if (uj) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return ret; } @@ -5887,11 +5816,9 @@ static int show_ip_ospf_neighbor_int_detail_common(struct vty *vty, } } - if (use_json) { - vty_out(vty, "%s\n", json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } else + if (use_json) + vty_json(vty, json); + else vty_out(vty, "\n"); return CMD_SUCCESS; @@ -5966,7 +5893,6 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self, struct summary_lsa *sl; struct as_external_lsa *asel; struct prefix_ipv4 p; - char buf[PREFIX2STR_BUFFER]; if (lsa != NULL) /* If self option is set, check LSA self flag. */ @@ -6025,10 +5951,9 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self, if (!json_lsa) vty_out(vty, " %pFX", &p); else { - prefix2str(&p, buf, sizeof(buf)); - json_object_string_add(json_lsa, - "summaryAddress", - buf); + json_object_string_addf( + json_lsa, "summaryAddress", + "%pFX", &p); } break; case OSPF_AS_EXTERNAL_LSA: @@ -6050,15 +5975,14 @@ static int show_lsa_summary(struct vty *vty, struct ospf_lsa *lsa, int self, (unsigned long)ntohl( asel->e[0].route_tag)); else { - prefix2str(&p, buf, sizeof(buf)); json_object_string_add( json_lsa, "metricType", IS_EXTERNAL_METRIC( asel->e[0].tos) ? "E2" : "E1"); - json_object_string_add(json_lsa, - "route", buf); + json_object_string_addf( + json_lsa, "route", "%pFX", &p); json_object_int_add( json_lsa, "tag", (unsigned long)ntohl( @@ -7200,12 +7124,8 @@ DEFUN (show_ip_ospf_instance_database_max, show_ip_ospf_database_common(vty, ospf, 1, argc, argv, 0, json, uj); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -7417,12 +7337,8 @@ DEFUN (show_ip_ospf_instance_database_type_adv_router, show_ip_ospf_database_type_adv_router_common(vty, ospf, 1, argc, argv, 0, json, uj); - if (uj) { - vty_out(vty, "%s\n", - json_object_to_json_string_ext( - json, JSON_C_TO_STRING_PRETTY)); - json_object_free(json); - } + if (uj) + vty_json(vty, json); return CMD_SUCCESS; } @@ -10632,11 +10548,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"); @@ -10644,14 +10556,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; @@ -10660,14 +10567,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; @@ -10771,9 +10673,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", @@ -11060,12 +10960,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; } @@ -11073,12 +10969,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; @@ -11089,12 +10982,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; @@ -11103,11 +10993,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; } diff --git a/pathd/path_ted.c b/pathd/path_ted.c index d17b5a0aab..6bfca50450 100644 --- a/pathd/path_ted.c +++ b/pathd/path_ted.c @@ -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_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/pim_cmd.c b/pimd/pim_cmd.c index 501d69dbf5..81b3ab2979 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -508,7 +508,7 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, if (!pim_ifp) continue; - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_socket_list, sock_node, + for (ALL_LIST_ELEMENTS_RO(pim_ifp->socket_list, sock_node, igmp)) { char uptime[10]; char query_hhmmss[10]; @@ -525,7 +525,7 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, json_object_string_add(json_row, "upTime", uptime); json_object_int_add(json_row, "version", - pim_ifp->igmp_version); + pim_ifp->version); if (igmp->t_igmp_query_timer) { json_object_boolean_true_add(json_row, @@ -555,7 +555,7 @@ static void igmp_show_interfaces(struct pim_instance *pim, struct vty *vty, : "down", inet_ntop(AF_INET, &igmp->ifaddr, buf, sizeof(buf)), - pim_ifp->igmp_version, + pim_ifp->version, igmp->t_igmp_query_timer ? "local" : "other", &igmp->querier_addr, query_hhmmss, @@ -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->socket_list, sock_node, igmp)) { found_ifname = 1; pim_time_uptime(uptime, sizeof(uptime), @@ -625,35 +625,33 @@ 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->query_max_response_time_dsec); - sqi = PIM_IGMP_SQI( - pim_ifp->igmp_default_query_interval); + sqi = PIM_IGMP_SQI(pim_ifp->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->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->specific_query_max_response_time_dsec, + pim_ifp->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) + pim_ifp->query_max_response_time_dsec) * 100; - qri_msec = pim_ifp->igmp_query_max_response_time_dsec - * 100; + qri_msec = pim_ifp->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->last_member_query_count; if (uj) { json_row = json_object_new_object(); @@ -676,7 +674,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, "queryOtherTimer", other_hhmmss); json_object_int_add(json_row, "version", - pim_ifp->igmp_version); + pim_ifp->version); json_object_int_add( json_row, "timerGroupMembershipIntervalMsec", @@ -727,7 +725,7 @@ static void igmp_show_interfaces_single(struct pim_instance *pim, &pim_ifp->primary_address); vty_out(vty, "Uptime : %s\n", uptime); vty_out(vty, "Version : %d\n", - pim_ifp->igmp_version); + pim_ifp->version); vty_out(vty, "\n"); vty_out(vty, "\n"); @@ -833,15 +831,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->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, - ij)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->join_list, join_node, ij)) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; char uptime[10]; @@ -887,7 +884,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->join_list) */ } /* for (iflist) */ @@ -1340,7 +1337,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->socket_list, sock_node, igmp)) { igmp_stats_add(&rx_stats, &igmp->rx_stats); } @@ -3429,8 +3426,7 @@ static void igmp_show_groups(struct pim_instance *pim, struct vty *vty, bool uj) continue; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, - grp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->group_list, grpnode, grp)) { char group_str[INET_ADDRSTRLEN]; char hhmmss[10]; char uptime[10]; @@ -3523,8 +3519,7 @@ static void igmp_show_group_retransmission(struct pim_instance *pim, continue; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, - grp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->group_list, grpnode, grp)) { char group_str[INET_ADDRSTRLEN]; char grp_retr_mmss[10]; struct listnode *src_node; @@ -3576,8 +3571,7 @@ static void igmp_show_sources(struct pim_instance *pim, struct vty *vty) continue; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, - grp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->group_list, grpnode, grp)) { char group_str[INET_ADDRSTRLEN]; struct listnode *srcnode; struct igmp_source *src; @@ -3610,7 +3604,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 */ } @@ -3632,8 +3626,7 @@ static void igmp_show_source_retransmission(struct pim_instance *pim, continue; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, - grp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->group_list, grpnode, grp)) { char group_str[INET_ADDRSTRLEN]; struct listnode *srcnode; struct igmp_source *src; @@ -3654,7 +3647,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 */ } @@ -3923,9 +3916,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->group_list) { + while (pim_ifp->group_list->count) { + grp = listnode_head(pim_ifp->group_list); igmp_group_delete(grp); } } 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..effc6fbb8d 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -124,16 +124,14 @@ struct pim_interface *pim_if_new(struct interface *ifp, bool igmp, bool pim, pim_ifp->pim = ifp->vrf->info; pim_ifp->mroute_vif_index = -1; - pim_ifp->igmp_version = IGMP_DEFAULT_VERSION; - pim_ifp->igmp_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->version = IGMP_DEFAULT_VERSION; + pim_ifp->default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; + pim_ifp->default_query_interval = IGMP_GENERAL_QUERY_INTERVAL; + pim_ifp->query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC; - pim_ifp->igmp_specific_query_max_response_time_dsec = + pim_ifp->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->last_member_query_count = IGMP_DEFAULT_ROBUSTNESS_VARIABLE; /* BSM config on interface: true by default */ pim_ifp->bsm_enable = true; @@ -145,8 +143,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->query_max_response_time_dsec + < pim_ifp->default_query_interval); if (pim) PIM_IF_DO_PIM(pim_ifp->options); @@ -155,7 +153,7 @@ 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->join_list = NULL; pim_ifp->pim_neighbor_list = NULL; pim_ifp->upstream_switch_list = NULL; pim_ifp->pim_generation_id = 0; @@ -200,7 +198,7 @@ void pim_if_delete(struct interface *ifp) pim_ifp = ifp->info; assert(pim_ifp); - if (pim_ifp->igmp_join_list) { + if (pim_ifp->join_list) { pim_if_igmp_join_del_all(ifp); } @@ -289,7 +287,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 */ @@ -535,27 +533,27 @@ void pim_if_addr_add(struct connected *ifc) struct igmp_sock *igmp; /* lookup IGMP socket */ - igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->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, - ifaddr, ifp, false); + pim_igmp_sock_add(pim_ifp->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->socket_list, ifaddr, ifp, + false); } /* Replay Static IGMP groups */ - if (pim_ifp->igmp_join_list) { + if (pim_ifp->join_list) { struct listnode *node; struct listnode *nextnode; struct igmp_join *ij; int join_fd; - for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, + for (ALL_LIST_ELEMENTS(pim_ifp->join_list, node, nextnode, ij)) { /* Close socket and reopen with Source and Group */ @@ -586,14 +584,14 @@ void pim_if_addr_add(struct connected *ifc) struct igmp_sock *igmp; /* lookup IGMP socket */ - igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list, + igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->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->socket_list, ifaddr, ifp, + true); } } /* igmp mtrace only */ @@ -664,7 +662,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->socket_list, ifaddr); if (igmp) { /* if addr found, del IGMP socket */ igmp_sock_delete(igmp); @@ -828,26 +826,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; @@ -1265,7 +1243,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->join_list, ij); return ij; } @@ -1282,12 +1260,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->join_list) { + pim_ifp->join_list = list_new(); + pim_ifp->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->join_list, group_addr, source_addr); /* This interface has already been configured to join this IGMP group */ @@ -1326,13 +1304,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->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->join_list, group_addr, source_addr); if (!ij) { char group_str[INET_ADDRSTRLEN]; char source_str[INET_ADDRSTRLEN]; @@ -1359,11 +1337,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->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->join_list) < 1) { + list_delete(&pim_ifp->join_list); + pim_ifp->join_list = 0; } return 0; @@ -1383,10 +1361,10 @@ static void pim_if_igmp_join_del_all(struct interface *ifp) return; } - if (!pim_ifp->igmp_join_list) + if (!pim_ifp->join_list) return; - for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij)) + for (ALL_LIST_ELEMENTS(pim_ifp->join_list, node, nextnode, ij)) pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr); } @@ -1694,8 +1672,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..bf8e4bd024 100644 --- a/pimd/pim_iface.h +++ b/pimd/pim_iface.h @@ -61,6 +61,20 @@ #define PIM_I_am_DR(pim_ifp) (pim_ifp)->pim_dr_addr.s_addr == (pim_ifp)->primary_address.s_addr #define PIM_I_am_DualActive(pim_ifp) (pim_ifp)->activeactive == true +/* Macros for interface flags */ + +/* + * PIM needs to know if hello is required to send before other PIM messages + * like Join, prune, assert would go out + */ +#define PIM_IF_FLAG_HELLO_SENT (1 << 0) + +#define PIM_IF_FLAG_TEST_HELLO_SENT(flags) ((flags)&PIM_IF_FLAG_HELLO_SENT) + +#define PIM_IF_FLAG_SET_HELLO_SENT(flags) ((flags) |= PIM_IF_FLAG_HELLO_SENT) + +#define PIM_IF_FLAG_UNSET_HELLO_SENT(flags) ((flags) &= ~PIM_IF_FLAG_HELLO_SENT) + struct pim_iface_upstream_switch { struct in_addr address; struct list *us; @@ -86,13 +100,13 @@ struct pim_interface { struct in_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 version; /* IGMP or MLD version */ + int default_robustness_variable; /* IGMP or MLD QRV */ + int default_query_interval; /* IGMP or MLD secs between general queries */ - int igmp_query_max_response_time_dsec; /* IGMPv3 Max Response Time in + int 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 + int specific_query_max_response_time_dsec; /* IGMP or MLD Max Response Time in dsecs called as last member query interval, defines the @@ -100,11 +114,11 @@ struct pim_interface { 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 last_member_query_count; /* IGMP or MLD last member query count */ + struct list *socket_list; /* list of struct IGMP or MLD sock */ + struct list *join_list; /* list of struct IGMP or MLD join */ + struct list *group_list; /* list of struct IGMP or MLD group */ + struct hash *group_hash; int pim_sock_fd; /* PIM socket file descriptor */ struct thread *t_pim_sock_read; /* thread for reading PIM socket */ @@ -161,6 +175,7 @@ struct pim_interface { uint32_t pim_ifstat_bsm_cfg_miss; uint32_t pim_ifstat_ucast_bsm_cfg_miss; uint32_t pim_ifstat_bsm_invalid_sz; + uint8_t flags; bool bsm_enable; /* bsm processing enable */ bool ucast_bsm_accept; /* ucast bsm processing */ @@ -193,7 +208,6 @@ void pim_if_addr_del(struct connected *ifc, int force_prim_as_any); void pim_if_addr_add_all(struct interface *ifp); void pim_if_addr_del_all(struct interface *ifp); void pim_if_addr_del_all_igmp(struct interface *ifp); -void pim_if_addr_del_all_pim(struct interface *ifp); int pim_if_add_vif(struct interface *ifp, bool ispimreg, bool is_vxlan_term); int pim_if_del_vif(struct interface *ifp); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 3163f7f548..a17e8e89b2 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -1567,10 +1567,3 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, if (send_upstream_starg) pim_jp_agg_single_upstream_send(&starup->rpf, starup, true); } - -unsigned int pim_ifchannel_hash_key(const void *arg) -{ - const struct pim_ifchannel *ch = arg; - - return jhash_2words(ch->sg.src.s_addr, ch->sg.grp.s_addr, 0); -} diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index 52f02a660b..332d40d926 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -160,6 +160,5 @@ void pim_ifchannel_set_star_g_join_state(struct pim_ifchannel *ch, int eom, int pim_ifchannel_compare(const struct pim_ifchannel *ch1, const struct pim_ifchannel *ch2); -unsigned int pim_ifchannel_hash_key(const void *arg); void delete_on_noinfo(struct pim_ifchannel *ch); #endif /* PIM_IFCHANNEL_H */ diff --git a/pimd/pim_igmp.c b/pimd/pim_igmp.c index 68b3af72a7..af43380b91 100644 --- a/pimd/pim_igmp.c +++ b/pimd/pim_igmp.c @@ -141,18 +141,6 @@ 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; @@ -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->query_max_response_time_dsec); if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[INET_ADDRSTRLEN]; @@ -363,11 +351,10 @@ static int igmp_recv_query(struct igmp_sock *igmp, int query_version, * For now we will simplify things and inform the user that they need to * configure all PIM routers to use the same version of IGMP. */ - if (query_version != pim_ifp->igmp_version) { + if (query_version != pim_ifp->version) { zlog_warn( "Recv IGMP query v%d from %s on %s but we are using v%d, please configure all PIM routers on this subnet to use the same IGMP version", - query_version, from_str, ifp->name, - pim_ifp->igmp_version); + query_version, from_str, ifp->name, pim_ifp->version); return 0; } @@ -648,14 +635,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->default_query_interval >> 2; */ if (igmp->startup_query_count == igmp->querier_robustness_variable) query_interval = 1; else - query_interval = PIM_IGMP_SQI( - pim_ifp->igmp_default_query_interval); + query_interval = + PIM_IGMP_SQI(pim_ifp->default_query_interval); --igmp->startup_query_count; } else { @@ -708,7 +695,7 @@ static int pim_igmp_general_query(struct thread *t) pim_ifp = igmp->interface->info; - if (pim_ifp->igmp_version == 3) { + if (pim_ifp->version == 3) { query_buf_size = PIM_IGMP_BUFSIZE_WRITE; } else { query_buf_size = IGMP_V12_MSG_SIZE; @@ -738,10 +725,10 @@ static int pim_igmp_general_query(struct thread *t) querier_str, dst_str, igmp->interface->name); } - igmp_send_query(pim_ifp->igmp_version, 0 /* igmp_group */, igmp->fd, + igmp_send_query(pim_ifp->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->query_max_response_time_dsec, 1 /* s_flag: always set for general queries */, igmp->querier_robustness_variable, igmp->querier_query_interval); @@ -799,7 +786,7 @@ 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->default_query_interval; } static void igmp_group_free(struct igmp_group *group) @@ -856,8 +843,8 @@ 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->group_list, group); + hash_release(pim_ifp->group_hash, group); igmp_group_free(group); } @@ -887,11 +874,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->socket_list, igmp); igmp_sock_free(igmp); - if (!listcount(pim_ifp->igmp_socket_list)) + if (!listcount(pim_ifp->socket_list)) pim_igmp_if_reset(pim_ifp); } @@ -903,8 +890,8 @@ void igmp_sock_delete_all(struct interface *ifp) pim_ifp = ifp->info; - for (ALL_LIST_ELEMENTS(pim_ifp->igmp_socket_list, igmp_node, - igmp_nextnode, igmp)) { + for (ALL_LIST_ELEMENTS(pim_ifp->socket_list, igmp_node, igmp_nextnode, + igmp)) { igmp_sock_delete(igmp); } } @@ -931,15 +918,15 @@ 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->socket_list = list_new(); + pim_ifp->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->group_list = list_new(); + pim_ifp->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->group_hash = hash_create(igmp_group_hash_key, + igmp_group_hash_equal, hash_name); } void pim_igmp_if_reset(struct pim_interface *pim_ifp) @@ -947,7 +934,7 @@ void pim_igmp_if_reset(struct pim_interface *pim_ifp) struct listnode *grp_node, *grp_nextnode; struct igmp_group *grp; - for (ALL_LIST_ELEMENTS(pim_ifp->igmp_group_list, grp_node, grp_nextnode, + for (ALL_LIST_ELEMENTS(pim_ifp->group_list, grp_node, grp_nextnode, grp)) { igmp_group_delete(grp); } @@ -957,13 +944,13 @@ 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->group_list); + assert(!listcount(pim_ifp->group_list)); - list_delete(&pim_ifp->igmp_group_list); - hash_free(pim_ifp->igmp_group_hash); + list_delete(&pim_ifp->group_list); + hash_free(pim_ifp->group_hash); - list_delete(&pim_ifp->igmp_socket_list); + list_delete(&pim_ifp->socket_list); } static struct igmp_sock *igmp_sock_new(int fd, struct in_addr ifaddr, @@ -990,7 +977,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->default_robustness_variable; igmp->sock_creation = pim_time_monotonic_sec(); igmp_stats_init(&igmp->rx_stats); @@ -1005,7 +992,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->default_query_interval; */ igmp_startup_mode_on(igmp); pim_igmp_general_query_on(igmp); @@ -1201,7 +1188,7 @@ struct igmp_group *find_group_by_addr(struct igmp_sock *igmp, lookup.group_addr.s_addr = group_addr.s_addr; - return hash_lookup(pim_ifp->igmp_group_hash, &lookup); + return hash_lookup(pim_ifp->group_hash, &lookup); } struct igmp_group *igmp_add_group_by_addr(struct igmp_sock *igmp, @@ -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->group_list, group); + group = hash_get(pim_ifp->group_hash, group, hash_alloc_intern); if (PIM_DEBUG_IGMP_TRACE) { char group_str[INET_ADDRSTRLEN]; @@ -1333,7 +1320,7 @@ void igmp_send_query_on_intf(struct interface *ifp, int igmp_ver) 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->socket_list, sock_node, igmp)) { char query_buf[query_buf_size]; @@ -1341,7 +1328,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->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..1d514086f6 100644 --- a/pimd/pim_igmp.h +++ b/pimd/pim_igmp.h @@ -110,7 +110,6 @@ 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, diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c index 13db11fa80..ea4bcb298b 100644 --- a/pimd/pim_igmpv3.c +++ b/pimd/pim_igmpv3.c @@ -65,12 +65,12 @@ static inline long igmp_gmi_msec(struct igmp_group *group) 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->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->query_max_response_time_dsec); } void igmp_group_reset_gmi(struct igmp_group *group) @@ -985,14 +985,13 @@ static void igmp_send_query_group(struct igmp_group *group, char *query_buf, struct igmp_sock *igmp; struct listnode *sock_node; - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_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, - s_flag, igmp->querier_robustness_variable, - igmp->querier_query_interval); + for (ALL_LIST_ELEMENTS_RO(pim_ifp->socket_list, sock_node, igmp)) { + igmp_send_query(pim_ifp->version, group, igmp->fd, ifp->name, + query_buf, query_buf_size, num_sources, + group->group_addr, group->group_addr, + pim_ifp->specific_query_max_response_time_dsec, + s_flag, igmp->querier_robustness_variable, + igmp->querier_query_interval); } } @@ -1014,7 +1013,7 @@ static void group_retransmit_group(struct igmp_group *group) pim_ifp = group->interface->info; - if (pim_ifp->igmp_version == 3) { + if (pim_ifp->version == 3) { query_buf_size = PIM_IGMP_BUFSIZE_WRITE; } else { query_buf_size = IGMP_V12_MSG_SIZE; @@ -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->last_member_query_count; + lmqi_msec = 100 * pim_ifp->specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* @@ -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->last_member_query_count; + lmqi_msec = 100 * pim_ifp->specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* Scan all group sources */ @@ -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->specific_query_max_response_time_dsec; if (PIM_DEBUG_IGMP_TRACE) { char group_str[INET_ADDRSTRLEN]; @@ -1320,7 +1319,7 @@ static void group_query_send(struct igmp_group *group) long lmqc; /* Last Member Query Count */ pim_ifp = group->interface->info; - lmqc = pim_ifp->igmp_last_member_query_count; + lmqc = pim_ifp->last_member_query_count; /* lower group timer to lmqt */ igmp_group_timer_lower_to_lmqt(group); @@ -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->last_member_query_count; + lmqi_msec = 100 * pim_ifp->specific_query_max_response_time_dsec; lmqt_msec = lmqc * lmqi_msec; /* @@ -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->specific_query_max_response_time_dsec; + lmqc = pim_ifp->last_member_query_count; lmqt_msec = PIM_IGMP_LMQT_MSEC( lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ @@ -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->specific_query_max_response_time_dsec; + lmqc = pim_ifp->last_member_query_count; lmqt_msec = PIM_IGMP_LMQT_MSEC( lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */ @@ -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->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->default_query_interval; if (PIM_DEBUG_IGMP_TRACE) { char ifaddr_str[INET_ADDRSTRLEN]; diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 7743bcc510..aa1df44f54 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -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->socket_list, + ifaddr); if (PIM_DEBUG_IGMP_PACKETS) { zlog_debug( diff --git a/pimd/pim_nb_config.c b/pimd/pim_nb_config.c index b9da8ec068..2399cf5c30 100644 --- a/pimd/pim_nb_config.c +++ b/pimd/pim_nb_config.c @@ -86,7 +86,7 @@ static void pim_if_membership_refresh(struct interface *ifp) */ /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, grp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->group_list, grpnode, grp)) { struct listnode *srcnode; struct igmp_source *src; @@ -105,7 +105,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 @@ -371,14 +371,6 @@ static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) 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); @@ -391,14 +383,14 @@ static void igmp_sock_query_interval_reconfig(struct igmp_sock *igmp) pim_inet4_dump("<ifaddr?>", igmp->ifaddr, 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->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->default_query_interval; */ igmp_startup_mode_on(igmp); } @@ -438,9 +430,9 @@ static void change_query_interval(struct pim_interface *pim_ifp, struct listnode *sock_node; struct igmp_sock *igmp; - pim_ifp->igmp_default_query_interval = query_interval; + pim_ifp->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->socket_list, sock_node, igmp)) { igmp_sock_query_interval_reconfig(igmp); igmp_sock_query_reschedule(igmp); } @@ -454,12 +446,11 @@ static void change_query_max_response_time(struct pim_interface *pim_ifp, struct listnode *grp_node; struct igmp_group *grp; - if (pim_ifp->igmp_query_max_response_time_dsec + if (pim_ifp->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->query_max_response_time_dsec = query_max_response_time_dsec; /* * Below we modify socket/group/source timers in order to quickly @@ -468,13 +459,13 @@ 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->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->group_list, grp_node, grp)) { struct listnode *src_node; struct igmp_source *src; @@ -2596,8 +2587,8 @@ int lib_interface_igmp_version_modify(struct nb_cb_modify_args *args) return NB_ERR_INCONSISTENCY; igmp_version = yang_dnode_get_uint8(args->dnode, NULL); - old_version = pim_ifp->igmp_version; - pim_ifp->igmp_version = igmp_version; + old_version = pim_ifp->version; + pim_ifp->version = igmp_version; /* Current and new version is different refresh existing * membership. Going from 3 -> 2 or 2 -> 3. @@ -2624,7 +2615,7 @@ int lib_interface_igmp_version_destroy(struct nb_cb_destroy_args *args) case NB_EV_APPLY: ifp = nb_running_get_entry(args->dnode, NULL, true); pim_ifp = ifp->info; - pim_ifp->igmp_version = IGMP_DEFAULT_VERSION; + pim_ifp->version = IGMP_DEFAULT_VERSION; break; } @@ -2698,7 +2689,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->specific_query_max_response_time_dsec = last_member_query_interval; break; @@ -2727,7 +2718,7 @@ int lib_interface_igmp_robustness_variable_modify( 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; + pim_ifp->last_member_query_count = last_member_query_count; break; } 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_pim.c b/pimd/pim_pim.c index 30dc6b3e92..351b906d24 100644 --- a/pimd/pim_pim.c +++ b/pimd/pim_pim.c @@ -454,6 +454,21 @@ void pim_ifstat_reset(struct interface *ifp) pim_ifp->pim_ifstat_hello_sendfail = 0; pim_ifp->pim_ifstat_hello_recv = 0; pim_ifp->pim_ifstat_hello_recvfail = 0; + pim_ifp->pim_ifstat_bsm_rx = 0; + pim_ifp->pim_ifstat_bsm_tx = 0; + pim_ifp->pim_ifstat_join_recv = 0; + pim_ifp->pim_ifstat_join_send = 0; + pim_ifp->pim_ifstat_prune_recv = 0; + pim_ifp->pim_ifstat_prune_send = 0; + pim_ifp->pim_ifstat_reg_recv = 0; + pim_ifp->pim_ifstat_reg_send = 0; + pim_ifp->pim_ifstat_reg_stop_recv = 0; + pim_ifp->pim_ifstat_reg_stop_send = 0; + pim_ifp->pim_ifstat_assert_recv = 0; + pim_ifp->pim_ifstat_assert_send = 0; + pim_ifp->pim_ifstat_bsm_cfg_miss = 0; + pim_ifp->pim_ifstat_ucast_bsm_cfg_miss = 0; + pim_ifp->pim_ifstat_bsm_invalid_sz = 0; } void pim_sock_reset(struct interface *ifp) @@ -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_rp.c b/pimd/pim_rp.c index 4865b0ed46..516ec2b2ee 100644 --- a/pimd/pim_rp.c +++ b/pimd/pim_rp.c @@ -1273,10 +1273,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 +1320,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_upstream.c b/pimd/pim_upstream.c index e59dbba9de..05da3cb7c2 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -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) diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index e4dec9ee8e..7ee1ff6abe 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -358,56 +358,55 @@ int pim_interface_config_write(struct vty *vty) } /* ip igmp version */ - if (pim_ifp->igmp_version - != IGMP_DEFAULT_VERSION) { + if (pim_ifp->version != IGMP_DEFAULT_VERSION) { vty_out(vty, " ip igmp version %d\n", - pim_ifp->igmp_version); + pim_ifp->version); ++writes; } /* IF ip igmp query-max-response-time */ - if (pim_ifp->igmp_query_max_response_time_dsec + if (pim_ifp->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->query_max_response_time_dsec); ++writes; } /* IF ip igmp query-interval */ - if (pim_ifp->igmp_default_query_interval + if (pim_ifp->default_query_interval != IGMP_GENERAL_QUERY_INTERVAL) { vty_out(vty, " ip igmp query-interval %d\n", - pim_ifp->igmp_default_query_interval); + pim_ifp->default_query_interval); ++writes; } /* IF ip igmp last-member_query-count */ - if (pim_ifp->igmp_last_member_query_count + if (pim_ifp->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->last_member_query_count); ++writes; } /* IF ip igmp last-member_query-interval */ - if (pim_ifp->igmp_specific_query_max_response_time_dsec + if (pim_ifp->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->specific_query_max_response_time_dsec); + ++writes; } /* IF ip igmp join */ - if (pim_ifp->igmp_join_list) { + if (pim_ifp->join_list) { struct listnode *node; struct igmp_join *ij; for (ALL_LIST_ELEMENTS_RO( - pim_ifp->igmp_join_list, - node, ij)) { + pim_ifp->join_list, node, + ij)) { char group_str[INET_ADDRSTRLEN]; char source_str [INET_ADDRSTRLEN]; diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index 4c8a96a84e..edd41bc44d 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 */ diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 3a08c6aee5..69157b3b40 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -554,8 +554,7 @@ void igmp_source_forward_reevaluate_all(struct pim_instance *pim) continue; /* scan igmp groups */ - for (ALL_LIST_ELEMENTS_RO(pim_ifp->igmp_group_list, grpnode, - grp)) { + for (ALL_LIST_ELEMENTS_RO(pim_ifp->group_list, grpnode, grp)) { struct listnode *srcnode; struct igmp_source *src; 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_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/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/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_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_l3vpn_to_bgp_vrf/scripts/check_routes.py b/tests/topotests/bgp_l3vpn_to_bgp_vrf/scripts/check_routes.py index c1a9499cbe..25951281a7 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 @@ -294,16 +294,16 @@ luCommand( "1 available, best", "wait", "Ensure 99.0.0.4 shows up", - 10 - ) + 10, +) luCommand( "r1", 'vtysh -c "show bgp vrf r1-cust1 ipv4 uni 5.1.0.0/24"', "2 available, best", "wait", "Ensure 5.1.0.0 shows up", - 10 - ) + 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 +316,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"}, @@ -338,16 +338,16 @@ luCommand( "1 available, best", "wait", "Ensure 99.0.0.4 shows up", - 10 - ) + 10, +) luCommand( "r3", 'vtysh -c "show bgp vrf r3-cust1 ipv4 uni 5.1.0.0/24"', "2 available, best", "wait", "Ensure 5.1.0.0 shows up", - 10 - ) + 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 +360,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}, @@ -382,24 +382,24 @@ luCommand( "1 available, best", "wait", "Ensure 99.0.0.4 shows up", - 10 - ) + 10, +) luCommand( "r4", 'vtysh -c "show bgp vrf r4-cust1 ipv4 uni 5.1.0.0/24"', "2 available, best", "wait", "Ensure 5.1.0.0 shows up", - 10 - ) + 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 - ) + 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 +409,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 +436,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 +632,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 +641,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 +661,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 +670,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_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_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..3253fe6900 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 @@ -4428,6 +4439,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..dd2f787014 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 @@ -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_sm_topo3/test_multicast_pim_sm_topo4.py b/tests/topotests/multicast_pim_sm_topo3/test_multicast_pim_sm_topo4.py index 5e29a1f1fd..2a8e29b1d4 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 @@ -954,11 +954,13 @@ def test_PIM_hello_tx_rx_p1(request): tc_name, result ) - step("verify stats not increamented on c1") + step("verify stats incremented 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 = { @@ -991,7 +993,7 @@ def test_PIM_hello_tx_rx_p1(request): tc_name, result ) - step("verify stats not increamented on l1") + step("verify stats not incremented on l1") result = verify_state_incremented(l1_state_before, l1_state_after) assert ( result is not True @@ -1041,10 +1043,10 @@ def test_PIM_hello_tx_rx_p1(request): tc_name, result ) - step("verify stats not increamented on c1") + step("verify stats incremented on c1") result = verify_state_incremented(c1_state_before, c1_state_after) assert ( - result is not True + result is True ), "Testcase{} : Failed Error: {}" "stats incremented".format(tc_name, result) write_test_footer(tc_name) diff --git a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py index b80da41bec..fd17180051 100644 --- a/tests/topotests/ospf_basic_functionality/test_ospf_lan.py +++ b/tests/topotests/ospf_basic_functionality/test_ospf_lan.py @@ -408,7 +408,7 @@ 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) 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/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/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..7868c3d41d 100755 --- a/tools/frr-reload.py +++ b/tools/frr-reload.py @@ -762,12 +762,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 +944,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: 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-interface.yang b/yang/frr-interface.yang index 46c03a1d1f..4a152aadda 100644 --- a/yang/frr-interface.yang +++ b/yang/frr-interface.yang @@ -288,13 +288,11 @@ module frr-interface { container lib { list interface { - key "name vrf"; + key "name"; description "Interface."; leaf name { - type string { - length "1..16"; - } + type string; description "Interface name."; } @@ -303,6 +301,7 @@ module frr-interface { type frr-vrf:vrf-ref; description "VRF this interface is associated with."; + config false; } leaf description { diff --git a/yang/frr-route-map.yang b/yang/frr-route-map.yang index 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..828ebd9086 100644 --- a/yang/subdir.am +++ b/yang/subdir.am @@ -88,6 +88,10 @@ dist_yangmodels_DATA += yang/frr-bgp-types.yang dist_yangmodels_DATA += yang/frr-bgp.yang endif +if OSPFD +dist_yangmodels_DATA += yang/frr-ospfd.yang +endif + if PATHD dist_yangmodels_DATA += yang/frr-pathd.yang endif @@ -97,3 +101,29 @@ CLEANFILES += \ yang/ietf/*.c \ yang/confd/*.c \ # + +if CONFD + +SUBMODULES = $(shell cd $(top_srcdir); grep -l belongs-to $(dist_yangmodels_DATA)) +EXCLUDED_MODULES = $(SUBMODULES) yang/frr-module-translator.yang +YANG_MODULES = $(filter-out $(EXCLUDED_MODULES),$(dist_yangmodels_DATA)) + +fxsdir = $(sysconfdir)/confd +fxs_DATA = $(YANG_MODULES:.yang=.fxs) + +SUFFIXES += .fxs +CLEANFILES += $(fxs_DATA) + +AM_V_CONFDC = $(AM_V_CONFDC_@AM_V@) +AM_V_CONFDC_ = $(AM_V_CONFDC_@AM_DEFAULT_V@) +AM_V_CONFDC_0 = @echo " CONFDC " $@; + +CONFDC_FLAGS = --yangpath $(srcdir)/yang --yangpath $(srcdir)/yang/ietf + +yang/%.fxs: yang/%.yang yang/confd/confd.%.yang + $(AM_V_CONFDC)$(CONFDC) $(CONFDC_FLAGS) -c -o $@ -a $(srcdir)/yang/confd/confd.$*.yang -- $< + +yang/%.fxs: yang/%.yang + $(AM_V_CONFDC)$(CONFDC) $(CONFDC_FLAGS) -c -o $@ -- $< + +endif diff --git a/zebra/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..2a8dc39771 100644 --- a/zebra/main.c +++ b/zebra/main.c @@ -443,8 +443,8 @@ int main(int argc, char **argv) * we have to have route_read() called before. */ zrouter.startup_time = monotime(NULL); - thread_add_timer(zrouter.master, rib_sweep_route, - NULL, graceful_restart, NULL); + thread_add_timer(zrouter.master, rib_sweep_route, NULL, + graceful_restart, &zrouter.sweeper); /* Needed for BSD routing socket. */ pid = getpid(); diff --git a/zebra/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_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_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_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..fe4641cd94 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"); diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index a3faa3d3e2..9c57381165 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -1127,11 +1127,7 @@ static void vty_show_ip_route_detail_json(struct vty *vty, 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, @@ -1241,14 +1237,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, @@ -2480,10 +2470,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", @@ -2631,10 +2618,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", @@ -3006,9 +2990,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..5ef7c9acea 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); } /* |
