diff options
144 files changed, 4810 insertions, 1545 deletions
diff --git a/bgpd/bgp_aspath.c b/bgpd/bgp_aspath.c index a781e70d2f..5766236a00 100644 --- a/bgpd/bgp_aspath.c +++ b/bgpd/bgp_aspath.c @@ -793,7 +793,7 @@ static int assegments_parse(struct stream *s, size_t length, if (head) prev->next = seg; else /* it's the first segment */ - head = prev = seg; + head = seg; for (i = 0; i < segh.length; i++) seg->as[i] = diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c index 80ef43f0d3..1f650aaeb7 100644 --- a/bgpd/bgp_bfd.c +++ b/bgpd/bgp_bfd.c @@ -329,19 +329,22 @@ static int bgp_bfd_dest_update(ZAPI_CALLBACK_ARGS) &remote_cbit, vrf_id); if (BGP_DEBUG(zebra, ZEBRA)) { + struct vrf *vrf; char buf[2][PREFIX2STR_BUFFER]; + + vrf = vrf_lookup_by_id(vrf_id); prefix2str(&dp, buf[0], sizeof(buf[0])); if (ifp) { zlog_debug( - "Zebra: vrf %u interface %s bfd destination %s %s %s", - vrf_id, ifp->name, buf[0], - bfd_get_status_str(status), + "Zebra: vrf %s(%u) interface %s bfd destination %s %s %s", + VRF_LOGNAME(vrf), vrf_id, ifp->name, + buf[0], bfd_get_status_str(status), remote_cbit ? "(cbit on)" : ""); } else { prefix2str(&sp, buf[1], sizeof(buf[1])); zlog_debug( - "Zebra: vrf %u source %s bfd destination %s %s %s", - vrf_id, buf[1], buf[0], + "Zebra: vrf %s(%u) source %s bfd destination %s %s %s", + VRF_LOGNAME(vrf), vrf_id, buf[1], buf[0], bfd_get_status_str(status), remote_cbit ? "(cbit on)" : ""); } diff --git a/bgpd/bgp_clist.c b/bgpd/bgp_clist.c index 7ca48a5bea..18369002b8 100644 --- a/bgpd/bgp_clist.c +++ b/bgpd/bgp_clist.c @@ -44,7 +44,7 @@ static int64_t bgp_clist_new_seq_get(struct community_list *list) int64_t newseq; struct community_entry *entry; - maxseq = newseq = 0; + maxseq = 0; for (entry = list->head; entry; entry = entry->next) { if (maxseq < entry->seq) diff --git a/bgpd/bgp_errors.c b/bgpd/bgp_errors.c index d9aba87e35..8a33ce6789 100644 --- a/bgpd/bgp_errors.c +++ b/bgpd/bgp_errors.c @@ -457,6 +457,12 @@ static struct log_ref ferr_bgp_err[] = { .suggestion = "Gather data and open a Issue so that this developmental escape can be fixed, the peer should have been reset", }, { + .code = EC_BGP_ROUTER_ID_SAME, + .title = "BGP has detected a duplicate router id during collision resolution", + .description = "As part of normal collision detection for opening a connection to a peer, BGP has detected that the remote peer's router-id is the same as ours", + .suggestion = "Change one of the two router-id's", + }, + { .code = END_FERR, } }; diff --git a/bgpd/bgp_errors.h b/bgpd/bgp_errors.h index 35c5cc3998..49c58ae6b0 100644 --- a/bgpd/bgp_errors.h +++ b/bgpd/bgp_errors.h @@ -98,6 +98,7 @@ enum bgp_log_refs { EC_BGP_CAPABILITY_UNKNOWN, EC_BGP_INVALID_NEXTHOP_LENGTH, EC_BGP_DOPPELGANGER_CONFIG, + EC_BGP_ROUTER_ID_SAME, }; extern void bgp_error_init(void); diff --git a/bgpd/bgp_evpn_vty.c b/bgpd/bgp_evpn_vty.c index c5f7927c4d..7ed37319b1 100644 --- a/bgpd/bgp_evpn_vty.c +++ b/bgpd/bgp_evpn_vty.c @@ -373,14 +373,14 @@ static void display_l3vni(struct vty *vty, struct bgp *bgp_vrf, json_export_rtl = json_object_new_array(); json_object_int_add(json, "vni", bgp_vrf->l3vni); json_object_string_add(json, "type", "L3"); - json_object_string_add(json, "kernelFlag", "Yes"); + json_object_string_add(json, "inKernel", "True"); json_object_string_add( json, "rd", prefix_rd2str(&bgp_vrf->vrf_prd, buf1, RD_ADDRSTRLEN)); json_object_string_add(json, "originatorIp", inet_ntoa(bgp_vrf->originator_ip)); json_object_string_add(json, "advertiseGatewayMacip", "n/a"); - json_object_string_add(json, "advertiseSviMacip", "n/a"); + json_object_string_add(json, "advertiseSviMacIp", "n/a"); json_object_to_json_string_ext(json, JSON_C_TO_STRING_NOSLASHESCAPE); json_object_string_add(json, "advertisePip", @@ -519,8 +519,8 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) json_export_rtl = json_object_new_array(); json_object_int_add(json, "vni", vpn->vni); json_object_string_add(json, "type", "L2"); - json_object_string_add(json, "kernelFlag", - is_vni_live(vpn) ? "Yes" : "No"); + json_object_string_add(json, "inKernel", + is_vni_live(vpn) ? "True" : "False"); json_object_string_add( json, "rd", prefix_rd2str(&vpn->prd, buf1, sizeof(buf1))); @@ -544,13 +544,13 @@ static void display_vni(struct vty *vty, struct bgpevpn *vpn, json_object *json) "Disabled"); if (!vpn->advertise_svi_macip && bgp_evpn && bgp_evpn->evpn_info->advertise_svi_macip) - json_object_string_add(json, "advertiseSviMacip", + json_object_string_add(json, "advertiseSviMacIp", "Active"); else if (vpn->advertise_svi_macip) - json_object_string_add(json, "advertiseSviMacip", + json_object_string_add(json, "advertiseSviMacIp", "Enabled"); else - json_object_string_add(json, "advertiseSviMacip", + json_object_string_add(json, "advertiseSviMacIp", "Disabled"); } else { vty_out(vty, "VNI: %d", vpn->vni); @@ -887,6 +887,22 @@ static void show_l3vni_entry(struct vty *vty, struct bgp *bgp, json_object_string_add( json_vni, "rd", prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN)); + json_object_string_add(json_vni, "advertiseGatewayMacip", + "n/a"); + json_object_string_add(json_vni, "advertiseSviMacIp", "n/a"); + json_object_to_json_string_ext(json_vni, + JSON_C_TO_STRING_NOSLASHESCAPE); + json_object_string_add( + json_vni, "advertisePip", + bgp->evpn_info->advertise_pip ? "Enabled" : "Disabled"); + json_object_string_add(json_vni, "sysIP", + inet_ntoa(bgp->evpn_info->pip_ip)); + json_object_string_add(json_vni, "sysMAC", + prefix_mac2str(&bgp->evpn_info->pip_rmac, + buf2, sizeof(buf2))); + json_object_string_add( + json_vni, "rmac", + prefix_mac2str(&bgp->rmac, buf2, sizeof(buf2))); } else { vty_out(vty, "%-1s %-10u %-4s %-21s", buf1, bgp->l3vni, "L3", prefix_rd2str(&bgp->vrf_prd, buf2, RD_ADDRSTRLEN)); @@ -1011,10 +1027,13 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[]) char *ecom_str; struct listnode *node, *nnode; struct ecommunity *ecom; + struct bgp *bgp_evpn; vty = args[0]; json = args[1]; + bgp_evpn = bgp_get_evpn(); + if (json) { json_vni = json_object_new_object(); json_import_rtl = json_object_new_array(); @@ -1030,13 +1049,37 @@ static void show_vni_entry(struct hash_bucket *bucket, void *args[]) json_object_string_add(json_vni, "type", "L2"); json_object_string_add(json_vni, "inKernel", is_vni_live(vpn) ? "True" : "False"); - json_object_string_add(json_vni, "originatorIp", - inet_ntoa(vpn->originator_ip)); - json_object_string_add(json_vni, "originatorIp", - inet_ntoa(vpn->originator_ip)); json_object_string_add( json_vni, "rd", prefix_rd2str(&vpn->prd, buf2, sizeof(buf2))); + json_object_string_add(json_vni, "originatorIp", + inet_ntoa(vpn->originator_ip)); + json_object_string_add(json_vni, "mcastGroup", + inet_ntoa(vpn->mcast_grp)); + /* per vni knob is enabled -- Enabled + * Global knob is enabled -- Active + * default -- Disabled + */ + if (!vpn->advertise_gw_macip && bgp_evpn + && bgp_evpn->advertise_gw_macip) + json_object_string_add( + json_vni, "advertiseGatewayMacip", "Active"); + else if (vpn->advertise_gw_macip) + json_object_string_add( + json_vni, "advertiseGatewayMacip", "Enabled"); + else + json_object_string_add( + json_vni, "advertiseGatewayMacip", "Disabled"); + if (!vpn->advertise_svi_macip && bgp_evpn + && bgp_evpn->evpn_info->advertise_svi_macip) + json_object_string_add(json_vni, "advertiseSviMacIp", + "Active"); + else if (vpn->advertise_svi_macip) + json_object_string_add(json_vni, "advertiseSviMacIp", + "Enabled"); + else + json_object_string_add(json_vni, "advertiseSviMacIp", + "Disabled"); } else { vty_out(vty, "%-1s %-10u %-4s %-21s", buf1, vpn->vni, "L2", prefix_rd2str(&vpn->prd, buf2, RD_ADDRSTRLEN)); @@ -3901,7 +3944,7 @@ DEFUN(show_bgp_l2vpn_evpn_vni, bgp_evpn->advertise_gw_macip ? "Enabled" : "Disabled"); - json_object_string_add(json, "advertiseSviMacip", + json_object_string_add(json, "advertiseSviMacIp", bgp_evpn->evpn_info->advertise_svi_macip ? "Enabled" : "Disabled"); json_object_string_add(json, "advertiseAllVnis", diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c index e0a9e3e4f0..b483d39bba 100644 --- a/bgpd/bgp_fsm.c +++ b/bgpd/bgp_fsm.c @@ -578,7 +578,8 @@ const char *const peer_down_str[] = {"", "Waiting for VRF to be initialized", "No AFI/SAFI activated for peer", "AS Set config change", - "Waiting for peer OPEN"}; + "Waiting for peer OPEN", + "Reached received prefix count"}; static int bgp_graceful_restart_timer_expire(struct thread *thread) { @@ -1512,6 +1513,10 @@ int bgp_start(struct peer *peer) "%s [FSM] Trying to start suppressed peer" " - this is never supposed to happen!", peer->host); + if (CHECK_FLAG(peer->flags, PEER_FLAG_SHUTDOWN)) + peer->last_reset = PEER_DOWN_USER_SHUTDOWN; + else if (CHECK_FLAG(peer->sflags, PEER_STATUS_PREFIX_OVERFLOW)) + peer->last_reset = PEER_DOWN_PFX_COUNT; return -1; } diff --git a/bgpd/bgp_network.c b/bgpd/bgp_network.c index 8b585704d8..8759a88444 100644 --- a/bgpd/bgp_network.c +++ b/bgpd/bgp_network.c @@ -203,7 +203,7 @@ int bgp_set_socket_ttl(struct peer *peer, int bgp_sock) int ret = 0; /* In case of peer is EBGP, we should set TTL for this connection. */ - if (!peer->gtsm_hops && (peer_sort(peer) == BGP_PEER_EBGP)) { + if (!peer->gtsm_hops && (peer_sort_lookup(peer) == BGP_PEER_EBGP)) { ret = sockopt_ttl(peer->su.sa.sa_family, bgp_sock, peer->ttl); if (ret) { flog_err( diff --git a/bgpd/bgp_nexthop.c b/bgpd/bgp_nexthop.c index 7116c80941..ab0c3a3f11 100644 --- a/bgpd/bgp_nexthop.c +++ b/bgpd/bgp_nexthop.c @@ -180,7 +180,7 @@ void bgp_tip_del(struct bgp *bgp, struct in_addr *tip) /* BGP own address structure */ struct bgp_addr { - struct prefix *p; + struct prefix p; struct list *ifp_name_list; }; @@ -192,17 +192,10 @@ static void show_address_entry(struct hash_bucket *bucket, void *args) struct listnode *node; char str[INET6_ADDRSTRLEN] = {0}; - if (addr->p->family == AF_INET) { - vty_out(vty, "addr: %s, count: %d : ", inet_ntop(AF_INET, - &(addr->p->u.prefix4), - str, INET_ADDRSTRLEN), - addr->ifp_name_list->count); - } else if (addr->p->family == AF_INET6) { - vty_out(vty, "addr: %s, count: %d : ", inet_ntop(AF_INET6, - &(addr->p->u.prefix6), - str, INET6_ADDRSTRLEN), - addr->ifp_name_list->count); - } + vty_out(vty, "addr: %s, count: %d : ", + inet_ntop(addr->p.family, &(addr->p.u.prefix), + str, INET6_ADDRSTRLEN), + addr->ifp_name_list->count); for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) { vty_out(vty, " %s,", name); @@ -231,8 +224,7 @@ static void *bgp_address_hash_alloc(void *p) struct bgp_addr *addr = NULL; addr = XMALLOC(MTYPE_BGP_ADDR, sizeof(struct bgp_addr)); - addr->p = prefix_new(); - prefix_copy(addr->p, copy_addr->p); + prefix_copy(&addr->p, ©_addr->p); addr->ifp_name_list = list_new(); addr->ifp_name_list->del = bgp_address_hash_string_del; @@ -244,7 +236,6 @@ static void bgp_address_hash_free(void *data) { struct bgp_addr *addr = data; - prefix_free(&addr->p); list_delete(&addr->ifp_name_list); XFREE(MTYPE_BGP_ADDR, addr); } @@ -253,7 +244,7 @@ static unsigned int bgp_address_hash_key_make(const void *p) { const struct bgp_addr *addr = p; - return prefix_hash_key((const void *)(addr->p)); + return prefix_hash_key(&addr->p); } static bool bgp_address_hash_cmp(const void *p1, const void *p2) @@ -261,7 +252,7 @@ static bool bgp_address_hash_cmp(const void *p1, const void *p2) const struct bgp_addr *addr1 = p1; const struct bgp_addr *addr2 = p2; - return prefix_same(addr1->p, addr2->p); + return prefix_same(&addr1->p, &addr2->p); } void bgp_address_init(struct bgp *bgp) @@ -288,12 +279,12 @@ static void bgp_address_add(struct bgp *bgp, struct connected *ifc, struct listnode *node; char *name; - tmp.p = p; + tmp.p = *p; - if (tmp.p->family == AF_INET) - tmp.p->prefixlen = IPV4_MAX_BITLEN; - else if (tmp.p->family == AF_INET6) - tmp.p->prefixlen = IPV6_MAX_BITLEN; + if (tmp.p.family == AF_INET) + tmp.p.prefixlen = IPV4_MAX_BITLEN; + else if (tmp.p.family == AF_INET6) + tmp.p.prefixlen = IPV6_MAX_BITLEN; addr = hash_get(bgp->address_hash, &tmp, bgp_address_hash_alloc); @@ -315,12 +306,12 @@ static void bgp_address_del(struct bgp *bgp, struct connected *ifc, struct listnode *node; char *name; - tmp.p = p; + tmp.p = *p; - if (tmp.p->family == AF_INET) - tmp.p->prefixlen = IPV4_MAX_BITLEN; - else if (tmp.p->family == AF_INET6) - tmp.p->prefixlen = IPV6_MAX_BITLEN; + if (tmp.p.family == AF_INET) + tmp.p.prefixlen = IPV4_MAX_BITLEN; + else if (tmp.p.family == AF_INET6) + tmp.p.prefixlen = IPV6_MAX_BITLEN; addr = hash_lookup(bgp->address_hash, &tmp); /* may have been deleted earlier by bgp_interface_down() */ @@ -482,75 +473,67 @@ static void bgp_connected_cleanup(struct route_table *table, int bgp_nexthop_self(struct bgp *bgp, afi_t afi, uint8_t type, uint8_t sub_type, struct attr *attr, struct bgp_node *rn) { - struct prefix p = {0}; - afi_t new_afi = afi; - struct bgp_addr tmp_addr = {0}, *addr = NULL; + uint8_t new_afi = afi == AFI_IP ? AF_INET : AF_INET6; + struct bgp_addr tmp_addr = {{0}}, *addr = NULL; struct tip_addr tmp_tip, *tip = NULL; - bool is_bgp_static_route = ((type == ZEBRA_ROUTE_BGP) - && (sub_type == BGP_ROUTE_STATIC)) + bool is_bgp_static_route = + ((type == ZEBRA_ROUTE_BGP) && (sub_type == BGP_ROUTE_STATIC)) ? true : false; if (!is_bgp_static_route) - new_afi = BGP_ATTR_NEXTHOP_AFI_IP6(attr) ? AFI_IP6 : AFI_IP; + new_afi = BGP_ATTR_NEXTHOP_AFI_IP6(attr) ? AF_INET6 : AF_INET; + tmp_addr.p.family = new_afi; switch (new_afi) { - case AFI_IP: - p.family = AF_INET; + case AF_INET: if (is_bgp_static_route) { - p.u.prefix4 = rn->p.u.prefix4; - p.prefixlen = rn->p.prefixlen; + tmp_addr.p.u.prefix4 = rn->p.u.prefix4; + tmp_addr.p.prefixlen = rn->p.prefixlen; } else { /* Here we need to find out which nexthop to be used*/ - if (attr->flag & - ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { - - p.u.prefix4 = attr->nexthop; - p.prefixlen = IPV4_MAX_BITLEN; - - } else if ((attr->mp_nexthop_len) && - ((attr->mp_nexthop_len == - BGP_ATTR_NHLEN_IPV4) || - (attr->mp_nexthop_len == - BGP_ATTR_NHLEN_VPNV4))) { - p.u.prefix4 = + if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { + tmp_addr.p.u.prefix4 = attr->nexthop; + tmp_addr.p.prefixlen = IPV4_MAX_BITLEN; + } else if ((attr->mp_nexthop_len) + && ((attr->mp_nexthop_len + == BGP_ATTR_NHLEN_IPV4) + || (attr->mp_nexthop_len + == BGP_ATTR_NHLEN_VPNV4))) { + tmp_addr.p.u.prefix4 = attr->mp_nexthop_global_in; - p.prefixlen = IPV4_MAX_BITLEN; + tmp_addr.p.prefixlen = IPV4_MAX_BITLEN; } else return 0; } break; - case AFI_IP6: - p.family = AF_INET6; - + case AF_INET6: if (is_bgp_static_route) { - p.u.prefix6 = rn->p.u.prefix6; - p.prefixlen = rn->p.prefixlen; + tmp_addr.p.u.prefix6 = rn->p.u.prefix6; + tmp_addr.p.prefixlen = rn->p.prefixlen; } else { - p.u.prefix6 = attr->mp_nexthop_global; - p.prefixlen = IPV6_MAX_BITLEN; + tmp_addr.p.u.prefix6 = attr->mp_nexthop_global; + tmp_addr.p.prefixlen = IPV6_MAX_BITLEN; } break; default: break; } - tmp_addr.p = &p; addr = hash_lookup(bgp->address_hash, &tmp_addr); if (addr) return 1; - if (new_afi == AFI_IP) { + if (new_afi == AF_INET) { memset(&tmp_tip, 0, sizeof(struct tip_addr)); tmp_tip.addr = attr->nexthop; if (attr->flag & ATTR_FLAG_BIT(BGP_ATTR_NEXT_HOP)) { tmp_tip.addr = attr->nexthop; } else if ((attr->mp_nexthop_len) && - ((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) - || (attr->mp_nexthop_len == - BGP_ATTR_NHLEN_VPNV4))) { + ((attr->mp_nexthop_len == BGP_ATTR_NHLEN_IPV4) + || (attr->mp_nexthop_len == BGP_ATTR_NHLEN_VPNV4))) { tmp_tip.addr = attr->mp_nexthop_global_in; } diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c index c72f7226e2..3132c8b866 100644 --- a/bgpd/bgp_packet.c +++ b/bgpd/bgp_packet.c @@ -1007,6 +1007,11 @@ static int bgp_collision_detect(struct peer *new, struct in_addr remote_id) return -1; } else { + if (ntohl(peer->local_id.s_addr) == + ntohl(remote_id.s_addr)) + flog_err(EC_BGP_ROUTER_ID_SAME, "Peer's router-id %s is the same as ours", + inet_ntoa(remote_id)); + /* 3. Otherwise, the local system closes newly created BGP connection (the one associated with the @@ -1298,8 +1303,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) /* Open option part parse. */ if (optlen != 0) { - if ((ret = bgp_open_option_parse(peer, optlen, &mp_capability)) - < 0) + if (bgp_open_option_parse(peer, optlen, &mp_capability) < 0) return BGP_Stop; } else { if (bgp_debug_neighbor_events(peer)) @@ -1341,7 +1345,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size) return BGP_Stop; /* Get sockname. */ - if ((ret = bgp_getsockname(peer)) < 0) { + if (bgp_getsockname(peer) < 0) { flog_err_sys(EC_LIB_SOCKET, "%s: bgp_getsockname() failed for peer: %s", __FUNCTION__, peer->host); @@ -1967,38 +1971,29 @@ static int bgp_route_refresh_receive(struct peer *peer, bgp_size_t size) } else p_pnt = p_end; - if ((ok = (p_pnt < p_end))) - orfp.ge = - *p_pnt++; /* value - checked in - prefix_bgp_orf_set() - */ - if ((ok = (p_pnt < p_end))) - orfp.le = - *p_pnt++; /* value - checked in - prefix_bgp_orf_set() - */ + /* val checked in prefix_bgp_orf_set */ + if (p_pnt < p_end) + orfp.ge = *p_pnt++; + + /* val checked in prefix_bgp_orf_set */ + if (p_pnt < p_end) + orfp.le = *p_pnt++; + if ((ok = (p_pnt < p_end))) orfp.p.prefixlen = *p_pnt++; - orfp.p.family = afi2family( - afi); /* afi checked already */ - - psize = PSIZE( - orfp.p.prefixlen); /* 0 if not - ok */ - if (psize - > prefix_blen( - &orfp.p)) /* valid for - family ? */ - { + + /* afi checked already */ + orfp.p.family = afi2family(afi); + + /* 0 if not ok */ + psize = PSIZE(orfp.p.prefixlen); + /* valid for family ? */ + if (psize > prefix_blen(&orfp.p)) { ok = 0; psize = prefix_blen(&orfp.p); } - if (psize - > (p_end - p_pnt)) /* valid for - packet ? */ - { + /* valid for packet ? */ + if (psize > (p_end - p_pnt)) { ok = 0; psize = p_end - p_pnt; } diff --git a/bgpd/bgp_pbr.c b/bgpd/bgp_pbr.c index eea20d7210..172ec8b42e 100644 --- a/bgpd/bgp_pbr.c +++ b/bgpd/bgp_pbr.c @@ -1403,11 +1403,16 @@ void bgp_pbr_print_policy_route(struct bgp_pbr_entry_main *api) ptr += sprintf(ptr, "@redirect ip nh %s", local_buff); break; - case ACTION_REDIRECT: + case ACTION_REDIRECT: { + struct vrf *vrf; + + vrf = vrf_lookup_by_id(api->actions[i].u.redirect_vrf); INCREMENT_DISPLAY(ptr, nb_items); - ptr += sprintf(ptr, "@redirect vrf %u", + ptr += sprintf(ptr, "@redirect vrf %s(%u)", + VRF_LOGNAME(vrf), api->actions[i].u.redirect_vrf); break; + } case ACTION_MARKING: INCREMENT_DISPLAY(ptr, nb_items); ptr += sprintf(ptr, "@set dscp %u", diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index 755024f4b6..1cd0bbe578 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -914,8 +914,8 @@ static int bgp_path_info_cmp(struct bgp *bgp, struct bgp_path_info *new, pair (newm, existm) with the cluster list length. Prefer the path with smaller cluster list length. */ if (newm == existm) { - if (peer_sort(new->peer) == BGP_PEER_IBGP - && peer_sort(exist->peer) == BGP_PEER_IBGP + if (peer_sort_lookup(new->peer) == BGP_PEER_IBGP + && peer_sort_lookup(exist->peer) == BGP_PEER_IBGP && (mpath_cfg == NULL || CHECK_FLAG( mpath_cfg->ibgp_flags, @@ -6270,6 +6270,9 @@ void bgp_aggregate_route(struct bgp *bgp, struct prefix *p, else if (aggregate->egp_origin_count > 0) origin = BGP_ORIGIN_EGP; + if (aggregate->origin != BGP_ORIGIN_UNSPECIFIED) + origin = aggregate->origin; + if (aggregate->as_set) { if (aggregate->aspath) /* Retrieve aggregate route's as-path. @@ -6434,6 +6437,9 @@ static void bgp_add_route_to_aggregate(struct bgp *bgp, struct prefix *aggr_p, else if (aggregate->egp_origin_count > 0) origin = BGP_ORIGIN_EGP; + if (aggregate->origin != BGP_ORIGIN_UNSPECIFIED) + origin = aggregate->origin; + if (aggregate->as_set) { /* Compute aggregate route's as-path. */ @@ -6565,6 +6571,9 @@ static void bgp_remove_route_from_aggregate(struct bgp *bgp, afi_t afi, else if (aggregate->egp_origin_count > 0) origin = BGP_ORIGIN_EGP; + if (aggregate->origin != BGP_ORIGIN_UNSPECIFIED) + origin = aggregate->origin; + if (aggregate->as_set) { /* Retrieve aggregate route's as-path. */ @@ -6660,6 +6669,19 @@ void bgp_aggregate_decrement(struct bgp *bgp, struct prefix *p, #define AGGREGATE_AS_SET 1 #define AGGREGATE_AS_UNSET 0 +static const char *bgp_origin2str(uint8_t origin) +{ + switch (origin) { + case BGP_ORIGIN_IGP: + return "igp"; + case BGP_ORIGIN_EGP: + return "egp"; + case BGP_ORIGIN_INCOMPLETE: + return "incomplete"; + } + return "n/a"; +} + static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, afi_t afi, safi_t safi) { @@ -6753,8 +6775,9 @@ static int bgp_aggregate_unset(struct vty *vty, const char *prefix_str, } static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, - safi_t safi, const char *rmap, uint8_t summary_only, - uint8_t as_set) + safi_t safi, const char *rmap, + uint8_t summary_only, uint8_t as_set, + uint8_t origin) { VTY_DECLVAR_CONTEXT(bgp, bgp); int ret; @@ -6818,6 +6841,12 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, aggregate->as_set = as_set_new; aggregate->safi = safi; + /* Override ORIGIN attribute if defined. + * E.g.: Cisco and Juniper set ORIGIN for aggregated address + * to IGP which is not what rfc4271 says. + * This enables the same behavior, optionally. + */ + aggregate->origin = origin; if (rmap) { XFREE(MTYPE_ROUTE_MAP_NAME, aggregate->rmap.name); @@ -6837,7 +6866,7 @@ static int bgp_aggregate_set(struct vty *vty, const char *prefix_str, afi_t afi, DEFUN (aggregate_address, aggregate_address_cmd, - "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", + "aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" @@ -6845,12 +6874,17 @@ DEFUN (aggregate_address, "Filter more specific routes from updates\n" "Generate AS set path information\n" "Apply route map to aggregate network\n" - "Name of route map\n") + "Name of route map\n" + "BGP origin code\n" + "Remote EGP\n" + "Local IGP\n" + "Unknown heritage\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D/M", &idx); char *prefix = argv[idx]->arg; char *rmap = NULL; + uint8_t origin = BGP_ORIGIN_UNSPECIFIED; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : AGGREGATE_AS_UNSET; idx = 0; @@ -6863,13 +6897,23 @@ DEFUN (aggregate_address, if (idx) rmap = argv[idx]->arg; - return bgp_aggregate_set(vty, prefix, AFI_IP, bgp_node_safi(vty), - rmap, summary_only, as_set); + idx = 0; + if (argv_find(argv, argc, "origin", &idx)) { + if (strncmp(argv[idx + 1]->arg, "igp", 2) == 0) + origin = BGP_ORIGIN_IGP; + if (strncmp(argv[idx + 1]->arg, "egp", 1) == 0) + origin = BGP_ORIGIN_EGP; + if (strncmp(argv[idx + 1]->arg, "incomplete", 2) == 0) + origin = BGP_ORIGIN_INCOMPLETE; + } + + return bgp_aggregate_set(vty, prefix, AFI_IP, bgp_node_safi(vty), rmap, + summary_only, as_set, origin); } DEFUN (aggregate_address_mask, aggregate_address_mask_cmd, - "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", + "aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]", "Configure BGP aggregate entries\n" "Aggregate address\n" "Aggregate mask\n" @@ -6878,7 +6922,11 @@ DEFUN (aggregate_address_mask, "Filter more specific routes from updates\n" "Generate AS set path information\n" "Apply route map to aggregate network\n" - "Name of route map\n") + "Name of route map\n" + "BGP origin code\n" + "Remote EGP\n" + "Local IGP\n" + "Unknown heritage\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D", &idx); @@ -6886,6 +6934,7 @@ DEFUN (aggregate_address_mask, char *mask = argv[idx + 1]->arg; bool rmap_found; char *rmap = NULL; + uint8_t origin = BGP_ORIGIN_UNSPECIFIED; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : AGGREGATE_AS_UNSET; idx = 0; @@ -6905,13 +6954,23 @@ DEFUN (aggregate_address_mask, return CMD_WARNING_CONFIG_FAILED; } + idx = 0; + if (argv_find(argv, argc, "origin", &idx)) { + if (strncmp(argv[idx + 1]->arg, "igp", 2) == 0) + origin = BGP_ORIGIN_IGP; + if (strncmp(argv[idx + 1]->arg, "egp", 1) == 0) + origin = BGP_ORIGIN_EGP; + if (strncmp(argv[idx + 1]->arg, "incomplete", 2) == 0) + origin = BGP_ORIGIN_INCOMPLETE; + } + return bgp_aggregate_set(vty, prefix_str, AFI_IP, bgp_node_safi(vty), - rmap, summary_only, as_set); + rmap, summary_only, as_set, origin); } DEFUN (no_aggregate_address, no_aggregate_address_cmd, - "no aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", + "no aggregate-address A.B.C.D/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" @@ -6920,7 +6979,11 @@ DEFUN (no_aggregate_address, "Filter more specific routes from updates\n" "Generate AS set path information\n" "Apply route map to aggregate network\n" - "Name of route map\n") + "Name of route map\n" + "BGP origin code\n" + "Remote EGP\n" + "Local IGP\n" + "Unknown heritage\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D/M", &idx); @@ -6930,7 +6993,7 @@ DEFUN (no_aggregate_address, DEFUN (no_aggregate_address_mask, no_aggregate_address_mask_cmd, - "no aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", + "no aggregate-address A.B.C.D A.B.C.D [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]", NO_STR "Configure BGP aggregate entries\n" "Aggregate address\n" @@ -6940,7 +7003,11 @@ DEFUN (no_aggregate_address_mask, "Filter more specific routes from updates\n" "Generate AS set path information\n" "Apply route map to aggregate network\n" - "Name of route map\n") + "Name of route map\n" + "BGP origin code\n" + "Remote EGP\n" + "Local IGP\n" + "Unknown heritage\n") { int idx = 0; argv_find(argv, argc, "A.B.C.D", &idx); @@ -6960,7 +7027,7 @@ DEFUN (no_aggregate_address_mask, DEFUN (ipv6_aggregate_address, ipv6_aggregate_address_cmd, - "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", + "aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]", "Configure BGP aggregate entries\n" "Aggregate prefix\n" "Generate AS set path information\n" @@ -6968,13 +7035,18 @@ DEFUN (ipv6_aggregate_address, "Filter more specific routes from updates\n" "Generate AS set path information\n" "Apply route map to aggregate network\n" - "Name of route map\n") + "Name of route map\n" + "BGP origin code\n" + "Remote EGP\n" + "Local IGP\n" + "Unknown heritage\n") { int idx = 0; argv_find(argv, argc, "X:X::X:X/M", &idx); char *prefix = argv[idx]->arg; char *rmap = NULL; bool rmap_found; + uint8_t origin = BGP_ORIGIN_UNSPECIFIED; int as_set = argv_find(argv, argc, "as-set", &idx) ? AGGREGATE_AS_SET : AGGREGATE_AS_UNSET; @@ -6987,13 +7059,23 @@ DEFUN (ipv6_aggregate_address, if (rmap_found) rmap = argv[idx]->arg; + idx = 0; + if (argv_find(argv, argc, "origin", &idx)) { + if (strncmp(argv[idx + 1]->arg, "igp", 2) == 0) + origin = BGP_ORIGIN_IGP; + if (strncmp(argv[idx + 1]->arg, "egp", 1) == 0) + origin = BGP_ORIGIN_EGP; + if (strncmp(argv[idx + 1]->arg, "incomplete", 2) == 0) + origin = BGP_ORIGIN_INCOMPLETE; + } + return bgp_aggregate_set(vty, prefix, AFI_IP6, SAFI_UNICAST, rmap, - sum_only, as_set); + sum_only, as_set, origin); } DEFUN (no_ipv6_aggregate_address, no_ipv6_aggregate_address_cmd, - "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD]", + "no aggregate-address X:X::X:X/M [<as-set [summary-only]|summary-only [as-set]>] [route-map WORD] [origin <egp|igp|incomplete>]", NO_STR "Configure BGP aggregate entries\n" "Aggregate prefix\n" @@ -7002,7 +7084,11 @@ DEFUN (no_ipv6_aggregate_address, "Filter more specific routes from updates\n" "Generate AS set path information\n" "Apply route map to aggregate network\n" - "Name of route map\n") + "Name of route map\n" + "BGP origin code\n" + "Remote EGP\n" + "Local IGP\n" + "Unknown heritage\n") { int idx = 0; argv_find(argv, argc, "X:X::X:X/M", &idx); @@ -8867,8 +8953,13 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, } else { if (nexthop_vrfid == VRF_UNKNOWN) vty_out(vty, " vrf ?"); - else - vty_out(vty, " vrf %u", nexthop_vrfid); + else { + struct vrf *vrf; + + vrf = vrf_lookup_by_id(nexthop_vrfid); + vty_out(vty, " vrf %s(%u)", + VRF_LOGNAME(vrf), nexthop_vrfid); + } } } @@ -10336,32 +10427,20 @@ DEFUN (show_ip_bgp_large_community_list, "Exact match of the large-communities\n" JSON_STR) { - char *vrf = NULL; afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; int idx = 0; bool exact_match = 0; - - if (argv_find(argv, argc, "ip", &idx)) - afi = AFI_IP; - if (argv_find(argv, argc, "view", &idx) - || argv_find(argv, argc, "vrf", &idx)) - vrf = argv[++idx]->arg; - if (argv_find(argv, argc, "ipv4", &idx) - || argv_find(argv, argc, "ipv6", &idx)) { - afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP; - if (argv_find(argv, argc, "unicast", &idx) - || argv_find(argv, argc, "multicast", &idx)) - safi = bgp_vty_safi_from_str(argv[idx]->text); - } - + struct bgp *bgp = NULL; bool uj = use_json(argc, argv); - struct bgp *bgp = bgp_lookup_by_name(vrf); - if (bgp == NULL) { - vty_out(vty, "Can't find BGP instance %s\n", vrf); - return CMD_WARNING; - } + if (uj) + argc--; + + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp, uj); + if (!idx) + return CMD_WARNING; argv_find(argv, argc, "large-community-list", &idx); @@ -10387,32 +10466,20 @@ DEFUN (show_ip_bgp_large_community, "Exact match of the large-communities\n" JSON_STR) { - char *vrf = NULL; afi_t afi = AFI_IP6; safi_t safi = SAFI_UNICAST; int idx = 0; bool exact_match = 0; - - if (argv_find(argv, argc, "ip", &idx)) - afi = AFI_IP; - if (argv_find(argv, argc, "view", &idx) - || argv_find(argv, argc, "vrf", &idx)) - vrf = argv[++idx]->arg; - if (argv_find(argv, argc, "ipv4", &idx) - || argv_find(argv, argc, "ipv6", &idx)) { - afi = strmatch(argv[idx]->text, "ipv6") ? AFI_IP6 : AFI_IP; - if (argv_find(argv, argc, "unicast", &idx) - || argv_find(argv, argc, "multicast", &idx)) - safi = bgp_vty_safi_from_str(argv[idx]->text); - } - + struct bgp *bgp = NULL; bool uj = use_json(argc, argv); - struct bgp *bgp = bgp_lookup_by_name(vrf); - if (bgp == NULL) { - vty_out(vty, "Can't find BGP instance %s\n", vrf); - return CMD_WARNING; - } + if (uj) + argc--; + + bgp_vty_find_and_parse_afi_safi_bgp(vty, argv, argc, &idx, &afi, &safi, + &bgp, uj); + if (!idx) + return CMD_WARNING; if (argv_find(argv, argc, "AA:BB:CC", &idx)) { if (argv_find(argv, argc, "exact-match", &idx)) @@ -12916,6 +12983,10 @@ void bgp_config_write_network(struct vty *vty, struct bgp *bgp, afi_t afi, if (bgp_aggregate->rmap.name) vty_out(vty, " route-map %s", bgp_aggregate->rmap.name); + if (bgp_aggregate->origin != BGP_ORIGIN_UNSPECIFIED) + vty_out(vty, " origin %s", + bgp_origin2str(bgp_aggregate->origin)); + vty_out(vty, "\n"); } } diff --git a/bgpd/bgp_route.h b/bgpd/bgp_route.h index 8f31cd38dc..0ad656d133 100644 --- a/bgpd/bgp_route.h +++ b/bgpd/bgp_route.h @@ -338,6 +338,9 @@ struct bgp_aggregate { /* Count of routes of origin type egp under this aggregate. */ unsigned long egp_origin_count; + /* Optional modify flag to override ORIGIN */ + uint8_t origin; + /* Hash containing the communities of all the * routes under this aggregate. */ diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c index f18f9ccf4b..62767a603c 100644 --- a/bgpd/bgp_vty.c +++ b/bgpd/bgp_vty.c @@ -9443,7 +9443,7 @@ static void bgp_show_neighnor_graceful_restart_rbit(struct vty *vty, bool rbit_status = 0; if (!use_json) - vty_out(vty, "\n R bit : "); + vty_out(vty, "\n R bit: "); if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV) && (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV)) @@ -9476,7 +9476,7 @@ static void bgp_show_neighbor_graceful_restart_remote_mode(struct vty *vty, const char *mode = "NotApplicable"; if (!use_json) - vty_out(vty, "\n Remote GR Mode : "); + vty_out(vty, "\n Remote GR Mode: "); if (CHECK_FLAG(peer->cap, PEER_CAP_RESTART_ADV) && (peer->status == Established)) { @@ -9512,7 +9512,7 @@ static void bgp_show_neighbor_graceful_restart_local_mode(struct vty *vty, const char *mode = "Invalid"; if (!use_json) - vty_out(vty, " Local GR Mode : "); + vty_out(vty, " Local GR Mode: "); if (bgp_peer_gr_mode_get(p) == PEER_HELPER) mode = "Helper"; @@ -9570,10 +9570,10 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( eor_flag = false; if (!use_json) { - vty_out(vty, " %s :\n", + vty_out(vty, " %s:\n", get_afi_safi_str(afi, safi, false)); - vty_out(vty, " F bit : "); + vty_out(vty, " F bit: "); } if (peer->nsf[afi][safi] @@ -9594,27 +9594,7 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( } if (!use_json) - vty_out(vty, " End-of-RIB Received : "); - - if (CHECK_FLAG(peer->af_sflags[afi][safi], - PEER_STATUS_EOR_RECEIVED)) { - if (use_json) - json_object_boolean_true_add( - json_endofrib_status, - "endOfRibRecv"); - else - vty_out(vty, "Yes\n"); - } else { - if (use_json) - json_object_boolean_false_add( - json_endofrib_status, - "endOfRibRecv"); - else - vty_out(vty, "No\n"); - } - - if (!use_json) - vty_out(vty, " End-of-RIB Send : "); + vty_out(vty, " End-of-RIB sent: "); if (CHECK_FLAG(peer->af_sflags[afi][safi], PEER_STATUS_EOR_SEND)) { @@ -9627,7 +9607,7 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( } else { vty_out(vty, "Yes\n"); vty_out(vty, - " EoRSentAfterUpdate : "); + " End-of-RIB sent after update: "); PRINT_EOR(eor_flag); } @@ -9642,11 +9622,31 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( } else { vty_out(vty, "No\n"); vty_out(vty, - " EoRSentAfterUpdate : "); + " End-of-RIB sent after update: "); vty_out(vty, "No\n"); } } + if (!use_json) + vty_out(vty, " End-of-RIB received: "); + + if (CHECK_FLAG(peer->af_sflags[afi][safi], + PEER_STATUS_EOR_RECEIVED)) { + if (use_json) + json_object_boolean_true_add( + json_endofrib_status, + "endOfRibRecv"); + else + vty_out(vty, "Yes\n"); + } else { + if (use_json) + json_object_boolean_false_add( + json_endofrib_status, + "endOfRibRecv"); + else + vty_out(vty, "No\n"); + } + if (use_json) { json_object_int_add(json_timer, "stalePathTimer", @@ -9686,46 +9686,36 @@ static void bgp_show_neighbor_graceful_restart_capability_per_afi_safi( .t_select_deferral)); } } else { - vty_out(vty, " Timers:\n"); - - vty_out(vty, "%*s", 6, ""); + vty_out(vty, " Timers:\n"); vty_out(vty, - "Configured Stale Path Time(sec)%*s: %u\n", - 8, "", peer->bgp->stalepath_time); + " Configured Stale Path Time(sec): %u\n", + peer->bgp->stalepath_time); - if (peer->t_gr_stale != NULL) { - vty_out(vty, "%*s", 6, ""); + if (peer->t_gr_stale != NULL) vty_out(vty, - "Stale Path Remaining(sec)%*s: %ld\n", - 14, "", + " Stale Path Remaining(sec): %ld\n", thread_timer_remain_second( peer->t_gr_stale)); - } /* Display Configured Selection * Deferral only when when * Gr mode is enabled. */ if (CHECK_FLAG(peer->flags, - PEER_FLAG_GRACEFUL_RESTART)) { - vty_out(vty, "%*s", 6, ""); + PEER_FLAG_GRACEFUL_RESTART)) vty_out(vty, - "Configured Selection Deferral Time(sec): %u\n", + " Configured Selection Deferral Time(sec): %u\n", peer->bgp->select_defer_time); - } if (peer->bgp->gr_info[afi][safi] .t_select_deferral - != NULL) { - - vty_out(vty, "%*s", 6, ""); + != NULL) vty_out(vty, - "Selection Deferral Time Remaining(sec) : %ld\n", + " Selection Deferral Time Remaining(sec): %ld\n", thread_timer_remain_second( peer->bgp ->gr_info[afi] [safi] .t_select_deferral)); - } } if (use_json) { json_object_object_add(json_afi_safi, @@ -9765,19 +9755,17 @@ static void bgp_show_neighbor_graceful_restart_time(struct vty *vty, json_object_object_add(json, "timers", json_timer); } else { - vty_out(vty, " Timers :\n"); - vty_out(vty, " Configured Restart Time(sec) : %u\n", + vty_out(vty, " Timers:\n"); + vty_out(vty, " Configured Restart Time(sec): %u\n", p->bgp->restart_time); - vty_out(vty, " Received Restart Time(sec) : %u\n", + vty_out(vty, " Received Restart Time(sec): %u\n", p->v_gr_restart); if (p->t_gr_restart != NULL) - vty_out(vty, - " Restart Time Remaining(sec) : %ld\n", + vty_out(vty, " Restart Time Remaining(sec): %ld\n", thread_timer_remain_second(p->t_gr_restart)); if (p->t_gr_restart != NULL) { - vty_out(vty, - " Restart Time Remaining(sec) : %ld\n", + vty_out(vty, " Restart Time Remaining(sec): %ld\n", thread_timer_remain_second(p->t_gr_restart)); } } diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c index 34581b66fc..96b307ee21 100644 --- a/bgpd/bgpd.c +++ b/bgpd/bgpd.c @@ -284,8 +284,11 @@ void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id) */ if (bgp->established_peers == 0) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("RID change : vrf %u, RTR ID %s", - bgp->vrf_id, inet_ntoa(*addr)); + zlog_debug( + "RID change : vrf %s(%u), RTR ID %s", + bgp->name_pretty, + bgp->vrf_id, + inet_ntoa(*addr)); bgp_router_id_set(bgp, addr, false); } } @@ -304,8 +307,11 @@ void bgp_router_id_zebra_bump(vrf_id_t vrf_id, const struct prefix *router_id) */ if (bgp->established_peers == 0) { if (BGP_DEBUG(zebra, ZEBRA)) - zlog_debug("RID change : vrf %u, RTR ID %s", - bgp->vrf_id, inet_ntoa(*addr)); + zlog_debug( + "RID change : vrf %s(%u), RTR ID %s", + bgp->name_pretty, + bgp->vrf_id, + inet_ntoa(*addr)); bgp_router_id_set(bgp, addr, false); } } @@ -427,10 +433,12 @@ int bgp_confederation_id_set(struct bgp *bgp, as_t as) AS change. Just Reset EBGP sessions, not CONFED sessions. If we were not doing confederation before, reset all EBGP sessions. */ for (ALL_LIST_ELEMENTS(bgp->peer, node, nnode, peer)) { + bgp_peer_sort_t ptype = peer_sort(peer); + /* We're looking for peers who's AS is not local or part of our confederation. */ if (already_confed) { - if (peer_sort(peer) == BGP_PEER_EBGP) { + if (ptype == BGP_PEER_EBGP) { peer->local_as = as; if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->status)) { @@ -446,9 +454,9 @@ int bgp_confederation_id_set(struct bgp *bgp, as_t as) /* Not doign confederation before, so reset every non-local session */ - if (peer_sort(peer) != BGP_PEER_IBGP) { + if (ptype != BGP_PEER_IBGP) { /* Reset the local_as to be our EBGP one */ - if (peer_sort(peer) == BGP_PEER_EBGP) + if (ptype == BGP_PEER_EBGP) peer->local_as = as; if (BGP_IS_VALID_STATE_FOR_NOTIF( peer->status)) { @@ -961,6 +969,11 @@ bgp_peer_sort_t peer_sort(struct peer *peer) return peer->sort; } +bgp_peer_sort_t peer_sort_lookup(struct peer *peer) +{ + return peer->sort; +} + static void peer_free(struct peer *peer) { afi_t afi; @@ -1652,7 +1665,7 @@ int bgp_afi_safi_peer_exists(struct bgp *bgp, afi_t afi, safi_t safi) /* Change peer's AS number. */ void peer_as_change(struct peer *peer, as_t as, int as_specified) { - bgp_peer_sort_t type; + bgp_peer_sort_t origtype, newtype; /* Stop peer. */ if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) { @@ -1663,7 +1676,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified) } else bgp_session_reset(peer); } - type = peer_sort(peer); + origtype = peer_sort_lookup(peer); peer->as = as; peer->as_type = as_specified; @@ -1674,21 +1687,22 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified) else peer->local_as = peer->bgp->as; + newtype = peer_sort(peer); /* Advertisement-interval reset */ if (!CHECK_FLAG(peer->flags, PEER_FLAG_ROUTEADV)) { - peer->v_routeadv = (peer_sort(peer) == BGP_PEER_IBGP) + peer->v_routeadv = (newtype == BGP_PEER_IBGP) ? BGP_DEFAULT_IBGP_ROUTEADV : BGP_DEFAULT_EBGP_ROUTEADV; } /* TTL reset */ - if (peer_sort(peer) == BGP_PEER_IBGP) + if (newtype == BGP_PEER_IBGP) peer->ttl = MAXTTL; - else if (type == BGP_PEER_IBGP) + else if (origtype == BGP_PEER_IBGP) peer->ttl = BGP_DEFAULT_TTL; /* reflector-client reset */ - if (peer_sort(peer) != BGP_PEER_IBGP) { + if (newtype != BGP_PEER_IBGP) { UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_UNICAST], PEER_FLAG_REFLECTOR_CLIENT); UNSET_FLAG(peer->af_flags[AFI_IP][SAFI_MULTICAST], @@ -1718,7 +1732,7 @@ void peer_as_change(struct peer *peer, as_t as, int as_specified) } /* local-as reset */ - if (peer_sort(peer) != BGP_PEER_EBGP) { + if (newtype != BGP_PEER_EBGP) { peer->change_local_as = 0; peer_flag_unset(peer, PEER_FLAG_LOCAL_AS); peer_flag_unset(peer, PEER_FLAG_LOCAL_AS_NO_PREPEND); @@ -2714,6 +2728,7 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, int first_member = 0; afi_t afi; safi_t safi; + bgp_peer_sort_t ptype, gtype; /* Lookup the peer. */ if (!peer) @@ -2742,15 +2757,16 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, peer->sort = group->conf->sort; } - if (!group->conf->as && peer_sort(peer)) { - if (peer_sort(group->conf) != BGP_PEER_INTERNAL - && peer_sort(group->conf) != peer_sort(peer)) { + ptype = peer_sort(peer); + if (!group->conf->as && ptype != BGP_PEER_UNSPECIFIED) { + gtype = peer_sort(group->conf); + if ((gtype != BGP_PEER_INTERNAL) && (gtype != ptype)) { if (as) *as = peer->as; return BGP_ERR_PEER_GROUP_PEER_TYPE_DIFFERENT; } - if (peer_sort(group->conf) == BGP_PEER_INTERNAL) + if (gtype == BGP_PEER_INTERNAL) first_member = 1; } @@ -2782,22 +2798,22 @@ int peer_group_bind(struct bgp *bgp, union sockunion *su, struct peer *peer, } if (first_member) { + gtype = peer_sort(group->conf); /* Advertisement-interval reset */ if (!CHECK_FLAG(group->conf->flags, PEER_FLAG_ROUTEADV)) { group->conf->v_routeadv = - (peer_sort(group->conf) - == BGP_PEER_IBGP) + (gtype == BGP_PEER_IBGP) ? BGP_DEFAULT_IBGP_ROUTEADV : BGP_DEFAULT_EBGP_ROUTEADV; } /* ebgp-multihop reset */ - if (peer_sort(group->conf) == BGP_PEER_IBGP) + if (gtype == BGP_PEER_IBGP) group->conf->ttl = MAXTTL; /* local-as reset */ - if (peer_sort(group->conf) != BGP_PEER_EBGP) { + if (gtype != BGP_PEER_EBGP) { group->conf->change_local_as = 0; peer_flag_unset(group->conf, PEER_FLAG_LOCAL_AS); @@ -4119,6 +4135,7 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, struct peer *member; struct listnode *node, *nnode; struct peer_flag_action action; + bgp_peer_sort_t ptype; memset(&action, 0, sizeof(struct peer_flag_action)); size = sizeof peer_af_flag_action_list @@ -4132,18 +4149,17 @@ static int peer_af_flag_modify(struct peer *peer, afi_t afi, safi_t safi, if (!found) return BGP_ERR_INVALID_FLAG; + ptype = peer_sort(peer); /* Special check for reflector client. */ - if (flag & PEER_FLAG_REFLECTOR_CLIENT - && peer_sort(peer) != BGP_PEER_IBGP) + if (flag & PEER_FLAG_REFLECTOR_CLIENT && ptype != BGP_PEER_IBGP) return BGP_ERR_NOT_INTERNAL_PEER; /* Special check for remove-private-AS. */ - if (flag & PEER_FLAG_REMOVE_PRIVATE_AS - && peer_sort(peer) == BGP_PEER_IBGP) + if (flag & PEER_FLAG_REMOVE_PRIVATE_AS && ptype == BGP_PEER_IBGP) return BGP_ERR_REMOVE_PRIVATE_AS; /* as-override is not allowed for IBGP peers */ - if (flag & PEER_FLAG_AS_OVERRIDE && peer_sort(peer) == BGP_PEER_IBGP) + if (flag & PEER_FLAG_AS_OVERRIDE && ptype == BGP_PEER_IBGP) return BGP_ERR_AS_OVERRIDE; /* Handle flag updates where desired state matches current state. */ @@ -5310,9 +5326,9 @@ int peer_local_as_set(struct peer *peer, as_t as, int no_prepend, struct bgp *bgp = peer->bgp; struct peer *member; struct listnode *node, *nnode; + bgp_peer_sort_t ptype = peer_sort(peer); - if (peer_sort(peer) != BGP_PEER_EBGP - && peer_sort(peer) != BGP_PEER_INTERNAL) + if (ptype != BGP_PEER_EBGP && ptype != BGP_PEER_INTERNAL) return BGP_ERR_LOCAL_AS_ALLOWED_ONLY_FOR_EBGP; if (bgp->as == as) diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h index d47ae71582..03d33130fe 100644 --- a/bgpd/bgpd.h +++ b/bgpd/bgpd.h @@ -1351,6 +1351,7 @@ struct peer { #define PEER_DOWN_NOAFI_ACTIVATED 30 /* No AFI/SAFI activated for peer */ #define PEER_DOWN_AS_SETS_REJECT 31 /* Reject routes with AS_SET */ #define PEER_DOWN_WAITING_OPEN 32 /* Waiting for open to succeed */ +#define PEER_DOWN_PFX_COUNT 33 /* Reached received prefix count */ /* * Remember to update peer_down_str in bgp_fsm.c when you add * a new value to the last_reset reason @@ -1489,6 +1490,7 @@ struct bgp_nlri { #define BGP_ORIGIN_IGP 0 #define BGP_ORIGIN_EGP 1 #define BGP_ORIGIN_INCOMPLETE 2 +#define BGP_ORIGIN_UNSPECIFIED 255 /* BGP notify message codes. */ #define BGP_NOTIFY_HEADER_ERR 1 @@ -1731,6 +1733,8 @@ extern struct peer *peer_unlock_with_caller(const char *, struct peer *); #define peer_lock(B) peer_lock_with_caller(__FUNCTION__, (B)) extern bgp_peer_sort_t peer_sort(struct peer *peer); +extern bgp_peer_sort_t peer_sort_lookup(struct peer *peer); + extern int peer_active(struct peer *); extern int peer_active_nego(struct peer *); extern void bgp_recalculate_all_bestpaths(struct bgp *bgp); diff --git a/bgpd/rfapi/rfapi_rib.c b/bgpd/rfapi/rfapi_rib.c index 39d4b3ee29..b7ec35c661 100644 --- a/bgpd/rfapi/rfapi_rib.c +++ b/bgpd/rfapi/rfapi_rib.c @@ -2184,6 +2184,7 @@ void rfapiRibPendingDeleteRoute(struct bgp *bgp, struct rfapi_import_table *it, rfapiRibUpdatePendingNode( bgp, m->rfd, it, it_node, m->rfd->response_lifetime); + agg_unlock_node(rn); } } diff --git a/doc/developer/cli.rst b/doc/developer/cli.rst index cf35b03f0c..12fcb7a325 100644 --- a/doc/developer/cli.rst +++ b/doc/developer/cli.rst @@ -371,11 +371,11 @@ Type rules +----------------------------+--------------------------------+--------------------------+ | ``A.B.C.D + X:X::X:X`` | ``const union sockunion *`` | ``NULL`` | +----------------------------+--------------------------------+--------------------------+ -| ``A.B.C.D/M`` | ``const struct prefix_ipv4 *`` | ``NULL`` | +| ``A.B.C.D/M`` | ``const struct prefix_ipv4 *`` | ``all-zeroes struct`` | +----------------------------+--------------------------------+--------------------------+ -| ``X:X::X:X/M`` | ``const struct prefix_ipv6 *`` | ``NULL`` | +| ``X:X::X:X/M`` | ``const struct prefix_ipv6 *`` | ``all-zeroes struct`` | +----------------------------+--------------------------------+--------------------------+ -| ``A.B.C.D/M + X:X::X:X/M`` | ``const struct prefix *`` | ``NULL`` | +| ``A.B.C.D/M + X:X::X:X/M`` | ``const struct prefix *`` | ``all-zeroes struct`` | +----------------------------+--------------------------------+--------------------------+ | ``(0-9)`` | ``long`` | ``0`` | +----------------------------+--------------------------------+--------------------------+ @@ -395,8 +395,10 @@ Note the following details: ``word`` tokens (e.g. constant words). This is useful if some parts of a command are optional. The type will be ``const char *``. - ``[no]`` will be passed as ``const char *no``. -- Pointers will be ``NULL`` when the argument is optional and the user did not - use it. +- Most pointers will be ``NULL`` when the argument is optional and the + user did not supply it. As noted in the table above, some prefix + struct type arguments are passed as pointers to all-zeroes structs, + not as ``NULL`` pointers. - If a parameter is not a pointer, but is optional and the user didn't use it, the default value will be passed. Check the ``_str`` argument if you need to determine whether the parameter was omitted. diff --git a/doc/developer/library.rst b/doc/developer/library.rst index a904a4e778..3d5c6a2a15 100644 --- a/doc/developer/library.rst +++ b/doc/developer/library.rst @@ -15,5 +15,6 @@ Library Facilities (libfrr) hooks cli modules + lua diff --git a/doc/developer/lists.rst b/doc/developer/lists.rst index 5f020060ce..853c65ddf3 100644 --- a/doc/developer/lists.rst +++ b/doc/developer/lists.rst @@ -1,3 +1,5 @@ +.. _lists: + List implementations ==================== diff --git a/doc/developer/locking.rst b/doc/developer/locking.rst index aee05aae06..d698789f9f 100644 --- a/doc/developer/locking.rst +++ b/doc/developer/locking.rst @@ -1,3 +1,5 @@ +.. _locking: + Locking ======= diff --git a/doc/developer/logging.rst b/doc/developer/logging.rst index e393fe6fba..db577c9216 100644 --- a/doc/developer/logging.rst +++ b/doc/developer/logging.rst @@ -1,3 +1,5 @@ +.. _logging: + Developer's Guide to Logging ============================ diff --git a/doc/developer/lua.rst b/doc/developer/lua.rst new file mode 100644 index 0000000000..23eb35fc58 --- /dev/null +++ b/doc/developer/lua.rst @@ -0,0 +1,65 @@ +.. _lua: + +Lua +=== + +Lua is currently experimental within FRR and has very limited +support. If you would like to compile FRR with Lua you must +follow these steps: + +1. Installation of Relevant Libraries + + .. code-block:: shell + + apt-get install lua5.3 liblua5-3 liblua5.3-dev + + These are the Debian libraries that are needed. There should + be equivalent RPM's that can be found + +2. Compilation + + Configure needs these options + + .. code-block:: shell + + ./configure --enable-dev-build --enable-lua <all other interesting options> + + Typically you just include the two new enable lines to build with it. + +3. Using Lua + + * Copy tools/lua.scr into /etc/frr + + * Create a route-map match command + + .. code-block:: console + + ! + router bgp 55 + neighbor 10.50.11.116 remote-as external + address-family ipv4 unicast + neighbor 10.50.11.116 route-map TEST in + exit-address-family + ! + route-map TEST permit 10 + match command mooey + ! + + * In the lua.scr file make sure that you have a function named 'mooey' + + .. code-block:: console + + function mooey () + zlog_debug(string.format("afi: %d: %s %d ifdx: %d aspath: %s localpref: %d", + prefix.family, prefix.route, nexthop.metric, + nexthop.ifindex, nexthop.aspath, nexthop.localpref)) + + nexthop.metric = 33 + nexthop.localpref = 13 + return 3 + end + +4. General Comments + + Please be aware that this is extremely experimental and needs a ton of work + to get this up into a state that is usable. diff --git a/doc/developer/modules.rst b/doc/developer/modules.rst index 763d8b1b8d..02330ddfe4 100644 --- a/doc/developer/modules.rst +++ b/doc/developer/modules.rst @@ -1,3 +1,5 @@ +.. _modules: + Modules ======= diff --git a/doc/developer/static-linking.rst b/doc/developer/static-linking.rst index bc33207b38..1e45c48dc3 100644 --- a/doc/developer/static-linking.rst +++ b/doc/developer/static-linking.rst @@ -10,7 +10,7 @@ likely to be present on a given platform - libfrr and libyang. The resultant binaries should still be fairly portable. For example, here is the DSO dependency list for `bgpd` after using these steps: -.. code-block:: +.. code-block:: shell $ ldd bgpd linux-vdso.so.1 (0x00007ffe3a989000) @@ -56,7 +56,7 @@ usable for our purposes. So download ``libpcre`` from `SourceForge <https://sourceforge.net/projects/pcre/>`_, and build it like this: -.. code-block:: +.. code-block:: shell ./configure --with-pic make diff --git a/doc/developer/subdir.am b/doc/developer/subdir.am index 791f7679a6..538a290c34 100644 --- a/doc/developer/subdir.am +++ b/doc/developer/subdir.am @@ -34,6 +34,7 @@ dev_RSTFILES = \ doc/developer/lists.rst \ doc/developer/locking.rst \ doc/developer/logging.rst \ + doc/developer/lua.rst \ doc/developer/memtypes.rst \ doc/developer/modules.rst \ doc/developer/next-hop-tracking.rst \ diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst index fa84f6dc76..de690adb34 100644 --- a/doc/user/bgp.rst +++ b/doc/user/bgp.rst @@ -924,6 +924,11 @@ Route Aggregation-IPv4 Address Family Apply a route-map for an aggregated prefix. +.. index:: aggregate-address A.B.C.D/M origin <egp|igp|incomplete> +.. clicmd:: aggregate-address A.B.C.D/M origin <egp|igp|incomplete> + + Override ORIGIN for an aggregated prefix. + .. index:: aggregate-address A.B.C.D/M as-set .. clicmd:: aggregate-address A.B.C.D/M as-set @@ -971,6 +976,11 @@ Route Aggregation-IPv6 Address Family Apply a route-map for an aggregated prefix. +.. index:: aggregate-address X:X::X:X/M origin <egp|igp|incomplete> +.. clicmd:: aggregate-address X:X::X:X/M origin <egp|igp|incomplete> + + Override ORIGIN for an aggregated prefix. + .. index:: aggregate-address X:X::X:X/M as-set .. clicmd:: aggregate-address X:X::X:X/M as-set diff --git a/doc/user/overview.rst b/doc/user/overview.rst index 262c0117df..2c8eadd4a7 100644 --- a/doc/user/overview.rst +++ b/doc/user/overview.rst @@ -292,6 +292,8 @@ BGP :t:`BGP/MPLS IP Virtual Private Networks (VPNs). Y. Rekhter. Feb 2006.` - :rfc:`4659` :t:`BGP-MPLS IP Virtual Private Network (VPN) Extension for IPv6 VPN. J. De Clercq, D. Ooms, M. Carugi, F. Le Faucheur. September 2006.` +- :rfc:`4893` + :t:`BGP Support for Four-octet AS Number Space. Q. Vohra, E. Chen May 2007.` - :rfc:`5004` :t:`Avoid BGP Best Path Transitions from One External to Another. E. Chen & S. Sangli. September 2007 (Partial support).` - :rfc:`5082` diff --git a/doc/user/pim.rst b/doc/user/pim.rst index 6bda692607..9876216736 100644 --- a/doc/user/pim.rst +++ b/doc/user/pim.rst @@ -461,6 +461,18 @@ cause great confusion. Display upstream information for S,G's and the RPF data associated with them. +.. index:: show ip pim [vrf NAME] mlag upstream [A.B.C.D [A.B.C.D]] [json] +.. clicmd:: show ip pim mlag upstream + + Display upstream entries that are synced across MLAG switches. + Allow the user to specify sub Source and Groups address filters. + +.. index:: show ip pim mlag summary +.. clicmd:: show ip pim mlag summary + + Display PIM MLAG (multi-chassis link aggregation) session status and + control message statistics. + .. index:: show ip pim bsr .. clicmd:: show ip pim bsr diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index 435639c291..8526b0f984 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -346,6 +346,27 @@ Route Map Exit Action Command Proceed processing the route-map at the first entry whose order is >= N +.. _route-map-optimization-command: + +Route Map Optimization Command +============================== + +.. index:: route-map optimization +.. clicmd:: route-map optimization + + Enable route-map processing optimization. The optimization is + enabled by default. + Instead of sequentially passing through all the route-map indexes + until a match is found, the search for the best-match index will be + based on a look-up in a prefix-tree. A per-route-map prefix-tree + will be constructed for this purpose. The prefix-tree will compose + of all the prefixes in all the prefix-lists that are included in the + match rule of all the sequences of a route-map. + +.. index:: no route-map optimization +.. clicmd:: no route-map optimization + + Disable the route-map processing optimization. Route Map Examples ================== diff --git a/doc/user/vrrp.rst b/doc/user/vrrp.rst index 435580131b..33582ee446 100644 --- a/doc/user/vrrp.rst +++ b/doc/user/vrrp.rst @@ -140,7 +140,7 @@ macvlan device. If you are using ``iproute2``, the equivalent configuration is: ip link set dev vrrp4-2-1 up ip link add vrrp6-2-1 link eth0 addrgenmode random type macvlan mode bridge - ip link set dev vrrp4-2-1 address 00:00:5e:00:02:05 + ip link set dev vrrp6-2-1 address 00:00:5e:00:02:05 ip addr add 2001:db8::370:7334/64 dev vrrp6-2-1 ip link set dev vrrp6-2-1 up diff --git a/isisd/isis_circuit.c b/isisd/isis_circuit.c index 8343f7d85f..e4152a8712 100644 --- a/isisd/isis_circuit.c +++ b/isisd/isis_circuit.c @@ -1386,7 +1386,6 @@ int isis_if_delete_hook(struct interface *ifp) if (ifp && ifp->info) { circuit = ifp->info; isis_csm_state_change(IF_DOWN_FROM_Z, circuit, circuit->area); - isis_csm_state_change(ISIS_DISABLE, circuit, circuit->area); } return 0; diff --git a/ldpd/address.c b/ldpd/address.c index 9c1564a31f..74a3f5a309 100644 --- a/ldpd/address.c +++ b/ldpd/address.c @@ -67,7 +67,7 @@ send_address(struct nbr *nbr, int af, struct if_addr_head *addr_list, fatalx("send_address: unknown af"); } - while ((if_addr = LIST_FIRST(addr_list)) != NULL) { + while (LIST_FIRST(addr_list) != NULL) { /* * Send as many addresses as possible - respect the session's * negotiated maximum pdu length. diff --git a/ldpd/ldp_zebra.c b/ldpd/ldp_zebra.c index 946b51e4ee..b3ccb77602 100644 --- a/ldpd/ldp_zebra.c +++ b/ldpd/ldp_zebra.c @@ -106,7 +106,7 @@ static int ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr) { struct zapi_labels zl = {}; - struct zapi_nexthop_label *znh; + struct zapi_nexthop *znh; if (kr->local_label < MPLS_LABEL_RESERVED_MAX || kr->remote_label == NO_LABEL) @@ -143,16 +143,14 @@ ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr) znh = &zl.nexthops[0]; switch (kr->af) { case AF_INET: - znh->family = AF_INET; - znh->address.ipv4 = kr->nexthop.v4; + znh->gate.ipv4 = kr->nexthop.v4; if (kr->ifindex) znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; else znh->type = NEXTHOP_TYPE_IPV4; break; case AF_INET6: - znh->family = AF_INET6; - znh->address.ipv6 = kr->nexthop.v6; + znh->gate.ipv6 = kr->nexthop.v6; if (kr->ifindex) znh->type = NEXTHOP_TYPE_IPV6_IFINDEX; else @@ -162,7 +160,8 @@ ldp_zebra_send_mpls_labels(int cmd, struct kroute *kr) break; } znh->ifindex = kr->ifindex; - znh->label = kr->remote_label; + znh->label_num = 1; + znh->labels[0] = kr->remote_label; return zebra_send_mpls_labels(zclient, cmd, &zl); } diff --git a/ldpd/ldpd.c b/ldpd/ldpd.c index dcbcf8ce50..13de48fd70 100644 --- a/ldpd/ldpd.c +++ b/ldpd/ldpd.c @@ -858,7 +858,6 @@ ldp_acl_request(struct imsgev *iev, char *acl_name, int af, union ldpd_addr *addr, uint8_t prefixlen) { struct imsg imsg; - ssize_t n; struct acl_check acl_check; if (acl_name[0] == '\0') @@ -876,9 +875,9 @@ ldp_acl_request(struct imsgev *iev, char *acl_name, int af, imsg_flush(&iev->ibuf); /* receive (blocking) and parse result */ - if ((n = imsg_read(&iev->ibuf)) == -1) + if (imsg_read(&iev->ibuf) == -1) fatal("imsg_read error"); - if ((n = imsg_get(&iev->ibuf, &imsg)) == -1) + if (imsg_get(&iev->ibuf, &imsg) == -1) fatal("imsg_get"); if (imsg.hdr.type != IMSG_ACL_CHECK || imsg.hdr.len != IMSG_HEADER_SIZE + sizeof(int)) @@ -1408,7 +1407,7 @@ merge_ifaces(struct ldpd_conf *conf, struct ldpd_conf *xconf) RB_FOREACH_SAFE(iface, iface_head, &conf->iface_tree, itmp) { /* find deleted interfaces */ - if ((xi = if_lookup_name(xconf, iface->name)) == NULL) { + if (if_lookup_name(xconf, iface->name) == NULL) { switch (ldpd_process) { case PROC_LDP_ENGINE: ldpe_if_exit(iface); @@ -1469,7 +1468,7 @@ merge_tnbrs(struct ldpd_conf *conf, struct ldpd_conf *xconf) continue; /* find deleted tnbrs */ - if ((xt = tnbr_find(xconf, tnbr->af, &tnbr->addr)) == NULL) { + if (tnbr_find(xconf, tnbr->af, &tnbr->addr) == NULL) { switch (ldpd_process) { case PROC_LDP_ENGINE: tnbr->flags &= ~F_TNBR_CONFIGURED; @@ -1515,33 +1514,35 @@ merge_nbrps(struct ldpd_conf *conf, struct ldpd_conf *xconf) RB_FOREACH_SAFE(nbrp, nbrp_head, &conf->nbrp_tree, ntmp) { /* find deleted nbrps */ - if ((xn = nbr_params_find(xconf, nbrp->lsr_id)) == NULL) { - switch (ldpd_process) { - case PROC_LDP_ENGINE: - nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr); - if (nbr) { - session_shutdown(nbr, S_SHUTDOWN, 0, 0); + if (nbr_params_find(xconf, nbrp->lsr_id) != NULL) + continue; + + switch (ldpd_process) { + case PROC_LDP_ENGINE: + nbr = nbr_find_ldpid(nbrp->lsr_id.s_addr); + if (nbr) { + session_shutdown(nbr, S_SHUTDOWN, 0, 0); #ifdef __OpenBSD__ - pfkey_remove(nbr); + pfkey_remove(nbr); #else - sock_set_md5sig( - (ldp_af_global_get(&global, - nbr->af))->ldp_session_socket, - nbr->af, &nbr->raddr, NULL); + sock_set_md5sig( + (ldp_af_global_get(&global, nbr->af)) + ->ldp_session_socket, + nbr->af, &nbr->raddr, NULL); #endif - nbr->auth.method = AUTH_NONE; - if (nbr_session_active_role(nbr)) - nbr_establish_connection(nbr); - } - break; - case PROC_LDE_ENGINE: - case PROC_MAIN: - break; + nbr->auth.method = AUTH_NONE; + if (nbr_session_active_role(nbr)) + nbr_establish_connection(nbr); } - RB_REMOVE(nbrp_head, &conf->nbrp_tree, nbrp); - free(nbrp); + break; + case PROC_LDE_ENGINE: + case PROC_MAIN: + break; } + RB_REMOVE(nbrp_head, &conf->nbrp_tree, nbrp); + free(nbrp); } + RB_FOREACH_SAFE(xn, nbrp_head, &xconf->nbrp_tree, ntmp) { /* find new nbrps */ if ((nbrp = nbr_params_find(conf, xn->lsr_id)) == NULL) { @@ -1624,7 +1625,7 @@ merge_l2vpns(struct ldpd_conf *conf, struct ldpd_conf *xconf) RB_FOREACH_SAFE(l2vpn, l2vpn_head, &conf->l2vpn_tree, ltmp) { /* find deleted l2vpns */ - if ((xl = l2vpn_find(xconf, l2vpn->name)) == NULL) { + if (l2vpn_find(xconf, l2vpn->name) == NULL) { switch (ldpd_process) { case PROC_LDE_ENGINE: l2vpn_exit(l2vpn); @@ -1680,7 +1681,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) /* merge intefaces */ RB_FOREACH_SAFE(lif, l2vpn_if_head, &l2vpn->if_tree, ftmp) { /* find deleted interfaces */ - if ((xf = l2vpn_if_find(xl, lif->ifname)) == NULL) { + if (l2vpn_if_find(xl, lif->ifname) == NULL) { RB_REMOVE(l2vpn_if_head, &l2vpn->if_tree, lif); free(lif); } @@ -1706,7 +1707,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) /* merge active pseudowires */ RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_tree, ptmp) { /* find deleted active pseudowires */ - if ((xp = l2vpn_pw_find_active(xl, pw->ifname)) == NULL) { + if (l2vpn_pw_find_active(xl, pw->ifname) == NULL) { switch (ldpd_process) { case PROC_LDE_ENGINE: l2vpn_pw_exit(pw); @@ -1807,7 +1808,7 @@ merge_l2vpn(struct ldpd_conf *xconf, struct l2vpn *l2vpn, struct l2vpn *xl) /* merge inactive pseudowires */ RB_FOREACH_SAFE(pw, l2vpn_pw_head, &l2vpn->pw_inactive_tree, ptmp) { /* find deleted inactive pseudowires */ - if ((xp = l2vpn_pw_find_inactive(xl, pw->ifname)) == NULL) { + if (l2vpn_pw_find_inactive(xl, pw->ifname) == NULL) { RB_REMOVE(l2vpn_pw_head, &l2vpn->pw_inactive_tree, pw); free(pw); } diff --git a/ldpd/socket.c b/ldpd/socket.c index 8706d03c6f..997434620a 100644 --- a/ldpd/socket.c +++ b/ldpd/socket.c @@ -209,7 +209,7 @@ sock_set_nonblock(int fd) flags |= O_NONBLOCK; - if ((flags = fcntl(fd, F_SETFL, flags)) == -1) + if (fcntl(fd, F_SETFL, flags) == -1) fatal("fcntl F_SETFL"); } @@ -223,7 +223,7 @@ sock_set_cloexec(int fd) flags |= FD_CLOEXEC; - if ((flags = fcntl(fd, F_SETFD, flags)) == -1) + if (fcntl(fd, F_SETFD, flags) == -1) fatal("fcntl F_SETFD"); } diff --git a/lib/filter.c b/lib/filter.c index 80f8cf0bd0..3226fb2f5e 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -412,7 +412,7 @@ static int64_t filter_new_seq_get(struct access_list *access) int64_t newseq; struct filter *filter; - maxseq = newseq = 0; + maxseq = 0; for (filter = access->head; filter; filter = filter->next) { if (maxseq < filter->seq) @@ -745,12 +745,16 @@ static void if_dump(const struct interface *ifp) struct listnode *node; struct connected *c __attribute__((unused)); - for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c)) + for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, c)) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + zlog_info( - "Interface %s vrf %u index %d metric %d mtu %d " + "Interface %s vrf %s(%u) index %d metric %d mtu %d " "mtu6 %d %s", - ifp->name, ifp->vrf_id, ifp->ifindex, ifp->metric, - ifp->mtu, ifp->mtu6, if_flag_dump(ifp->flags)); + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, + ifp->metric, ifp->mtu, ifp->mtu6, + if_flag_dump(ifp->flags)); + } } /* Interface printing for all interface. */ @@ -811,27 +815,25 @@ DEFUN (show_address, "address\n" VRF_CMD_HELP_STR) { - int idx_vrf = 3; - struct listnode *node; - struct interface *ifp; - struct connected *ifc; - struct prefix *p; - vrf_id_t vrf_id = VRF_DEFAULT; + int idx_vrf = 3; + struct listnode *node; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; + vrf_id_t vrf_id = VRF_DEFAULT; - if (argc > 2) - VRF_GET_ID (vrf_id, argv[idx_vrf]->arg); + if (argc > 2) + VRF_GET_ID (vrf_id, argv[idx_vrf]->arg); - FOR_ALL_INTERFACES (vrf, ifp) - { - for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) - { - p = ifc->address; + FOR_ALL_INTERFACES (vrf, ifp) { + for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) { + p = ifc->address; - if (p->family == AF_INET) - vty_out (vty, "%s/%d\n", inet_ntoa (p->u.prefix4), p->prefixlen); + if (p->family == AF_INET) + vty_out (vty, "%s/%d\n", inet_ntoa (p->u.prefix4), p->prefixlen); + } } - } - return CMD_SUCCESS; + return CMD_SUCCESS; } DEFUN (show_address_vrf_all, @@ -841,31 +843,30 @@ DEFUN (show_address_vrf_all, "address\n" VRF_ALL_CMD_HELP_STR) { - struct vrf *vrf; - struct listnode *node; - struct interface *ifp; - struct connected *ifc; - struct prefix *p; + struct vrf *vrf; + struct listnode *node; + struct interface *ifp; + struct connected *ifc; + struct prefix *p; - RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) - { - if (RB_EMPTY (if_name_head, &vrf->ifaces_by_name)) - continue; + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) + { + if (RB_EMPTY (if_name_head, &vrf->ifaces_by_name)) + continue; - vty_out (vty, "\nVRF %u\n\n", vrf->vrf_id); + vty_out (vty, "\nVRF %s(%u)\n\n", + VRF_LOGNAME(vrf), vrf->vrf_id); - FOR_ALL_INTERFACES (vrf, ifp) - { - for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) - { - p = ifc->address; + FOR_ALL_INTERFACES (vrf, ifp) { + for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc)) { + p = ifc->address; - if (p->family == AF_INET) - vty_out (vty, "%s/%d\n", inet_ntoa (p->u.prefix4), p->prefixlen); - } - } - } - return CMD_SUCCESS; + if (p->family == AF_INET) + vty_out (vty, "%s/%d\n", inet_ntoa (p->u.prefix4), p->prefixlen); + } + } + } + return CMD_SUCCESS; } #endif @@ -927,14 +928,16 @@ connected_log(struct connected *connected, char *str) { struct prefix *p; struct interface *ifp; + struct vrf *vrf; char logbuf[BUFSIZ]; char buf[BUFSIZ]; ifp = connected->ifp; p = connected->address; - snprintf(logbuf, BUFSIZ, "%s interface %s vrf %u %s %s/%d ", str, - ifp->name, ifp->vrf_id, prefix_family_str(p), + vrf = vrf_lookup_by_id(ifp->vrf_id); + snprintf(logbuf, BUFSIZ, "%s interface %s vrf %s(%u) %s %s/%d ", str, + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, prefix_family_str(p), inet_ntop(p->family, &p->u.prefix, buf, BUFSIZ), p->prefixlen); p = connected->destination; diff --git a/lib/ipaddr.h b/lib/ipaddr.h index 6bd614044c..c6372f1abb 100644 --- a/lib/ipaddr.h +++ b/lib/ipaddr.h @@ -119,10 +119,13 @@ static inline void ipv4_mapped_ipv6_to_ipv4(struct in6_addr *in6, memcpy(in, (char *)in6 + 12, sizeof(struct in_addr)); } +/* + * Check if a struct ipaddr has nonzero value + */ static inline bool ipaddr_isset(struct ipaddr *ip) { static struct ipaddr a = {}; - return (0 == memcmp(&a, ip, sizeof(struct ipaddr))); + return (0 != memcmp(&a, ip, sizeof(struct ipaddr))); } #ifdef __cplusplus @@ -1092,6 +1092,11 @@ static const struct zebra_desc_table command_types[] = { DESC_ENTRY(ZEBRA_VXLAN_SG_ADD), DESC_ENTRY(ZEBRA_VXLAN_SG_DEL), DESC_ENTRY(ZEBRA_VXLAN_SG_REPLAY), + DESC_ENTRY(ZEBRA_MLAG_PROCESS_UP), + DESC_ENTRY(ZEBRA_MLAG_PROCESS_DOWN), + DESC_ENTRY(ZEBRA_MLAG_CLIENT_REGISTER), + DESC_ENTRY(ZEBRA_MLAG_CLIENT_UNREGISTER), + DESC_ENTRY(ZEBRA_MLAG_FORWARD_MSG), DESC_ENTRY(ZEBRA_ERROR), DESC_ENTRY(ZEBRA_CLIENT_CAPABILITIES)}; #undef DESC_ENTRY diff --git a/lib/nexthop_group.c b/lib/nexthop_group.c index 3005a51c71..d660428bcd 100644 --- a/lib/nexthop_group.c +++ b/lib/nexthop_group.c @@ -216,7 +216,8 @@ struct nexthop_group *nexthop_group_new(void) return XCALLOC(MTYPE_NEXTHOP_GROUP, sizeof(struct nexthop_group)); } -void nexthop_group_copy(struct nexthop_group *to, struct nexthop_group *from) +void nexthop_group_copy(struct nexthop_group *to, + const struct nexthop_group *from) { /* Copy everything, including recursive info */ copy_nexthops(&to->nexthop, from->nexthop, NULL); diff --git a/lib/nexthop_group.h b/lib/nexthop_group.h index 73b020283a..f99a53f694 100644 --- a/lib/nexthop_group.h +++ b/lib/nexthop_group.h @@ -43,7 +43,7 @@ struct nexthop_group *nexthop_group_new(void); void nexthop_group_delete(struct nexthop_group **nhg); void nexthop_group_copy(struct nexthop_group *to, - struct nexthop_group *from); + const struct nexthop_group *from); /* * Copy a list of nexthops in 'nh' to an nhg, enforcing canonical sort order diff --git a/lib/plist.c b/lib/plist.c index 662221beec..e465963f21 100644 --- a/lib/plist.c +++ b/lib/plist.c @@ -303,6 +303,8 @@ static void prefix_list_delete(struct prefix_list *plist) /* If prefix-list contain prefix_list_entry free all of it. */ for (pentry = plist->head; pentry; pentry = next) { + route_map_notify_pentry_dependencies(plist->name, pentry, + RMAP_EVENT_PLIST_DELETED); next = pentry->next; prefix_list_trie_del(plist, pentry); prefix_list_entry_free(pentry); @@ -385,7 +387,7 @@ static int64_t prefix_new_seq_get(struct prefix_list *plist) int64_t newseq; struct prefix_list_entry *pentry; - maxseq = newseq = 0; + maxseq = 0; for (pentry = plist->head; pentry; pentry = pentry->next) { if (maxseq < pentry->seq) @@ -518,6 +520,8 @@ static void prefix_list_entry_delete(struct prefix_list *plist, else plist->tail = pentry->prev; + route_map_notify_pentry_dependencies(plist->name, pentry, + RMAP_EVENT_PLIST_DELETED); prefix_list_entry_free(pentry); plist->count--; @@ -631,6 +635,9 @@ static void prefix_list_entry_add(struct prefix_list *plist, /* Increment count. */ plist->count++; + route_map_notify_pentry_dependencies(plist->name, pentry, + RMAP_EVENT_PLIST_ADDED); + /* Run hook function. */ if (plist->master->add_hook) (*plist->master->add_hook)(plist); diff --git a/lib/routemap.c b/lib/routemap.c index 0d5621d90e..54b5383173 100644 --- a/lib/routemap.c +++ b/lib/routemap.c @@ -31,6 +31,7 @@ #include "hash.h" #include "libfrr.h" #include "lib_errors.h" +#include "table.h" DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP, "Route map") DEFINE_MTYPE(LIB, ROUTE_MAP_NAME, "Route map name") @@ -44,12 +45,52 @@ DEFINE_MTYPE_STATIC(LIB, ROUTE_MAP_DEP_DATA, "Route map dependency data") DEFINE_QOBJ_TYPE(route_map_index) DEFINE_QOBJ_TYPE(route_map) +#define IPv4_PREFIX_LIST "ip address prefix-list" +#define IPv6_PREFIX_LIST "ipv6 address prefix-list" +#define IPv4_MATCH_RULE "ip " +#define IPv6_MATCH_RULE "ipv6 " + +#define IS_RULE_IPv4_PREFIX_LIST(S) \ + (strncmp(S, IPv4_PREFIX_LIST, strlen(IPv4_PREFIX_LIST)) == 0) +#define IS_RULE_IPv6_PREFIX_LIST(S) \ + (strncmp(S, IPv6_PREFIX_LIST, strlen(IPv6_PREFIX_LIST)) == 0) + +#define IS_IPv4_RULE(S) \ + (strncmp(S, IPv4_MATCH_RULE, strlen(IPv4_MATCH_RULE)) == 0) +#define IS_IPv6_RULE(S) \ + (strncmp(S, IPv6_MATCH_RULE, strlen(IPv6_MATCH_RULE)) == 0) +struct route_map_pentry_dep { + struct prefix_list_entry *pentry; + const char *plist_name; + route_map_event_t event; +}; + /* Vector for route match rules. */ static vector route_match_vec; /* Vector for route set rules. */ static vector route_set_vec; +static void route_map_pfx_tbl_update(route_map_event_t event, + struct route_map_index *index, afi_t afi, + const char *plist_name); +static void route_map_pfx_table_add_default(afi_t afi, + struct route_map_index *index); +static void route_map_pfx_table_del_default(afi_t afi, + struct route_map_index *index); +static void route_map_add_plist_entries(afi_t afi, + struct route_map_index *index, + const char *plist_name, + struct prefix_list_entry *entry); +static void route_map_del_plist_entries(afi_t afi, + struct route_map_index *index, + const char *plist_name, + struct prefix_list_entry *entry); +static bool route_map_is_ip_rule_present(struct route_map_index *index); +static bool route_map_is_ipv6_rule_present(struct route_map_index *index); + +static struct hash *route_map_get_dep_hash(route_map_event_t event); + struct route_map_match_set_hooks rmap_match_set_hook; /* match interface */ @@ -566,6 +607,12 @@ static struct route_map *route_map_add(const char *name) route_map_notify_dependencies(name, RMAP_EVENT_CALL_ADDED); } + if (!map->ipv4_prefix_table) + map->ipv4_prefix_table = route_table_init(); + + if (!map->ipv6_prefix_table) + map->ipv6_prefix_table = route_table_init(); + if (rmap_debug) zlog_debug("Add route-map %s", name); return map; @@ -786,8 +833,9 @@ static void vty_show_route_map_entry(struct vty *vty, struct route_map *map) struct route_map_index *index; struct route_map_rule *rule; - vty_out(vty, "route-map: %s Invoked: %" PRIu64 "\n", - map->name, map->applied - map->applied_clear); + vty_out(vty, "route-map: %s Invoked: %" PRIu64 " Optimization: %s\n", + map->name, map->applied - map->applied_clear, + map->optimization_disabled ? "disabled" : "enabled"); for (index = map->head; index; index = index->next) { vty_out(vty, " %s, sequence %d Invoked %" PRIu64 "\n", @@ -914,6 +962,7 @@ static struct route_map_index *route_map_index_new(void) /* Free route map index. */ void route_map_index_delete(struct route_map_index *index, int notify) { + struct routemap_hook_context *rhc; struct route_map_rule *rule; QOBJ_UNREG(index); @@ -923,12 +972,21 @@ void route_map_index_delete(struct route_map_index *index, int notify) index->map->name, index->pref); /* Free route map northbound hook contexts. */ - while (!TAILQ_EMPTY(&index->rhclist)) - routemap_hook_context_free(TAILQ_FIRST(&index->rhclist)); + while ((rhc = TAILQ_FIRST(&index->rhclist)) != NULL) + routemap_hook_context_free(rhc); /* Free route match. */ - while ((rule = index->match_list.head) != NULL) + while ((rule = index->match_list.head) != NULL) { + if (IS_RULE_IPv4_PREFIX_LIST(rule->cmd->str)) + route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED, + index, AFI_IP, rule->rule_str); + else if (IS_RULE_IPv6_PREFIX_LIST(rule->cmd->str)) + route_map_pfx_tbl_update(RMAP_EVENT_PLIST_DELETED, + index, AFI_IP6, + rule->rule_str); + route_map_rule_delete(&index->match_list, rule); + } /* Free route set. */ while ((rule = index->set_list.head) != NULL) @@ -948,6 +1006,8 @@ void route_map_index_delete(struct route_map_index *index, int notify) /* Free 'char *nextrm' if not NULL */ XFREE(MTYPE_ROUTE_MAP_NAME, index->nextrm); + route_map_pfx_tbl_update(RMAP_EVENT_INDEX_DELETED, index, 0, NULL); + /* Execute event hook. */ if (route_map_master.event_hook && notify) { (*route_map_master.event_hook)(index->map->name); @@ -1007,6 +1067,8 @@ route_map_index_add(struct route_map *map, enum route_map_type type, int pref) point->prev = index; } + route_map_pfx_tbl_update(RMAP_EVENT_INDEX_ADDED, index, 0, NULL); + /* Execute event hook. */ if (route_map_master.event_hook) { (*route_map_master.event_hook)(map->name); @@ -1254,6 +1316,19 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, return RMAP_COMPILE_SUCCESS; } + /* If IPv4 or IPv6 prefix-list match criteria + * has been delete to the route-map index, update + * the route-map's prefix table. + */ + if (IS_RULE_IPv4_PREFIX_LIST(match_name)) + route_map_pfx_tbl_update( + RMAP_EVENT_PLIST_DELETED, index, AFI_IP, + rule->rule_str); + else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) + route_map_pfx_tbl_update( + RMAP_EVENT_PLIST_DELETED, index, + AFI_IP6, rule->rule_str); + /* Remove the dependency of the route-map on the rule * that is being replaced. */ @@ -1282,6 +1357,38 @@ enum rmap_compile_rets route_map_add_match(struct route_map_index *index, /* Add new route match rule to linked list. */ route_map_rule_add(&index->match_list, rule); + /* If IPv4 or IPv6 prefix-list match criteria + * has been added to the route-map index, update + * the route-map's prefix table. + */ + if (IS_RULE_IPv4_PREFIX_LIST(match_name)) { + route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP, + match_arg); + } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) { + route_map_pfx_tbl_update(RMAP_EVENT_PLIST_ADDED, index, AFI_IP6, + match_arg); + } else { + /* If IPv4 match criteria has been added to the route-map + * index, check for IPv6 prefix-list match rule presence and + * remove this index from the trie node created for each of the + * prefix-entry within the prefix-list. If no IPv6 prefix-list + * match rule is present, remove this index from the IPv6 + * default route's trie node. + */ + if (IS_IPv4_RULE(match_name)) + route_map_del_plist_entries(AFI_IP6, index, NULL, NULL); + + /* If IPv6 match criteria has been added to the route-map + * index, check for IPv4 prefix-list match rule presence and + * remove this index from the trie node created for each of the + * prefix-entry within the prefix-list. If no IPv4 prefix-list + * match rule is present, remove this index from the IPv4 + * default route's trie node. + */ + else if (IS_IPv6_RULE(match_name)) + route_map_del_plist_entries(AFI_IP, index, NULL, NULL); + } + /* Execute event hook. */ if (route_map_master.event_hook) { (*route_map_master.event_hook)(index->map->name); @@ -1329,6 +1436,45 @@ enum rmap_compile_rets route_map_delete_match(struct route_map_index *index, index->map->name); route_map_rule_delete(&index->match_list, rule); + + /* If IPv4 or IPv6 prefix-list match criteria + * has been delete to the route-map index, update + * the route-map's prefix table. + */ + if (IS_RULE_IPv4_PREFIX_LIST(match_name)) { + route_map_pfx_tbl_update( + RMAP_EVENT_PLIST_DELETED, index, AFI_IP, + match_arg); + } else if (IS_RULE_IPv6_PREFIX_LIST(match_name)) { + route_map_pfx_tbl_update( + RMAP_EVENT_PLIST_DELETED, index, + AFI_IP6, match_arg); + } else { + /* If no more IPv4 match rules are present in + * this index, check for IPv6 prefix-list match + * rule presence and add this index to trie node + * created for each of the prefix-entry within + * the prefix-list. If no IPv6 prefix-list match + * rule is present, add this index to the IPv6 + * default route's trie node. + */ + if (!route_map_is_ip_rule_present(index)) + route_map_add_plist_entries( + AFI_IP6, index, NULL, NULL); + + /* If no more IPv6 match rules are present in + * this index, check for IPv4 prefix-list match + * rule presence and add this index to trie node + * created for each of the prefix-entry within + * the prefix-list. If no IPv6 prefix-list match + * rule is present, add this index to the IPv4 + * default route's trie node. + */ + if (!route_map_is_ipv6_rule_present(index)) + route_map_add_plist_entries( + AFI_IP, index, NULL, NULL); + } + return RMAP_COMPILE_SUCCESS; } /* Can't find matched rule. */ @@ -1494,6 +1640,705 @@ route_map_apply_match(struct route_map_rule_list *match_list, return ret; } +static struct list *route_map_get_index_list(struct route_node **rn, + const struct prefix *prefix, + struct route_table *table) +{ + struct route_node *tmp_rn = NULL; + + if (!(*rn)) { + *rn = route_node_match(table, prefix); + + if (!(*rn)) + return NULL; + + if ((*rn)->info) + return (struct list *)((*rn)->info); + + /* If rn->info is NULL, get the parent. + * Store the rn in tmp_rn and unlock it later. + */ + tmp_rn = *rn; + } + + do { + *rn = (*rn)->parent; + if (tmp_rn) + route_unlock_node(tmp_rn); + + if (!(*rn)) + break; + + if ((*rn)->info) { + route_lock_node(*rn); + return (struct list *)((*rn)->info); + } + } while (!(*rn)->info); + + return NULL; +} + +/* + * This function returns the route-map index that best matches the prefix. + */ +static struct route_map_index * +route_map_get_index(struct route_map *map, const struct prefix *prefix, + route_map_object_t type, void *object, uint8_t *match_ret) +{ + int ret = 0; + struct list *candidate_rmap_list = NULL; + struct route_node *rn = NULL; + struct listnode *ln = NULL, *nn = NULL; + struct route_map_index *index = NULL, *best_index = NULL; + struct route_map_index *head_index = NULL; + struct route_table *table = NULL; + unsigned char family = prefix->family; + + if (family == AF_INET) + table = map->ipv4_prefix_table; + else + table = map->ipv6_prefix_table; + + if (!table) + return NULL; + + do { + candidate_rmap_list = + route_map_get_index_list(&rn, prefix, table); + if (!rn) + break; + + /* If the index at the head of the list is of seq higher + * than that in best_index, ignore the list and get the + * parent node's list. + */ + head_index = (struct route_map_index *)(listgetdata( + listhead(candidate_rmap_list))); + if (best_index && head_index + && (best_index->pref < head_index->pref)) { + route_unlock_node(rn); + continue; + } + + for (ALL_LIST_ELEMENTS(candidate_rmap_list, ln, nn, index)) { + /* If the index is of seq higher than that in + * best_index, ignore the list and get the parent + * node's list. + */ + if (best_index && (best_index->pref < index->pref)) + break; + + ret = route_map_apply_match(&index->match_list, prefix, + type, object); + + if (ret == RMAP_MATCH) { + *match_ret = ret; + best_index = index; + break; + } else if (ret == RMAP_NOOP) { + /* + * If match_ret is denymatch, even if we see + * more noops, we retain this return value and + * return this eventually if there are no + * matches. + */ + if (*match_ret != RMAP_NOMATCH) + *match_ret = ret; + } else { + /* + * ret is RMAP_NOMATCH. + */ + *match_ret = ret; + } + } + + route_unlock_node(rn); + + } while (rn); + + return best_index; +} + +static int route_map_candidate_list_cmp(struct route_map_index *idx1, + struct route_map_index *idx2) +{ + if (!idx1) + return -1; + if (!idx2) + return 1; + + return (idx1->pref - idx2->pref); +} + +/* + * This function adds the route-map index into the default route's + * route-node in the route-map's IPv4/IPv6 prefix-table. + */ +static void route_map_pfx_table_add_default(afi_t afi, + struct route_map_index *index) +{ + struct route_node *rn = NULL; + struct list *rmap_candidate_list = NULL; + struct prefix p; + bool updated_rn = false; + struct route_table *table = NULL; + + memset(&p, 0, sizeof(p)); + p.family = afi2family(afi); + p.prefixlen = 0; + + if (p.family == AF_INET) { + table = index->map->ipv4_prefix_table; + if (!table) + index->map->ipv4_prefix_table = route_table_init(); + + table = index->map->ipv4_prefix_table; + } else { + table = index->map->ipv6_prefix_table; + if (!table) + index->map->ipv6_prefix_table = route_table_init(); + + table = index->map->ipv6_prefix_table; + } + + /* Add default route to table */ + rn = route_node_get(table, &p); + + if (!rn) + return; + + if (!rn->info) { + rmap_candidate_list = list_new(); + rmap_candidate_list->cmp = + (int (*)(void *, void *))route_map_candidate_list_cmp; + rn->info = rmap_candidate_list; + } else { + rmap_candidate_list = (struct list *)rn->info; + updated_rn = true; + } + + listnode_add_sort_nodup(rmap_candidate_list, index); + if (updated_rn) + route_unlock_node(rn); +} + +/* + * This function removes the route-map index from the default route's + * route-node in the route-map's IPv4/IPv6 prefix-table. + */ +static void route_map_pfx_table_del_default(afi_t afi, + struct route_map_index *index) +{ + struct route_node *rn = NULL; + struct list *rmap_candidate_list = NULL; + struct prefix p; + struct route_table *table = NULL; + + memset(&p, 0, sizeof(p)); + p.family = afi2family(afi); + p.prefixlen = 0; + + if (p.family == AF_INET) + table = index->map->ipv4_prefix_table; + else + table = index->map->ipv6_prefix_table; + + /* Remove RMAP index from default route in table */ + rn = route_node_lookup(table, &p); + if (!rn || !rn->info) + return; + + rmap_candidate_list = (struct list *)rn->info; + + listnode_delete(rmap_candidate_list, index); + + if (listcount(rmap_candidate_list) == 0) { + list_delete(&rmap_candidate_list); + rn->info = NULL; + route_unlock_node(rn); + } + route_unlock_node(rn); +} + +/* + * This function adds the route-map index to the route-node for + * the prefix-entry in the route-map's IPv4/IPv6 prefix-table. + */ +static void route_map_pfx_table_add(struct route_table *table, + struct route_map_index *index, + struct prefix_list_entry *pentry) +{ + struct route_node *rn = NULL; + struct list *rmap_candidate_list = NULL; + bool updated_rn = false; + + rn = route_node_get(table, &pentry->prefix); + if (!rn) + return; + + if (!rn->info) { + rmap_candidate_list = list_new(); + rmap_candidate_list->cmp = + (int (*)(void *, void *))route_map_candidate_list_cmp; + rn->info = rmap_candidate_list; + } else { + rmap_candidate_list = (struct list *)rn->info; + updated_rn = true; + } + + listnode_add_sort_nodup(rmap_candidate_list, index); + if (updated_rn) + route_unlock_node(rn); +} + +/* + * This function removes the route-map index from the route-node for + * the prefix-entry in the route-map's IPv4/IPv6 prefix-table. + */ +static void route_map_pfx_table_del(struct route_table *table, + struct route_map_index *index, + struct prefix_list_entry *pentry) +{ + struct route_node *rn = NULL; + struct list *rmap_candidate_list = NULL; + + rn = route_node_lookup(table, &pentry->prefix); + if (!rn || !rn->info) + return; + + rmap_candidate_list = (struct list *)rn->info; + + listnode_delete(rmap_candidate_list, index); + + if (listcount(rmap_candidate_list) == 0) { + list_delete(&rmap_candidate_list); + rn->info = NULL; + route_unlock_node(rn); + } + route_unlock_node(rn); +} + +/* This function checks for the presence of an IPv4 match rule + * in the given route-map index. + */ +static bool route_map_is_ip_rule_present(struct route_map_index *index) +{ + struct route_map_rule_list *match_list = NULL; + struct route_map_rule *rule = NULL; + + match_list = &index->match_list; + for (rule = match_list->head; rule; rule = rule->next) + if (IS_IPv4_RULE(rule->cmd->str)) + return true; + + return false; +} + +/* This function checks for the presence of an IPv6 match rule + * in the given route-map index. + */ +static bool route_map_is_ipv6_rule_present(struct route_map_index *index) +{ + struct route_map_rule_list *match_list = NULL; + struct route_map_rule *rule = NULL; + + match_list = &index->match_list; + for (rule = match_list->head; rule; rule = rule->next) + if (IS_IPv6_RULE(rule->cmd->str)) + return true; + + return false; +} + +/* This function does the following: + * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list + * match clause (based on the afi passed to this foo) and get the + * prefix-list name. + * 2) Look up the prefix-list using the name. + * 3) If the prefix-list is not found then, add the index to the IPv4/IPv6 + * default-route's node in the trie (based on the afi passed to this foo). + * 4) If the prefix-list is found then, remove the index from the IPv4/IPv6 + * default-route's node in the trie (based on the afi passed to this foo). + * 5) If a prefix-entry is passed then, create a route-node for this entry and + * add this index to the route-node. + * 6) If prefix-entry is not passed then, for every prefix-entry in the + * prefix-list, create a route-node for this entry and + * add this index to the route-node. + */ +static void route_map_add_plist_entries(afi_t afi, + struct route_map_index *index, + const char *plist_name, + struct prefix_list_entry *entry) +{ + struct route_map_rule_list *match_list = NULL; + struct route_map_rule *match = NULL; + struct prefix_list *plist = NULL; + struct prefix_list_entry *pentry = NULL; + bool plist_rule_is_present = false; + + if (!plist_name) { + match_list = &index->match_list; + + for (match = match_list->head; match; match = match->next) { + if (afi == AFI_IP) { + if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) { + plist_rule_is_present = true; + break; + } + } else { + if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) { + plist_rule_is_present = true; + break; + } + } + } + + if (plist_rule_is_present) + plist = prefix_list_lookup(afi, match->rule_str); + } else { + plist = prefix_list_lookup(afi, plist_name); + } + + if (!plist) { + route_map_pfx_table_add_default(afi, index); + return; + } + + route_map_pfx_table_del_default(afi, index); + + if (entry) { + if (afi == AFI_IP) { + route_map_pfx_table_add(index->map->ipv4_prefix_table, + index, entry); + } else { + route_map_pfx_table_add(index->map->ipv6_prefix_table, + index, entry); + } + } else { + for (pentry = plist->head; pentry; pentry = pentry->next) { + if (afi == AFI_IP) { + route_map_pfx_table_add( + index->map->ipv4_prefix_table, index, + pentry); + } else { + route_map_pfx_table_add( + index->map->ipv6_prefix_table, index, + pentry); + } + } + } +} + +/* This function does the following: + * 1) If plist_name is not present, search for a IPv4 or IPv6 prefix-list + * match clause (based on the afi passed to this foo) and get the + * prefix-list name. + * 2) Look up the prefix-list using the name. + * 3) If the prefix-list is not found then, delete the index from the IPv4/IPv6 + * default-route's node in the trie (based on the afi passed to this foo). + * 4) If a prefix-entry is passed then, remove this index from the route-node + * for the prefix in this prefix-entry. + * 5) If prefix-entry is not passed then, for every prefix-entry in the + * prefix-list, remove this index from the route-node + * for the prefix in this prefix-entry. + */ +static void route_map_del_plist_entries(afi_t afi, + struct route_map_index *index, + const char *plist_name, + struct prefix_list_entry *entry) +{ + struct route_map_rule_list *match_list = NULL; + struct route_map_rule *match = NULL; + struct prefix_list *plist = NULL; + struct prefix_list_entry *pentry = NULL; + bool plist_rule_is_present = false; + + if (!plist_name) { + match_list = &index->match_list; + + for (match = match_list->head; match; match = match->next) { + if (afi == AFI_IP) { + if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str)) { + plist_rule_is_present = true; + break; + } + } else { + if (IS_RULE_IPv6_PREFIX_LIST(match->cmd->str)) { + plist_rule_is_present = true; + break; + } + } + } + + if (plist_rule_is_present) + plist = prefix_list_lookup(afi, match->rule_str); + } else { + plist = prefix_list_lookup(afi, plist_name); + } + + if (!plist) { + route_map_pfx_table_del_default(afi, index); + return; + } + + if (entry) { + if (afi == AFI_IP) { + route_map_pfx_table_del(index->map->ipv4_prefix_table, + index, entry); + } else { + route_map_pfx_table_del(index->map->ipv6_prefix_table, + index, entry); + } + } else { + for (pentry = plist->head; pentry; pentry = pentry->next) { + if (afi == AFI_IP) { + route_map_pfx_table_del( + index->map->ipv4_prefix_table, index, + pentry); + } else { + route_map_pfx_table_del( + index->map->ipv6_prefix_table, index, + pentry); + } + } + } +} + +/* + * This function handles the cases where a prefix-list is added/removed + * as a match command from a particular route-map index. + * It updates the prefix-table of the route-map accordingly. + */ +static void route_map_trie_update(afi_t afi, route_map_event_t event, + struct route_map_index *index, + const char *plist_name) +{ + if (event == RMAP_EVENT_PLIST_ADDED) { + if (afi == AFI_IP) { + if (!route_map_is_ipv6_rule_present(index)) { + route_map_pfx_table_del_default(AFI_IP6, index); + route_map_add_plist_entries(afi, index, + plist_name, NULL); + } else { + route_map_del_plist_entries(AFI_IP6, index, + NULL, NULL); + } + } else { + if (!route_map_is_ip_rule_present(index)) { + route_map_pfx_table_del_default(AFI_IP, index); + route_map_add_plist_entries(afi, index, + plist_name, NULL); + } else { + route_map_del_plist_entries(AFI_IP, index, NULL, + NULL); + } + } + } else if (event == RMAP_EVENT_PLIST_DELETED) { + if (afi == AFI_IP) { + route_map_del_plist_entries(afi, index, plist_name, + NULL); + + if (!route_map_is_ipv6_rule_present(index)) + route_map_pfx_table_add_default(afi, index); + + if (!route_map_is_ip_rule_present(index)) + route_map_add_plist_entries(AFI_IP6, index, + NULL, NULL); + } else { + route_map_del_plist_entries(afi, index, plist_name, + NULL); + + if (!route_map_is_ip_rule_present(index)) + route_map_pfx_table_add_default(afi, index); + + if (!route_map_is_ipv6_rule_present(index)) + route_map_add_plist_entries(AFI_IP, index, NULL, + NULL); + } + } +} + +/* + * This function handles the cases where a route-map index and + * prefix-list is added/removed. + * It updates the prefix-table of the route-map accordingly. + */ +static void route_map_pfx_tbl_update(route_map_event_t event, + struct route_map_index *index, afi_t afi, + const char *plist_name) +{ + struct route_map *rmap = NULL; + + if (!index) + return; + + if (event == RMAP_EVENT_INDEX_ADDED) { + route_map_pfx_table_add_default(AFI_IP, index); + route_map_pfx_table_add_default(AFI_IP6, index); + return; + } + + if (event == RMAP_EVENT_INDEX_DELETED) { + route_map_pfx_table_del_default(AFI_IP, index); + route_map_pfx_table_del_default(AFI_IP6, index); + + if ((index->map->head == NULL) && (index->map->tail == NULL)) { + rmap = index->map; + + if (rmap->ipv4_prefix_table) { + route_table_finish(rmap->ipv4_prefix_table); + rmap->ipv4_prefix_table = NULL; + } + + if (rmap->ipv6_prefix_table) { + route_table_finish(rmap->ipv6_prefix_table); + rmap->ipv6_prefix_table = NULL; + } + } + return; + } + + /* Handle prefix-list match rule addition/deletion. + */ + route_map_trie_update(afi, event, index, plist_name); +} + +/* + * This function handles the cases where a new prefix-entry is added to + * a prefix-list or, an existing prefix-entry is removed from the prefix-list. + * It updates the prefix-table of the route-map accordingly. + */ +static void route_map_pentry_update(route_map_event_t event, + const char *plist_name, + struct route_map_index *index, + struct prefix_list_entry *pentry) +{ + struct prefix_list *plist = NULL; + afi_t afi; + unsigned char family = pentry->prefix.family; + + if (family == AF_INET) { + afi = AFI_IP; + plist = prefix_list_lookup(AFI_IP, plist_name); + } else { + afi = AFI_IP6; + plist = prefix_list_lookup(AFI_IP6, plist_name); + } + + if (event == RMAP_EVENT_PLIST_ADDED) { + if (plist->count == 1) { + if (afi == AFI_IP) { + if (!route_map_is_ipv6_rule_present(index)) + route_map_add_plist_entries( + afi, index, plist_name, pentry); + } else { + if (!route_map_is_ip_rule_present(index)) + route_map_add_plist_entries( + afi, index, plist_name, pentry); + } + } else { + route_map_add_plist_entries(afi, index, plist_name, + pentry); + } + } else if (event == RMAP_EVENT_PLIST_DELETED) { + route_map_del_plist_entries(afi, index, plist_name, pentry); + + if (plist->count == 1) { + if (afi == AFI_IP) { + if (!route_map_is_ipv6_rule_present(index)) + route_map_pfx_table_add_default(afi, + index); + } else { + if (!route_map_is_ip_rule_present(index)) + route_map_pfx_table_add_default(afi, + index); + } + } + } +} + +static void route_map_pentry_process_dependency(struct hash_backet *backet, + void *data) +{ + char *rmap_name = NULL; + struct route_map *rmap = NULL; + struct route_map_index *index = NULL; + struct route_map_rule_list *match_list = NULL; + struct route_map_rule *match = NULL; + struct route_map_dep_data *dep_data = NULL; + struct route_map_pentry_dep *pentry_dep = + (struct route_map_pentry_dep *)data; + unsigned char family = pentry_dep->pentry->prefix.family; + + dep_data = (struct route_map_dep_data *)backet->data; + if (!dep_data) + return; + + rmap_name = dep_data->rname; + rmap = route_map_lookup_by_name(rmap_name); + if (!rmap || !rmap->head) + return; + + for (index = rmap->head; index; index = index->next) { + match_list = &index->match_list; + + if (!match_list) + continue; + + for (match = match_list->head; match; match = match->next) { + if (strcmp(match->rule_str, pentry_dep->plist_name) + == 0) { + if (IS_RULE_IPv4_PREFIX_LIST(match->cmd->str) + && family == AF_INET) { + route_map_pentry_update( + pentry_dep->event, + pentry_dep->plist_name, index, + pentry_dep->pentry); + } else if (IS_RULE_IPv6_PREFIX_LIST( + match->cmd->str) + && family == AF_INET6) { + route_map_pentry_update( + pentry_dep->event, + pentry_dep->plist_name, index, + pentry_dep->pentry); + } + } + } + } +} + +void route_map_notify_pentry_dependencies(const char *affected_name, + struct prefix_list_entry *pentry, + route_map_event_t event) +{ + struct route_map_dep *dep = NULL; + struct hash *upd8_hash = NULL; + struct route_map_pentry_dep pentry_dep; + + if (!affected_name || !pentry) + return; + + upd8_hash = route_map_get_dep_hash(event); + if (!upd8_hash) + return; + + dep = (struct route_map_dep *)hash_get(upd8_hash, (void *)affected_name, + NULL); + if (dep) { + if (!dep->this_hash) + dep->this_hash = upd8_hash; + + memset(&pentry_dep, 0, sizeof(struct route_map_pentry_dep)); + pentry_dep.pentry = pentry; + pentry_dep.plist_name = affected_name; + pentry_dep.event = event; + + hash_iterate(dep->dep_rmap_hash, + route_map_pentry_process_dependency, + (void *)&pentry_dep); + } +} + /* Apply route map's each index to the object. The matrix for a route-map looks like this: @@ -1547,9 +2392,10 @@ route_map_result_t route_map_apply(struct route_map *map, static int recursion = 0; enum route_map_cmd_result_t match_ret = RMAP_NOMATCH; route_map_result_t ret = RMAP_PERMITMATCH; - struct route_map_index *index; - struct route_map_rule *set; + struct route_map_index *index = NULL; + struct route_map_rule *set = NULL; char buf[PREFIX_STRLEN]; + bool skip_match_clause = false; if (recursion > RMAP_RECURSION_LIMIT) { flog_warn( @@ -1566,18 +2412,55 @@ route_map_result_t route_map_apply(struct route_map *map, } map->applied++; - for (index = map->head; index; index = index->next) { - /* Apply this index. */ - index->applied++; - match_ret = route_map_apply_match(&index->match_list, prefix, - type, object); - - if (rmap_debug) { - zlog_debug("Route-map: %s, sequence: %d, prefix: %s, result: %s", - map->name, index->pref, - prefix2str(prefix, buf, sizeof(buf)), - route_map_cmd_result_str(match_ret)); + + if ((!map->optimization_disabled) + && (map->ipv4_prefix_table || map->ipv6_prefix_table)) { + index = route_map_get_index(map, prefix, type, object, + (uint8_t *)&match_ret); + if (index) { + if (rmap_debug) + zlog_debug( + "Best match route-map: %s, sequence: %d for pfx: %s, result: %s", + map->name, index->pref, + prefix2str(prefix, buf, sizeof(buf)), + route_map_cmd_result_str(match_ret)); + } else { + if (rmap_debug) + zlog_debug( + "No best match sequence for pfx: %s in route-map: %s, result: %s", + prefix2str(prefix, buf, sizeof(buf)), + map->name, + route_map_cmd_result_str(match_ret)); + /* + * No index matches this prefix. Return deny unless, + * match_ret = RMAP_NOOP. + */ + if (match_ret == RMAP_NOOP) + ret = RMAP_PERMITMATCH; + else + ret = RMAP_DENYMATCH; + goto route_map_apply_end; } + skip_match_clause = true; + } else { + index = map->head; + } + + for (; index; index = index->next) { + if (skip_match_clause == false) { + /* Apply this index. */ + match_ret = route_map_apply_match(&index->match_list, + prefix, type, object); + if (rmap_debug) { + zlog_debug( + "Route-map: %s, sequence: %d, prefix: %s, result: %s", + map->name, index->pref, + prefix2str(prefix, buf, sizeof(buf)), + route_map_cmd_result_str(match_ret)); + } + } else + skip_match_clause = false; + /* Now we apply the matrix from above */ if (match_ret == RMAP_NOOP) @@ -2025,8 +2908,30 @@ void route_map_notify_dependencies(const char *affected_name, XFREE(MTYPE_ROUTE_MAP_NAME, name); } - /* VTY related functions. */ +DEFUN(no_routemap_optimization, no_routemap_optimization_cmd, + "no route-map optimization", + NO_STR + "route-map\n" + "optimization\n") +{ + VTY_DECLVAR_CONTEXT(route_map_index, index); + + index->map->optimization_disabled = true; + return CMD_SUCCESS; +} + +DEFUN(routemap_optimization, routemap_optimization_cmd, + "route-map optimization", + "route-map\n" + "optimization\n") +{ + VTY_DECLVAR_CONTEXT(route_map_index, index); + + index->map->optimization_disabled = false; + return CMD_SUCCESS; +} + static void clear_route_map_helper(struct route_map *map) { struct route_map_index *index; @@ -2201,6 +3106,121 @@ void route_map_counter_decrement(struct route_map *map) } } +DEFUN_HIDDEN(show_route_map_pfx_tbl, show_route_map_pfx_tbl_cmd, + "show route-map WORD prefix-table", + SHOW_STR + "route-map\n" + "route-map name\n" + "internal prefix-table\n") +{ + const char *rmap_name = argv[2]->arg; + struct route_map *rmap = NULL; + struct route_table *rm_pfx_tbl4 = NULL; + struct route_table *rm_pfx_tbl6 = NULL; + struct route_node *rn = NULL, *prn = NULL; + struct list *rmap_index_list = NULL; + struct listnode *ln = NULL, *nln = NULL; + struct route_map_index *index = NULL; + struct prefix *p = NULL, *pp = NULL; + char buf[SU_ADDRSTRLEN], pbuf[SU_ADDRSTRLEN]; + uint8_t len = 54; + + vty_out(vty, "%s:\n", frr_protonameinst); + rmap = route_map_lookup_by_name(rmap_name); + if (rmap) { + rm_pfx_tbl4 = rmap->ipv4_prefix_table; + if (rm_pfx_tbl4) { + vty_out(vty, "\n%s%43s%s\n", "IPv4 Prefix", "", + "Route-map Index List"); + vty_out(vty, "%s%39s%s\n", "_______________", "", + "____________________"); + for (rn = route_top(rm_pfx_tbl4); rn; + rn = route_next(rn)) { + p = &rn->p; + + vty_out(vty, " %s/%d (%d)\n", + inet_ntop(p->family, &p->u.prefix, buf, + SU_ADDRSTRLEN), + p->prefixlen, rn->lock); + + vty_out(vty, "(P) "); + prn = rn->parent; + if (prn) { + pp = &prn->p; + vty_out(vty, "%s/%d\n", + inet_ntop(pp->family, + &pp->u.prefix, pbuf, + SU_ADDRSTRLEN), + pp->prefixlen); + } + + vty_out(vty, "\n"); + rmap_index_list = (struct list *)rn->info; + if (!rmap_index_list + || !listcount(rmap_index_list)) + vty_out(vty, "%*s%s\n", len, "", "-"); + else + for (ALL_LIST_ELEMENTS(rmap_index_list, + ln, nln, + index)) { + vty_out(vty, "%*s%s seq %d\n", + len, "", + index->map->name, + index->pref); + } + vty_out(vty, "\n"); + } + } + + rm_pfx_tbl6 = rmap->ipv6_prefix_table; + if (rm_pfx_tbl6) { + vty_out(vty, "\n%s%43s%s\n", "IPv6 Prefix", "", + "Route-map Index List"); + vty_out(vty, "%s%39s%s\n", "_______________", "", + "____________________"); + for (rn = route_top(rm_pfx_tbl6); rn; + rn = route_next(rn)) { + p = &rn->p; + + vty_out(vty, " %s/%d (%d)\n", + inet_ntop(p->family, &p->u.prefix, buf, + SU_ADDRSTRLEN), + p->prefixlen, rn->lock); + + vty_out(vty, "(P) "); + prn = rn->parent; + if (prn) { + pp = &prn->p; + vty_out(vty, "%s/%d\n", + inet_ntop(pp->family, + &pp->u.prefix, pbuf, + SU_ADDRSTRLEN), + pp->prefixlen); + } + + vty_out(vty, "\n"); + rmap_index_list = (struct list *)rn->info; + if (!rmap_index_list + || !listcount(rmap_index_list)) + vty_out(vty, "%*s%s\n", len, "", "-"); + else + for (ALL_LIST_ELEMENTS(rmap_index_list, + ln, nln, + index)) { + vty_out(vty, "%*s%s seq %d\n", + len, "", + index->map->name, + index->pref); + } + vty_out(vty, "\n"); + } + } + } + + vty_out(vty, "\n"); + return CMD_SUCCESS; +} + /* Initialization of route map vector. */ void route_map_init(void) { @@ -2237,4 +3257,9 @@ void route_map_init(void) install_element(ENABLE_NODE, &debug_rmap_cmd); install_element(ENABLE_NODE, &no_debug_rmap_cmd); + + install_element(RMAP_NODE, &routemap_optimization_cmd); + install_element(RMAP_NODE, &no_routemap_optimization_cmd); + + install_element(ENABLE_NODE, &show_route_map_pfx_tbl_cmd); } diff --git a/lib/routemap.h b/lib/routemap.h index 05c958967c..e8cab64b47 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -25,6 +25,8 @@ #include "memory.h" #include "qobj.h" #include "vty.h" +#include "lib/plist.h" +#include "lib/plist_int.h" #ifdef __cplusplus extern "C" { @@ -220,6 +222,7 @@ struct route_map { /* Maintain update info */ bool to_be_processed; /* True if modification isn't acted on yet */ bool deleted; /* If 1, then this node will be deleted */ + bool optimization_disabled; /* How many times have we applied this route-map */ uint64_t applied; @@ -228,6 +231,12 @@ struct route_map { /* Counter to track active usage of this route-map */ uint16_t use_count; + /* Tables to maintain IPv4 and IPv6 prefixes from + * the prefix-list match clause. + */ + struct route_table *ipv4_prefix_table; + struct route_table *ipv6_prefix_table; + QOBJ_FIELDS }; DECLARE_QOBJ_TYPE(route_map) @@ -310,7 +319,10 @@ extern void route_map_upd8_dependency(route_map_event_t type, const char *arg, const char *rmap_name); extern void route_map_notify_dependencies(const char *affected_name, route_map_event_t event); - +extern void +route_map_notify_pentry_dependencies(const char *affected_name, + struct prefix_list_entry *pentry, + route_map_event_t event); extern int generic_match_add(struct vty *vty, struct route_map_index *index, const char *command, const char *arg, route_map_event_t type); diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index 7023710564..5b03b5266f 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -1064,7 +1064,6 @@ void route_map_cli_init(void) install_element(CONFIG_NODE, &no_route_map_all_cmd); /* Install the on-match stuff */ - install_element(RMAP_NODE, &route_map_cmd); install_element(RMAP_NODE, &rmap_onmatch_next_cmd); install_element(RMAP_NODE, &no_rmap_onmatch_next_cmd); install_element(RMAP_NODE, &rmap_onmatch_goto_cmd); diff --git a/lib/routemap_northbound.c b/lib/routemap_northbound.c index 68b112b09a..2d04a3d65c 100644 --- a/lib/routemap_northbound.c +++ b/lib/routemap_northbound.c @@ -243,9 +243,7 @@ static int lib_route_map_entry_description_destroy(enum nb_event event, break; case NB_EV_APPLY: rmi = nb_running_get_entry(dnode, NULL, true); - if (rmi->description != NULL) - XFREE(MTYPE_TMP, rmi->description); - rmi->description = NULL; + XFREE(MTYPE_TMP, rmi->description); break; } diff --git a/lib/skiplist.c b/lib/skiplist.c index 6efa2c362d..67cc1ab378 100644 --- a/lib/skiplist.c +++ b/lib/skiplist.c @@ -378,7 +378,7 @@ int skiplist_next_value(register struct skiplist *l, /* in */ void **valuePointer, /* in/out */ void **cursor) /* in/out */ { - register int k, m; + register int k; register struct skiplistnode *p, *q; CHECKLAST(l); @@ -389,7 +389,7 @@ int skiplist_next_value(register struct skiplist *l, /* in */ if (!cursor || !*cursor) { p = l->header; - k = m = l->level; + k = l->level; /* * Find matching key diff --git a/lib/sockopt.c b/lib/sockopt.c index d6c88c0aff..52b1f0356e 100644 --- a/lib/sockopt.c +++ b/lib/sockopt.c @@ -90,12 +90,11 @@ int getsockopt_so_recvbuf(const int sock) static void *getsockopt_cmsg_data(struct msghdr *msgh, int level, int type) { struct cmsghdr *cmsg; - void *ptr = NULL; for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(msgh, cmsg)) if (cmsg->cmsg_level == level && cmsg->cmsg_type == type) - return (ptr = CMSG_DATA(cmsg)); + return CMSG_DATA(cmsg); return NULL; } @@ -114,6 +114,8 @@ extern struct vrf *vrf_get(vrf_id_t, const char *); extern const char *vrf_id_to_name(vrf_id_t vrf_id); extern vrf_id_t vrf_name_to_id(const char *); +#define VRF_LOGNAME(V) V ? V->name : "Unknown" + #define VRF_GET_ID(V, NAME, USE_JSON) \ do { \ struct vrf *_vrf; \ diff --git a/lib/zclient.c b/lib/zclient.c index 4f2ad959dc..b0d2ea43a2 100644 --- a/lib/zclient.c +++ b/lib/zclient.c @@ -2602,7 +2602,7 @@ int zebra_send_mpls_labels(struct zclient *zclient, int cmd, int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl) { - struct zapi_nexthop_label *znh; + struct zapi_nexthop *znh; stream_reset(s); @@ -2631,20 +2631,8 @@ int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl) for (int i = 0; i < zl->nexthop_num; i++) { znh = &zl->nexthops[i]; - stream_putc(s, znh->type); - stream_putw(s, znh->family); - switch (znh->family) { - case AF_INET: - stream_put_in_addr(s, &znh->address.ipv4); - break; - case AF_INET6: - stream_write(s, (uint8_t *)&znh->address.ipv6, 16); - break; - default: - break; - } - stream_putl(s, znh->ifindex); - stream_putl(s, znh->label); + if (zapi_nexthop_encode(s, znh, 0) < 0) + return -1; } /* Put length at the first point of the stream. */ @@ -2655,7 +2643,7 @@ int zapi_labels_encode(struct stream *s, int cmd, struct zapi_labels *zl) int zapi_labels_decode(struct stream *s, struct zapi_labels *zl) { - struct zapi_nexthop_label *znh; + struct zapi_nexthop *znh; memset(zl, 0, sizeof(*zl)); @@ -2719,21 +2707,8 @@ int zapi_labels_decode(struct stream *s, struct zapi_labels *zl) for (int i = 0; i < zl->nexthop_num; i++) { znh = &zl->nexthops[i]; - STREAM_GETC(s, znh->type); - STREAM_GETW(s, znh->family); - switch (znh->family) { - case AF_INET: - STREAM_GET(&znh->address.ipv4.s_addr, s, - IPV4_MAX_BYTELEN); - break; - case AF_INET6: - STREAM_GET(&znh->address.ipv6, s, 16); - break; - default: - break; - } - STREAM_GETL(s, znh->ifindex); - STREAM_GETL(s, znh->label); + if (zapi_nexthop_decode(s, znh, 0) < 0) + return -1; } return 0; diff --git a/lib/zclient.h b/lib/zclient.h index 9a230d3f34..e6f4c747e3 100644 --- a/lib/zclient.h +++ b/lib/zclient.h @@ -458,14 +458,6 @@ struct zapi_route { uint32_t tableid; }; -struct zapi_nexthop_label { - enum nexthop_types_t type; - int family; - union g_addr address; - ifindex_t ifindex; - mpls_label_t label; -}; - struct zapi_labels { uint8_t message; #define ZAPI_LABELS_FTN 0x01 @@ -476,8 +468,9 @@ struct zapi_labels { uint8_t type; unsigned short instance; } route; + uint16_t nexthop_num; - struct zapi_nexthop_label nexthops[MULTIPATH_NUM]; + struct zapi_nexthop nexthops[MULTIPATH_NUM]; }; struct zapi_pw { diff --git a/nhrpd/nhrp_peer.c b/nhrpd/nhrp_peer.c index c5e985cdac..2d6c263582 100644 --- a/nhrpd/nhrp_peer.c +++ b/nhrpd/nhrp_peer.c @@ -755,10 +755,9 @@ static void nhrp_peer_forward(struct nhrp_peer *p, if ((type == NHRP_EXTENSION_REVERSE_TRANSIT_NHS) == (packet_types[hdr->type].type == PACKET_REPLY)) { /* Check NHS list for forwarding loop */ - while ((cie = nhrp_cie_pull(&extpl, pp->hdr, - &cie_nbma, - &cie_protocol)) - != NULL) { + while (nhrp_cie_pull(&extpl, pp->hdr, + &cie_nbma, + &cie_protocol) != NULL) { if (sockunion_same(&p->vc->remote.nbma, &cie_nbma)) goto err; diff --git a/ospfd/ospf_abr.c b/ospfd/ospf_abr.c index b4690cfa42..a8dfcbb36b 100644 --- a/ospfd/ospf_abr.c +++ b/ospfd/ospf_abr.c @@ -670,8 +670,7 @@ static int ospf_abr_translate_nssa(struct ospf_area *area, struct ospf_lsa *lsa) * originate translated LSA */ - if ((new = ospf_translated_nssa_originate(area->ospf, lsa)) - == NULL) { + if (ospf_translated_nssa_originate(area->ospf, lsa) == NULL) { if (IS_DEBUG_OSPF_NSSA) zlog_debug( "ospf_abr_translate_nssa(): Could not translate " diff --git a/ospfd/ospf_dump.c b/ospfd/ospf_dump.c index dffcb930e4..a16fb81ce3 100644 --- a/ospfd/ospf_dump.c +++ b/ospfd/ospf_dump.c @@ -158,12 +158,12 @@ const char *ospf_timeval_dump(struct timeval *t, char *buf, size_t size) #define HOUR_IN_SECONDS (60*MINUTE_IN_SECONDS) #define DAY_IN_SECONDS (24*HOUR_IN_SECONDS) #define WEEK_IN_SECONDS (7*DAY_IN_SECONDS) - unsigned long w, d, h, m, s, ms, us; + unsigned long w, d, h, m, ms, us; if (!t) return "inactive"; - w = d = h = m = s = ms = us = 0; + w = d = h = m = ms = 0; memset(buf, 0, size); us = t->tv_usec; diff --git a/ospfd/ospf_opaque.c b/ospfd/ospf_opaque.c index a989b8468c..b042a06372 100644 --- a/ospfd/ospf_opaque.c +++ b/ospfd/ospf_opaque.c @@ -1557,8 +1557,8 @@ struct ospf_lsa *ospf_opaque_lsa_install(struct ospf_lsa *lsa, int rt_recalc) ospf_lsa_unlock(&oipi->lsa); oipi->lsa = ospf_lsa_lock(lsa); } - /* Register the new lsa entry and get its control info. */ - else if ((oipi = register_opaque_lsa(lsa)) == NULL) { + /* Register the new lsa entry */ + else if (register_opaque_lsa(lsa) == NULL) { flog_warn(EC_OSPF_LSA, "ospf_opaque_lsa_install: register_opaque_lsa() ?"); goto out; diff --git a/ospfd/ospf_sr.c b/ospfd/ospf_sr.c index ff2039bec8..b5a54a0bc4 100644 --- a/ospfd/ospf_sr.c +++ b/ospfd/ospf_sr.c @@ -609,7 +609,7 @@ static int compute_prefix_nhlfe(struct sr_prefix *srp) static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe) { struct zapi_labels zl = {}; - struct zapi_nexthop_label *znh; + struct zapi_nexthop *znh; if (IS_DEBUG_OSPF_SR) zlog_debug(" |- %s LSP %u/%u for %s/%u via %u", @@ -631,10 +631,10 @@ static int ospf_zebra_send_mpls_labels(int cmd, struct sr_nhlfe nhlfe) zl.nexthop_num = 1; znh = &zl.nexthops[0]; znh->type = NEXTHOP_TYPE_IPV4_IFINDEX; - znh->family = AF_INET; - znh->address.ipv4 = nhlfe.nexthop; + znh->gate.ipv4 = nhlfe.nexthop; znh->ifindex = nhlfe.ifindex; - znh->label = nhlfe.label_out; + znh->label_num = 1; + znh->labels[0] = nhlfe.label_out; return zebra_send_mpls_labels(zclient, cmd, &zl); } diff --git a/ospfd/ospf_zebra.c b/ospfd/ospf_zebra.c index 64013435f6..d415256652 100644 --- a/ospfd/ospf_zebra.c +++ b/ospfd/ospf_zebra.c @@ -1002,7 +1002,6 @@ static int ospf_distribute_list_update_timer(struct thread *thread) void ospf_distribute_list_update(struct ospf *ospf, int type, unsigned short instance) { - struct route_table *rt; struct ospf_external *ext; void **args = XCALLOC(MTYPE_OSPF_DIST_ARGS, sizeof(void *) * 2); @@ -1011,7 +1010,7 @@ void ospf_distribute_list_update(struct ospf *ospf, int type, /* External info does not exist. */ ext = ospf_external_lookup(ospf, type, instance); - if (!ext || !(rt = EXTERNAL_INFO(ext))) { + if (!ext || !EXTERNAL_INFO(ext)) { XFREE(MTYPE_OSPF_DIST_ARGS, args); return; } diff --git a/pbrd/pbr_vty.c b/pbrd/pbr_vty.c index c1922d8728..e395b7831d 100644 --- a/pbrd/pbr_vty.c +++ b/pbrd/pbr_vty.c @@ -88,8 +88,7 @@ DEFUN_NOSH(no_pbr_map, no_pbr_map_cmd, "no pbr-map PBRMAP [seq (1-700)]", DEFPY(pbr_set_table_range, pbr_set_table_range_cmd, - "[no] pbr table range (10000-4294966272)$lb (10000-4294966272)$ub", - NO_STR + "pbr table range (10000-4294966272)$lb (10000-4294966272)$ub", PBR_STR "Set table ID range\n" "Set table ID range\n" @@ -113,6 +112,19 @@ DEFPY(pbr_set_table_range, return ret; } +DEFPY(no_pbr_set_table_range, no_pbr_set_table_range_cmd, + "no pbr table range [(10000-4294966272)$lb (10000-4294966272)$ub]", + NO_STR + PBR_STR + "Set table ID range\n" + "Set table ID range\n" + "Lower bound for table ID range\n" + "Upper bound for table ID range\n") +{ + pbr_nht_set_tableid_range(PBR_NHT_DEFAULT_LOW_TABLEID, + PBR_NHT_DEFAULT_HIGH_TABLEID); + return CMD_SUCCESS; +} DEFPY(pbr_map_match_src, pbr_map_match_src_cmd, "[no] match src-ip <A.B.C.D/M|X:X::X:X/M>$prefix", @@ -854,6 +866,7 @@ void pbr_vty_init(void) install_element(CONFIG_NODE, &pbr_map_cmd); install_element(CONFIG_NODE, &no_pbr_map_cmd); install_element(CONFIG_NODE, &pbr_set_table_range_cmd); + install_element(CONFIG_NODE, &no_pbr_set_table_range_cmd); install_element(INTERFACE_NODE, &pbr_policy_cmd); install_element(PBRMAP_NODE, &pbr_map_match_src_cmd); install_element(PBRMAP_NODE, &pbr_map_match_dst_cmd); diff --git a/pimd/pim_cmd.c b/pimd/pim_cmd.c index 6508fb4453..0caf8e4f78 100644 --- a/pimd/pim_cmd.c +++ b/pimd/pim_cmd.c @@ -166,7 +166,7 @@ static void pim_if_membership_refresh(struct interface *ifp) sg.src = src->source_addr; sg.grp = grp->group_addr; pim_ifchannel_local_membership_add(ifp, - &sg); + &sg, false /*is_vxlan*/); } } /* scan group sources */ @@ -4625,6 +4625,379 @@ DEFUN (show_ip_pim_local_membership, return CMD_SUCCESS; } +DEFUN (show_ip_pim_mlag_summary, + show_ip_pim_mlag_summary_cmd, + "show ip pim mlag summary [json]", + SHOW_STR + IP_STR + PIM_STR + "MLAG\n" + "status and stats\n" + JSON_STR) +{ + bool uj = use_json(argc, argv); + char role_buf[MLAG_ROLE_STRSIZE]; + char addr_buf[INET_ADDRSTRLEN]; + + if (uj) { + json_object *json = NULL; + json_object *json_stat = NULL; + + json = json_object_new_object(); + if (router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP) + json_object_boolean_true_add(json, "mlagConnUp"); + if (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP) + json_object_boolean_true_add(json, "mlagPeerConnUp"); + if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP) + json_object_boolean_true_add(json, "mlagPeerZebraUp"); + json_object_string_add(json, "mlagRole", + mlag_role2str(router->mlag_role, + role_buf, sizeof(role_buf))); + inet_ntop(AF_INET, &router->local_vtep_ip, + addr_buf, INET_ADDRSTRLEN); + json_object_string_add(json, "localVtepIp", addr_buf); + inet_ntop(AF_INET, &router->anycast_vtep_ip, + addr_buf, INET_ADDRSTRLEN); + json_object_string_add(json, "anycastVtepIp", addr_buf); + json_object_string_add(json, "peerlinkRif", + router->peerlink_rif); + + json_stat = json_object_new_object(); + json_object_int_add(json_stat, "mlagConnFlaps", + router->mlag_stats.mlagd_session_downs); + json_object_int_add(json_stat, "mlagPeerConnFlaps", + router->mlag_stats.peer_session_downs); + json_object_int_add(json_stat, "mlagPeerZebraFlaps", + router->mlag_stats.peer_zebra_downs); + json_object_int_add(json_stat, "mrouteAddRx", + router->mlag_stats.msg.mroute_add_rx); + json_object_int_add(json_stat, "mrouteAddTx", + router->mlag_stats.msg.mroute_add_tx); + json_object_int_add(json_stat, "mrouteDelRx", + router->mlag_stats.msg.mroute_del_rx); + json_object_int_add(json_stat, "mrouteDelTx", + router->mlag_stats.msg.mroute_del_tx); + json_object_int_add(json_stat, "mlagStatusUpdates", + router->mlag_stats.msg.mlag_status_updates); + json_object_int_add(json_stat, "peerZebraStatusUpdates", + router->mlag_stats.msg.peer_zebra_status_updates); + json_object_int_add(json_stat, "pimStatusUpdates", + router->mlag_stats.msg.pim_status_updates); + json_object_int_add(json_stat, "vxlanUpdates", + router->mlag_stats.msg.vxlan_updates); + json_object_object_add(json, "connStats", json_stat); + + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + return CMD_SUCCESS; + } + + vty_out(vty, "MLAG daemon connection: %s\n", + (router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP) + ? "up" : "down"); + vty_out(vty, "MLAG peer state: %s\n", + (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP) + ? "up" : "down"); + vty_out(vty, "Zebra peer state: %s\n", + (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP) + ? "up" : "down"); + vty_out(vty, "MLAG role: %s\n", + mlag_role2str(router->mlag_role, role_buf, sizeof(role_buf))); + inet_ntop(AF_INET, &router->local_vtep_ip, + addr_buf, INET_ADDRSTRLEN); + vty_out(vty, "Local VTEP IP: %s\n", addr_buf); + inet_ntop(AF_INET, &router->anycast_vtep_ip, + addr_buf, INET_ADDRSTRLEN); + vty_out(vty, "Anycast VTEP IP: %s\n", addr_buf); + vty_out(vty, "Peerlink: %s\n", router->peerlink_rif); + vty_out(vty, "Session flaps: mlagd: %d mlag-peer: %d zebra-peer: %d\n", + router->mlag_stats.mlagd_session_downs, + router->mlag_stats.peer_session_downs, + router->mlag_stats.peer_zebra_downs); + vty_out(vty, "Message Statistics:\n"); + vty_out(vty, " mroute adds: rx: %d, tx: %d\n", + router->mlag_stats.msg.mroute_add_rx, + router->mlag_stats.msg.mroute_add_tx); + vty_out(vty, " mroute dels: rx: %d, tx: %d\n", + router->mlag_stats.msg.mroute_del_rx, + router->mlag_stats.msg.mroute_del_tx); + vty_out(vty, " peer zebra status updates: %d\n", + router->mlag_stats.msg.peer_zebra_status_updates); + vty_out(vty, " PIM status updates: %d\n", + router->mlag_stats.msg.pim_status_updates); + vty_out(vty, " VxLAN updates: %d\n", + router->mlag_stats.msg.vxlan_updates); + + return CMD_SUCCESS; +} + +static void pim_show_mlag_up_entry_detail(struct vrf *vrf, + struct vty *vty, struct pim_upstream *up, + char *src_str, char *grp_str, json_object *json) +{ + if (json) { + json_object *json_row = NULL; + json_object *own_list = NULL; + json_object *json_group = NULL; + + + json_object_object_get_ex(json, grp_str, &json_group); + if (!json_group) { + json_group = json_object_new_object(); + json_object_object_add(json, grp_str, + json_group); + } + + json_row = json_object_new_object(); + json_object_string_add(json_row, "source", src_str); + json_object_string_add(json_row, "group", grp_str); + + own_list = json_object_new_array(); + if (pim_up_mlag_is_local(up)) + json_object_array_add(own_list, + json_object_new_string("local")); + if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)) + json_object_array_add(own_list, + json_object_new_string("peer")); + if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)) + json_object_array_add( + own_list, json_object_new_string("Interface")); + json_object_object_add(json_row, "owners", own_list); + + json_object_int_add(json_row, "localCost", + pim_up_mlag_local_cost(up)); + json_object_int_add(json_row, "peerCost", + pim_up_mlag_peer_cost(up)); + if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)) + json_object_boolean_false_add(json_row, "df"); + else + json_object_boolean_true_add(json_row, "df"); + json_object_object_add(json_group, src_str, json_row); + } else { + char own_str[6]; + + own_str[0] = '\0'; + if (pim_up_mlag_is_local(up)) + strlcat(own_str, "L", sizeof(own_str)); + if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)) + strlcat(own_str, "P", sizeof(own_str)); + if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)) + strlcat(own_str, "I", sizeof(own_str)); + /* XXX - fixup, print paragraph output */ + vty_out(vty, + "%-15s %-15s %-6s %-11u %-10d %2s\n", + src_str, grp_str, own_str, + pim_up_mlag_local_cost(up), + pim_up_mlag_peer_cost(up), + PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags) + ? "n" : "y"); + } +} + +static void pim_show_mlag_up_detail(struct vrf *vrf, + struct vty *vty, const char *src_or_group, + const char *group, bool uj) +{ + char src_str[INET_ADDRSTRLEN]; + char grp_str[INET_ADDRSTRLEN]; + struct pim_upstream *up; + struct pim_instance *pim = vrf->info; + json_object *json = NULL; + + if (uj) + json = json_object_new_object(); + else + vty_out(vty, + "Source Group Owner Local-cost Peer-cost DF\n"); + + frr_each (rb_pim_upstream, &pim->upstream_head, up) { + if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER) + && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE) + && !pim_up_mlag_is_local(up)) + continue; + + pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str)); + pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str)); + /* XXX: strcmps are clearly inefficient. we should do uint comps + * here instead. + */ + if (group) { + if (strcmp(src_str, src_or_group) || + strcmp(grp_str, group)) + continue; + } else { + if (strcmp(src_str, src_or_group) && + strcmp(grp_str, src_or_group)) + continue; + } + pim_show_mlag_up_entry_detail(vrf, vty, up, + src_str, grp_str, json); + } + + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + +static void pim_show_mlag_up_vrf(struct vrf *vrf, struct vty *vty, bool uj) +{ + json_object *json = NULL; + json_object *json_row; + struct pim_upstream *up; + char src_str[INET_ADDRSTRLEN]; + char grp_str[INET_ADDRSTRLEN]; + struct pim_instance *pim = vrf->info; + json_object *json_group = NULL; + + if (uj) { + json = json_object_new_object(); + } else { + vty_out(vty, + "Source Group Owner Local-cost Peer-cost DF\n"); + } + + frr_each (rb_pim_upstream, &pim->upstream_head, up) { + if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER) + && !(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE) + && !pim_up_mlag_is_local(up)) + continue; + pim_inet4_dump("<src?>", up->sg.src, src_str, sizeof(src_str)); + pim_inet4_dump("<grp?>", up->sg.grp, grp_str, sizeof(grp_str)); + if (uj) { + json_object *own_list = NULL; + + json_object_object_get_ex(json, grp_str, &json_group); + if (!json_group) { + json_group = json_object_new_object(); + json_object_object_add(json, grp_str, + json_group); + } + + json_row = json_object_new_object(); + json_object_string_add(json_row, "vrf", vrf->name); + json_object_string_add(json_row, "source", src_str); + json_object_string_add(json_row, "group", grp_str); + + own_list = json_object_new_array(); + if (pim_up_mlag_is_local(up)) { + + json_object_array_add(own_list, + json_object_new_string("local")); + } + if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)) { + json_object_array_add(own_list, + json_object_new_string("peer")); + } + json_object_object_add(json_row, "owners", own_list); + + json_object_int_add(json_row, "localCost", + pim_up_mlag_local_cost(up)); + json_object_int_add(json_row, "peerCost", + pim_up_mlag_peer_cost(up)); + if (PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags)) + json_object_boolean_false_add(json_row, "df"); + else + json_object_boolean_true_add(json_row, "df"); + json_object_object_add(json_group, src_str, json_row); + } else { + char own_str[6]; + + own_str[0] = '\0'; + if (pim_up_mlag_is_local(up)) + strlcat(own_str, "L", sizeof(own_str)); + if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)) + strlcat(own_str, "P", sizeof(own_str)); + if (up->flags & (PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE)) + strlcat(own_str, "I", sizeof(own_str)); + vty_out(vty, + "%-15s %-15s %-6s %-11u %-10u %2s\n", + src_str, grp_str, own_str, + pim_up_mlag_local_cost(up), + pim_up_mlag_peer_cost(up), + PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags) + ? "n" : "y"); + } + } + if (uj) { + vty_out(vty, "%s\n", json_object_to_json_string_ext( + json, JSON_C_TO_STRING_PRETTY)); + json_object_free(json); + } +} + +static void pim_show_mlag_help_string(struct vty *vty, bool uj) +{ + if (!uj) { + vty_out(vty, "Owner codes:\n"); + vty_out(vty, + "L: EVPN-MLAG Entry, I:PIM-MLAG Entry, " + "P: Peer Entry\n"); + } +} + + +DEFUN(show_ip_pim_mlag_up, show_ip_pim_mlag_up_cmd, + "show ip pim [vrf NAME] mlag upstream [A.B.C.D [A.B.C.D]] [json]", + SHOW_STR + IP_STR + PIM_STR + VRF_CMD_HELP_STR + "MLAG\n" + "upstream\n" + "Unicast or Multicast address\n" + "Multicast address\n" JSON_STR) +{ + const char *src_or_group = NULL; + const char *group = NULL; + int idx = 2; + struct vrf *vrf = pim_cmd_lookup_vrf(vty, argv, argc, &idx); + bool uj = use_json(argc, argv); + + if (!vrf || !vrf->info) { + vty_out(vty, "%s: VRF or Info missing\n", __func__); + return CMD_WARNING; + } + + if (uj) + argc--; + + if (argv_find(argv, argc, "A.B.C.D", &idx)) { + src_or_group = argv[idx]->arg; + if (idx + 1 < argc) + group = argv[idx + 1]->arg; + } + + pim_show_mlag_help_string(vty, uj); + + if (src_or_group) + pim_show_mlag_up_detail(vrf, vty, src_or_group, group, uj); + else + pim_show_mlag_up_vrf(vrf, vty, uj); + + return CMD_SUCCESS; +} + + +DEFUN(show_ip_pim_mlag_up_vrf_all, show_ip_pim_mlag_up_vrf_all_cmd, + "show ip pim vrf all mlag upstream [json]", + SHOW_STR IP_STR PIM_STR VRF_CMD_HELP_STR + "MLAG\n" + "upstream\n" JSON_STR) +{ + struct vrf *vrf; + bool uj = use_json(argc, argv); + + pim_show_mlag_help_string(vty, uj); + RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { + pim_show_mlag_up_vrf(vrf, vty, uj); + } + + return CMD_SUCCESS; +} + DEFUN (show_ip_pim_neighbor, show_ip_pim_neighbor_cmd, "show ip pim [vrf NAME] neighbor [detail|WORD] [json]", @@ -5294,7 +5667,7 @@ static void pim_cmd_show_ip_multicast_helper(struct pim_instance *pim, pim = vrf->info; vty_out(vty, "Router MLAG Role: %s\n", - mlag_role2str(router->role, mlag_role, sizeof(mlag_role))); + mlag_role2str(router->mlag_role, mlag_role, sizeof(mlag_role))); vty_out(vty, "Mroute socket descriptor:"); vty_out(vty, " %d(%s)\n", pim->mroute_socket, vrf->name); @@ -10259,7 +10632,7 @@ DEFUN_HIDDEN (no_ip_pim_mlag, addr.s_addr = 0; pim_vxlan_mlag_update(true/*mlag_enable*/, - false/*peer_state*/, PIM_VXLAN_MLAG_ROLE_SECONDARY, + false/*peer_state*/, MLAG_ROLE_NONE, NULL/*peerlink*/, &addr); return CMD_SUCCESS; @@ -10299,9 +10672,9 @@ DEFUN_HIDDEN (ip_pim_mlag, idx += 2; if (!strcmp(argv[idx]->arg, "primary")) { - role = PIM_VXLAN_MLAG_ROLE_PRIMARY; + role = MLAG_ROLE_PRIMARY; } else if (!strcmp(argv[idx]->arg, "secondary")) { - role = PIM_VXLAN_MLAG_ROLE_SECONDARY; + role = MLAG_ROLE_SECONDARY; } else { vty_out(vty, "unknown MLAG role %s\n", argv[idx]->arg); return CMD_WARNING; @@ -10471,6 +10844,9 @@ void pim_cmd_init(void) install_element(VIEW_NODE, &show_ip_pim_join_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_jp_agg_cmd); install_element(VIEW_NODE, &show_ip_pim_local_membership_cmd); + install_element(VIEW_NODE, &show_ip_pim_mlag_summary_cmd); + install_element(VIEW_NODE, &show_ip_pim_mlag_up_cmd); + install_element(VIEW_NODE, &show_ip_pim_mlag_up_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_neighbor_cmd); install_element(VIEW_NODE, &show_ip_pim_neighbor_vrf_all_cmd); install_element(VIEW_NODE, &show_ip_pim_rpf_cmd); @@ -10595,6 +10971,8 @@ void pim_cmd_init(void) install_element(CONFIG_NODE, &no_debug_ssmpingd_cmd); install_element(CONFIG_NODE, &debug_pim_zebra_cmd); install_element(CONFIG_NODE, &no_debug_pim_zebra_cmd); + install_element(CONFIG_NODE, &debug_pim_mlag_cmd); + install_element(CONFIG_NODE, &no_debug_pim_mlag_cmd); install_element(CONFIG_NODE, &debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &no_debug_pim_vxlan_cmd); install_element(CONFIG_NODE, &debug_msdp_cmd); diff --git a/pimd/pim_iface.c b/pimd/pim_iface.c index c615540149..8cc720c535 100644 --- a/pimd/pim_iface.c +++ b/pimd/pim_iface.c @@ -498,6 +498,7 @@ void pim_if_addr_add(struct connected *ifc) struct pim_interface *pim_ifp; struct interface *ifp; struct in_addr ifaddr; + bool vxlan_term; zassert(ifc); @@ -635,7 +636,8 @@ void pim_if_addr_add(struct connected *ifc) address assigned, then try to create a vif_index. */ if (pim_ifp->mroute_vif_index < 0) { - pim_if_add_vif(ifp, false, false /*vxlan_term*/); + vxlan_term = pim_vxlan_is_term_dev_cfg(pim_ifp->pim, ifp); + pim_if_add_vif(ifp, false, vxlan_term); } pim_ifchannel_scan_forward_start(ifp); } @@ -730,6 +732,7 @@ void pim_if_addr_add_all(struct interface *ifp) int v4_addrs = 0; int v6_addrs = 0; struct pim_interface *pim_ifp = ifp->info; + bool vxlan_term; /* PIM/IGMP enabled ? */ @@ -768,7 +771,8 @@ void pim_if_addr_add_all(struct interface *ifp) * address assigned, then try to create a vif_index. */ if (pim_ifp->mroute_vif_index < 0) { - pim_if_add_vif(ifp, false, false /*vxlan_term*/); + vxlan_term = pim_vxlan_is_term_dev_cfg(pim_ifp->pim, ifp); + pim_if_add_vif(ifp, false, vxlan_term); } pim_ifchannel_scan_forward_start(ifp); diff --git a/pimd/pim_ifchannel.c b/pimd/pim_ifchannel.c index 22d6e6298e..2ea1f4e9a4 100644 --- a/pimd/pim_ifchannel.c +++ b/pimd/pim_ifchannel.c @@ -854,8 +854,9 @@ void pim_ifchannel_join_add(struct interface *ifp, struct in_addr neigh_addr, /* * If we are going to be a LHR, we need to note it */ - if (ch->upstream->parent && (ch->upstream->parent->flags - & PIM_UPSTREAM_FLAG_MASK_SRC_IGMP) + if (ch->upstream->parent && + (PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR( + ch->upstream->parent->flags)) && !(ch->upstream->flags & PIM_UPSTREAM_FLAG_MASK_SRC_LHR)) { pim_upstream_ref(ch->upstream, @@ -1042,11 +1043,12 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, } int pim_ifchannel_local_membership_add(struct interface *ifp, - struct prefix_sg *sg) + struct prefix_sg *sg, bool is_vxlan) { struct pim_ifchannel *ch, *starch; struct pim_interface *pim_ifp; struct pim_instance *pim; + int up_flags; /* PIM enabled on interface? */ pim_ifp = ifp->info; @@ -1080,7 +1082,9 @@ int pim_ifchannel_local_membership_add(struct interface *ifp, } } - ch = pim_ifchannel_add(ifp, sg, 0, PIM_UPSTREAM_FLAG_MASK_SRC_IGMP); + up_flags = is_vxlan ? PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM : + PIM_UPSTREAM_FLAG_MASK_SRC_IGMP; + ch = pim_ifchannel_add(ifp, sg, 0, up_flags); ifmembership_set(ch, PIM_IFMEMBERSHIP_INCLUDE); diff --git a/pimd/pim_ifchannel.h b/pimd/pim_ifchannel.h index b36c3236b0..3d5cbd8ecf 100644 --- a/pimd/pim_ifchannel.h +++ b/pimd/pim_ifchannel.h @@ -130,7 +130,7 @@ void pim_ifchannel_prune(struct interface *ifp, struct in_addr upstream, struct prefix_sg *sg, uint8_t source_flags, uint16_t holdtime); int pim_ifchannel_local_membership_add(struct interface *ifp, - struct prefix_sg *sg); + struct prefix_sg *sg, bool is_vxlan); void pim_ifchannel_local_membership_del(struct interface *ifp, struct prefix_sg *sg); diff --git a/pimd/pim_instance.h b/pimd/pim_instance.h index da0c75decb..7b1fd2e172 100644 --- a/pimd/pim_instance.h +++ b/pimd/pim_instance.h @@ -48,6 +48,46 @@ enum pim_spt_switchover { PIM_SPT_INFINITY, }; +/* stats for updates rxed from the MLAG component during the life of a + * session + */ +struct pim_mlag_msg_stats { + uint32_t mroute_add_rx; + uint32_t mroute_add_tx; + uint32_t mroute_del_rx; + uint32_t mroute_del_tx; + uint32_t mlag_status_updates; + uint32_t pim_status_updates; + uint32_t vxlan_updates; + uint32_t peer_zebra_status_updates; +}; + +struct pim_mlag_stats { + /* message stats are reset when the connection to mlagd flaps */ + struct pim_mlag_msg_stats msg; + uint32_t mlagd_session_downs; + uint32_t peer_session_downs; + uint32_t peer_zebra_downs; +}; + +enum pim_mlag_flags { + PIM_MLAGF_NONE = 0, + /* connection to the local MLAG daemon is up */ + PIM_MLAGF_LOCAL_CONN_UP = (1 << 0), + /* connection to the MLAG daemon on the peer switch is up. note + * that there is no direct connection between FRR and the peer MLAG + * daemon. this is just a peer-session status provided by the local + * MLAG daemon. + */ + PIM_MLAGF_PEER_CONN_UP = (1 << 1), + /* status update rxed from the local daemon */ + PIM_MLAGF_STATUS_RXED = (1 << 2), + /* initial dump of data done post peerlink flap */ + PIM_MLAGF_PEER_REPLAY_DONE = (1 << 3), + /* zebra is up on the peer */ + PIM_MLAGF_PEER_ZEBRA_UP = (1 << 4) +}; + struct pim_router { struct thread_master *master; @@ -65,7 +105,7 @@ struct pim_router { */ vrf_id_t vrf_id; - enum mlag_role role; + enum mlag_role mlag_role; uint32_t pim_mlag_intf_cnt; /* if true we have registered with MLAG */ bool mlag_process_register; @@ -77,6 +117,12 @@ struct pim_router { struct stream_fifo *mlag_fifo; struct stream *mlag_stream; struct thread *zpthread_mlag_write; + struct in_addr anycast_vtep_ip; + struct in_addr local_vtep_ip; + struct pim_mlag_stats mlag_stats; + enum pim_mlag_flags mlag_flags; + char peerlink_rif[INTERFACE_NAMSIZ]; + struct interface *peerlink_rif_p; }; /* Per VRF PIM DB */ diff --git a/pimd/pim_mlag.c b/pimd/pim_mlag.c index f60c18204b..1c2f7c563d 100644 --- a/pimd/pim_mlag.c +++ b/pimd/pim_mlag.c @@ -25,14 +25,462 @@ #include "pimd.h" #include "pim_mlag.h" +#include "pim_upstream.h" +#include "pim_vxlan.h" extern struct zclient *zclient; +#define PIM_MLAG_METADATA_LEN 4 + +/******************************* pim upstream sync **************************/ +/* Update DF role for the upstream entry and return true on role change */ +bool pim_mlag_up_df_role_update(struct pim_instance *pim, + struct pim_upstream *up, bool is_df, const char *reason) +{ + struct channel_oil *c_oil = up->channel_oil; + bool old_is_df = !PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags); + struct pim_interface *vxlan_ifp; + + if (is_df == old_is_df) { + if (PIM_DEBUG_MLAG) + zlog_debug( + "%s: Ignoring Role update for %s, since no change", + __func__, up->sg_str); + return false; + } + + if (PIM_DEBUG_MLAG) + zlog_debug("local MLAG mroute %s role changed to %s based on %s", + up->sg_str, is_df ? "df" : "non-df", reason); + + if (is_df) + PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(up->flags); + else + PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(up->flags); + + + /* If the DF role has changed check if ipmr-lo needs to be + * muted/un-muted. Active-Active devices and vxlan termination + * devices (ipmr-lo) are suppressed on the non-DF. + * This may leave the mroute with the empty OIL in which case the + * the forwarding entry's sole purpose is to just blackhole the flow + * headed to the switch. + */ + if (c_oil) { + vxlan_ifp = pim_vxlan_get_term_ifp(pim); + if (vxlan_ifp) + pim_channel_update_oif_mute(c_oil, vxlan_ifp); + } + + /* If DF role changed on a (*,G) termination mroute update the + * associated DF role on the inherited (S,G) entries + */ + if ((up->sg.src.s_addr == INADDR_ANY) && + PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags)) + pim_vxlan_inherit_mlag_flags(pim, up, true /* inherit */); + + return true; +} + +/* Run per-upstream entry DF election and return true on role change */ +static bool pim_mlag_up_df_role_elect(struct pim_instance *pim, + struct pim_upstream *up) +{ + bool is_df; + uint32_t peer_cost; + uint32_t local_cost; + bool rv; + + if (!pim_up_mlag_is_local(up)) + return false; + + /* We are yet to rx a status update from the local MLAG daemon so + * we will assume DF status. + */ + if (!(router->mlag_flags & PIM_MLAGF_STATUS_RXED)) + return pim_mlag_up_df_role_update(pim, up, + true /*is_df*/, "mlagd-down"); + + /* If not connected to peer assume DF role on the MLAG primary + * switch (and non-DF on the secondary switch. + */ + if (!(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)) { + is_df = (router->mlag_role == MLAG_ROLE_PRIMARY) ? true : false; + return pim_mlag_up_df_role_update(pim, up, + is_df, "peer-down"); + } + + /* If MLAG peer session is up but zebra is down on the peer + * assume DF role. + */ + if (!(router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)) + return pim_mlag_up_df_role_update(pim, up, + true /*is_df*/, "zebra-down"); + + /* If we are connected to peer switch but don't have a mroute + * from it we have to assume non-DF role to avoid duplicates. + * Note: When the peer connection comes up we wait for initial + * replay to complete before moving "strays" i.e. local-mlag-mroutes + * without a peer reference to non-df role. + */ + if (!PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)) + return pim_mlag_up_df_role_update(pim, up, + false /*is_df*/, "no-peer-mroute"); + + /* switch with the lowest RPF cost wins. if both switches have the same + * cost MLAG role is used as a tie breaker (MLAG primary wins). + */ + peer_cost = up->mlag.peer_mrib_metric; + local_cost = pim_up_mlag_local_cost(up); + if (local_cost == peer_cost) { + is_df = (router->mlag_role == MLAG_ROLE_PRIMARY) ? true : false; + rv = pim_mlag_up_df_role_update(pim, up, is_df, "equal-cost"); + } else { + is_df = (local_cost < peer_cost) ? true : false; + rv = pim_mlag_up_df_role_update(pim, up, is_df, "cost"); + } + + return rv; +} + +/* Handle upstream entry add from the peer MLAG switch - + * - if a local entry doesn't exist one is created with reference + * _MLAG_PEER + * - if a local entry exists and has a MLAG OIF DF election is run. + * the non-DF switch stop forwarding traffic to MLAG devices. + */ +static void pim_mlag_up_peer_add(struct mlag_mroute_add *msg) +{ + struct pim_upstream *up; + struct pim_instance *pim; + int flags = 0; + struct prefix_sg sg; + struct vrf *vrf; + char sg_str[PIM_SG_LEN]; + + memset(&sg, 0, sizeof(struct prefix_sg)); + sg.src.s_addr = htonl(msg->source_ip); + sg.grp.s_addr = htonl(msg->group_ip); + if (PIM_DEBUG_MLAG) + pim_str_sg_set(&sg, sg_str); + + if (PIM_DEBUG_MLAG) + zlog_debug("peer MLAG mroute add %s:%s cost %d", + msg->vrf_name, sg_str, msg->cost_to_rp); + + /* XXX - this is not correct. we MUST cache updates to avoid losing + * an entry because of race conditions with the peer switch. + */ + vrf = vrf_lookup_by_name(msg->vrf_name); + if (!vrf) { + if (PIM_DEBUG_MLAG) + zlog_debug("peer MLAG mroute add failed %s:%s; no vrf", + msg->vrf_name, sg_str); + return; + } + pim = vrf->info; + + up = pim_upstream_find(pim, &sg); + if (up) { + /* upstream already exists; create peer reference if it + * doesn't already exist. + */ + if (!PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)) + pim_upstream_ref(up, + PIM_UPSTREAM_FLAG_MASK_MLAG_PEER, + __PRETTY_FUNCTION__); + } else { + PIM_UPSTREAM_FLAG_SET_MLAG_PEER(flags); + up = pim_upstream_add(pim, &sg, NULL /*iif*/, flags, + __PRETTY_FUNCTION__, NULL /*if_ch*/); + + if (!up) { + if (PIM_DEBUG_MLAG) + zlog_debug("peer MLAG mroute add failed %s:%s", + vrf->name, sg_str); + return; + } + } + up->mlag.peer_mrib_metric = msg->cost_to_rp; + pim_mlag_up_df_role_elect(pim, up); +} + +/* Handle upstream entry del from the peer MLAG switch - + * - peer reference is removed. this can result in the upstream + * being deleted altogether. + * - if a local entry continues to exisy and has a MLAG OIF DF election + * is re-run (at the end of which the local entry will be the DF). + */ +static void pim_mlag_up_peer_deref(struct pim_instance *pim, + struct pim_upstream *up) +{ + if (!PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)) + return; + + PIM_UPSTREAM_FLAG_UNSET_MLAG_PEER(up->flags); + up = pim_upstream_del(pim, up, __PRETTY_FUNCTION__); + if (up) + pim_mlag_up_df_role_elect(pim, up); +} +static void pim_mlag_up_peer_del(struct mlag_mroute_del *msg) +{ + struct pim_upstream *up; + struct pim_instance *pim; + struct prefix_sg sg; + struct vrf *vrf; + char sg_str[PIM_SG_LEN]; + + memset(&sg, 0, sizeof(struct prefix_sg)); + sg.src.s_addr = htonl(msg->source_ip); + sg.grp.s_addr = htonl(msg->group_ip); + if (PIM_DEBUG_MLAG) + pim_str_sg_set(&sg, sg_str); + + if (PIM_DEBUG_MLAG) + zlog_debug("peer MLAG mroute del %s:%s", msg->vrf_name, + sg_str); + + vrf = vrf_lookup_by_name(msg->vrf_name); + if (!vrf) { + if (PIM_DEBUG_MLAG) + zlog_debug("peer MLAG mroute del skipped %s:%s; no vrf", + msg->vrf_name, sg_str); + return; + } + pim = vrf->info; + + up = pim_upstream_find(pim, &sg); + if (!up) { + if (PIM_DEBUG_MLAG) + zlog_debug("peer MLAG mroute del skipped %s:%s; no up", + vrf->name, sg_str); + return; + } + + pim_mlag_up_peer_deref(pim, up); +} + +/* When we lose connection to the local MLAG daemon we can drop all peer + * references. + */ +static void pim_mlag_up_peer_del_all(void) +{ + struct list *temp = list_new(); + struct pim_upstream *up; + struct vrf *vrf; + struct pim_instance *pim; + + /* + * So why these gyrations? + * pim->upstream_head has the list of *,G and S,G + * that are in the system. The problem of course + * is that it is an ordered list: + * (*,G1) -> (S1,G1) -> (S2,G2) -> (S3, G2) -> (*,G2) -> (S1,G2) + * And the *,G1 has pointers to S1,G1 and S2,G1 + * if we delete *,G1 then we have a situation where + * S1,G1 and S2,G2 can be deleted as well. Then a + * simple ALL_LIST_ELEMENTS will have the next listnode + * pointer become invalid and we crash. + * So let's grab the list of MLAG_PEER upstreams + * add a refcount put on another list and delete safely + */ + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { + pim = vrf->info; + frr_each (rb_pim_upstream, &pim->upstream_head, up) { + if (!PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(up->flags)) + continue; + listnode_add(temp, up); + /* + * Add a reference since we are adding to this + * list for deletion + */ + up->ref_count++; + } + + while (temp->count) { + up = listnode_head(temp); + listnode_delete(temp, up); + + pim_mlag_up_peer_deref(pim, up); + /* + * This is the deletion of the reference added + * above + */ + pim_upstream_del(pim, up, __PRETTY_FUNCTION__); + } + } + + list_delete(&temp); +} + +static int pim_mlag_signal_zpthread(void) +{ + /* XXX - This is a temporary stub; the MLAG thread code is planned for + * a separate commit + */ + return (0); +} + +/* Send upstream entry to the local MLAG daemon (which will subsequently + * send it to the peer MLAG switch). + */ +static void pim_mlag_up_local_add_send(struct pim_instance *pim, + struct pim_upstream *up) +{ + struct stream *s = NULL; + struct vrf *vrf = pim->vrf; + + if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) + return; + + s = stream_new(sizeof(struct mlag_mroute_add) + PIM_MLAG_METADATA_LEN); + if (!s) + return; + + if (PIM_DEBUG_MLAG) + zlog_debug("local MLAG mroute add %s:%s", + vrf->name, up->sg_str); + + ++router->mlag_stats.msg.mroute_add_tx; + + stream_putl(s, MLAG_MROUTE_ADD); + stream_put(s, vrf->name, VRF_NAMSIZ); + stream_putl(s, ntohl(up->sg.src.s_addr)); + stream_putl(s, ntohl(up->sg.grp.s_addr)); + + stream_putl(s, pim_up_mlag_local_cost(up)); + /* XXX - who is addding*/ + stream_putl(s, MLAG_OWNER_VXLAN); + /* XXX - am_i_DR field should be removed */ + stream_putc(s, false); + stream_putc(s, !(PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->flags))); + stream_putl(s, vrf->vrf_id); + /* XXX - this field is a No-op for VXLAN*/ + stream_put(s, NULL, INTERFACE_NAMSIZ); + + stream_fifo_push_safe(router->mlag_fifo, s); + pim_mlag_signal_zpthread(); +} + +static void pim_mlag_up_local_del_send(struct pim_instance *pim, + struct pim_upstream *up) +{ + struct stream *s = NULL; + struct vrf *vrf = pim->vrf; + + if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) + return; + + s = stream_new(sizeof(struct mlag_mroute_del) + PIM_MLAG_METADATA_LEN); + if (!s) + return; + + if (PIM_DEBUG_MLAG) + zlog_debug("local MLAG mroute del %s:%s", + vrf->name, up->sg_str); + + ++router->mlag_stats.msg.mroute_del_tx; + + stream_putl(s, MLAG_MROUTE_DEL); + stream_put(s, vrf->name, VRF_NAMSIZ); + stream_putl(s, ntohl(up->sg.src.s_addr)); + stream_putl(s, ntohl(up->sg.grp.s_addr)); + /* XXX - who is adding */ + stream_putl(s, MLAG_OWNER_VXLAN); + stream_putl(s, vrf->vrf_id); + /* XXX - this field is a No-op for VXLAN */ + stream_put(s, NULL, INTERFACE_NAMSIZ); + + /* XXX - is this the the most optimal way to do things */ + stream_fifo_push_safe(router->mlag_fifo, s); + pim_mlag_signal_zpthread(); +} + + +/* Called when a local upstream entry is created or if it's cost changes */ +void pim_mlag_up_local_add(struct pim_instance *pim, + struct pim_upstream *up) +{ + pim_mlag_up_df_role_elect(pim, up); + /* XXX - need to add some dup checks here */ + pim_mlag_up_local_add_send(pim, up); +} + +/* Called when local MLAG reference is removed from an upstream entry */ +void pim_mlag_up_local_del(struct pim_instance *pim, + struct pim_upstream *up) +{ + pim_mlag_up_df_role_elect(pim, up); + pim_mlag_up_local_del_send(pim, up); +} + +/* When connection to local MLAG daemon is established all the local + * MLAG upstream entries are replayed to it. + */ +static void pim_mlag_up_local_replay(void) +{ + struct pim_upstream *up; + struct vrf *vrf; + struct pim_instance *pim; + + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { + pim = vrf->info; + frr_each (rb_pim_upstream, &pim->upstream_head, up) { + if (pim_up_mlag_is_local(up)) + pim_mlag_up_local_add_send(pim, up); + } + } +} + +/* on local/peer mlag connection and role changes the DF status needs + * to be re-evaluated + */ +static void pim_mlag_up_local_reeval(bool mlagd_send, const char *reason_code) +{ + struct pim_upstream *up; + struct vrf *vrf; + struct pim_instance *pim; + + if (PIM_DEBUG_MLAG) + zlog_debug("%s re-run DF election because of %s", + __func__, reason_code); + RB_FOREACH(vrf, vrf_name_head, &vrfs_by_name) { + pim = vrf->info; + frr_each (rb_pim_upstream, &pim->upstream_head, up) { + if (!pim_up_mlag_is_local(up)) + continue; + /* if role changes re-send to peer */ + if (pim_mlag_up_df_role_elect(pim, up) && + mlagd_send) + pim_mlag_up_local_add_send(pim, up); + } + } +} + +/*****************PIM Actions for MLAG state changes**********************/ + +/* notify the anycast VTEP component about state changes */ +static inline void pim_mlag_vxlan_state_update(void) +{ + bool enable = !!(router->mlag_flags & PIM_MLAGF_STATUS_RXED); + bool peer_state = !!(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP); + + pim_vxlan_mlag_update(enable, peer_state, router->mlag_role, + router->peerlink_rif_p, &router->local_vtep_ip); + +} + +/**************End of PIM Actions for MLAG State changes******************/ + /********************API to process PIM MLAG Data ************************/ static void pim_mlag_process_mlagd_state_change(struct mlag_status msg) { + bool role_chg = false; + bool state_chg = false; + bool notify_vxlan = false; + struct interface *peerlink_rif_p; char buf[MLAG_ROLE_STRSIZE]; if (PIM_DEBUG_MLAG) @@ -41,6 +489,84 @@ static void pim_mlag_process_mlagd_state_change(struct mlag_status msg) mlag_role2str(msg.my_role, buf, sizeof(buf)), (msg.peer_state == MLAG_STATE_RUNNING ? "RUNNING" : "DOWN")); + + if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) { + if (PIM_DEBUG_MLAG) + zlog_debug("%s: msg ignored mlagd process state down", + __func__); + return; + } + ++router->mlag_stats.msg.mlag_status_updates; + + /* evaluate the changes first */ + if (router->mlag_role != msg.my_role) { + role_chg = true; + notify_vxlan = true; + router->mlag_role = msg.my_role; + } + + strcpy(router->peerlink_rif, msg.peerlink_rif); + /* XXX - handle the case where we may rx the interface name from the + * MLAG daemon before we get the interface from zebra. + */ + peerlink_rif_p = if_lookup_by_name(router->peerlink_rif, VRF_DEFAULT); + if (router->peerlink_rif_p != peerlink_rif_p) { + router->peerlink_rif_p = peerlink_rif_p; + notify_vxlan = true; + } + + if (msg.peer_state == MLAG_STATE_RUNNING) { + if (!(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)) { + state_chg = true; + notify_vxlan = true; + router->mlag_flags |= PIM_MLAGF_PEER_CONN_UP; + } + router->connected_to_mlag = true; + } else { + if (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP) { + ++router->mlag_stats.peer_session_downs; + state_chg = true; + notify_vxlan = true; + router->mlag_flags &= ~PIM_MLAGF_PEER_CONN_UP; + } + router->connected_to_mlag = false; + } + + /* apply the changes */ + /* when connection to mlagd comes up we hold send mroutes till we have + * rxed the status and had a chance to re-valuate DF state + */ + if (!(router->mlag_flags & PIM_MLAGF_STATUS_RXED)) { + router->mlag_flags |= PIM_MLAGF_STATUS_RXED; + pim_mlag_vxlan_state_update(); + /* on session up re-eval DF status */ + pim_mlag_up_local_reeval(false /*mlagd_send*/, "mlagd_up"); + /* replay all the upstream entries to the local MLAG daemon */ + pim_mlag_up_local_replay(); + return; + } + + if (notify_vxlan) + pim_mlag_vxlan_state_update(); + + if (state_chg) { + if (!(router->mlag_flags & PIM_MLAGF_PEER_CONN_UP)) + /* when a connection goes down the primary takes over + * DF role for all entries + */ + pim_mlag_up_local_reeval(true /*mlagd_send*/, + "peer_down"); + else + /* XXX - when session comes up we need to wait for + * PEER_REPLAY_DONE before running re-election on + * local-mlag entries that are missing peer reference + */ + pim_mlag_up_local_reeval(true /*mlagd_send*/, + "peer_up"); + } else if (role_chg) { + /* MLAG role changed without a state change */ + pim_mlag_up_local_reeval(true /*mlagd_send*/, "role_chg"); + } } static void pim_mlag_process_peer_frr_state_change(struct mlag_frr_status msg) @@ -49,37 +575,116 @@ static void pim_mlag_process_peer_frr_state_change(struct mlag_frr_status msg) zlog_debug( "%s: msg dump: peer_frr_state: %s", __func__, (msg.frr_state == MLAG_FRR_STATE_UP ? "UP" : "DOWN")); + + if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) { + if (PIM_DEBUG_MLAG) + zlog_debug("%s: msg ignored mlagd process state down", + __func__); + return; + } + ++router->mlag_stats.msg.peer_zebra_status_updates; + + /* evaluate the changes first */ + if (msg.frr_state == MLAG_FRR_STATE_UP) { + if (!(router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP)) { + router->mlag_flags |= PIM_MLAGF_PEER_ZEBRA_UP; + /* XXX - when peer zebra comes up we need to wait for + * for some time to let the peer setup MDTs before + * before relinquishing DF status + */ + pim_mlag_up_local_reeval(true /*mlagd_send*/, + "zebra_up"); + } + } else { + if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP) { + ++router->mlag_stats.peer_zebra_downs; + router->mlag_flags &= ~PIM_MLAGF_PEER_ZEBRA_UP; + /* when a peer zebra goes down we assume DF role */ + pim_mlag_up_local_reeval(true /*mlagd_send*/, + "zebra_down"); + } + } } static void pim_mlag_process_vxlan_update(struct mlag_vxlan *msg) { + char addr_buf1[INET_ADDRSTRLEN]; + char addr_buf2[INET_ADDRSTRLEN]; + uint32_t local_ip; + + if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) { + if (PIM_DEBUG_MLAG) + zlog_debug("%s: msg ignored mlagd process state down", + __func__); + return; + } + + ++router->mlag_stats.msg.vxlan_updates; + router->anycast_vtep_ip.s_addr = htonl(msg->anycast_ip); + local_ip = htonl(msg->local_ip); + if (router->local_vtep_ip.s_addr != local_ip) { + router->local_vtep_ip.s_addr = local_ip; + pim_mlag_vxlan_state_update(); + } + + if (PIM_DEBUG_MLAG) { + inet_ntop(AF_INET, &router->local_vtep_ip, + addr_buf1, INET_ADDRSTRLEN); + inet_ntop(AF_INET, &router->anycast_vtep_ip, + addr_buf2, INET_ADDRSTRLEN); + + zlog_debug("%s: msg dump: local-ip:%s, anycast-ip:%s", + __func__, addr_buf1, addr_buf2); + } } static void pim_mlag_process_mroute_add(struct mlag_mroute_add msg) { if (PIM_DEBUG_MLAG) { zlog_debug( - "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x cost: %u", - __func__, msg.vrf_name, msg.source_ip, msg.group_ip, - msg.cost_to_rp); + "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x cost: %u", + __func__, msg.vrf_name, msg.source_ip, + msg.group_ip, msg.cost_to_rp); zlog_debug( - "owner_id: %d, DR: %d, Dual active: %d, vrf_id: 0x%x intf_name: %s", - msg.owner_id, msg.am_i_dr, msg.am_i_dual_active, - msg.vrf_id, msg.intf_name); + "owner_id: %d, DR: %d, Dual active: %d, vrf_id: 0x%x intf_name: %s", + msg.owner_id, msg.am_i_dr, msg.am_i_dual_active, + msg.vrf_id, msg.intf_name); + } + + if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) { + if (PIM_DEBUG_MLAG) + zlog_debug("%s: msg ignored mlagd process state down", + __func__); + return; } + + ++router->mlag_stats.msg.mroute_add_rx; + + pim_mlag_up_peer_add(&msg); } static void pim_mlag_process_mroute_del(struct mlag_mroute_del msg) { if (PIM_DEBUG_MLAG) { zlog_debug( - "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x ", - __func__, msg.vrf_name, msg.source_ip, msg.group_ip); + "%s: msg dump: vrf_name: %s, s.ip: 0x%x, g.ip: 0x%x ", + __func__, msg.vrf_name, msg.source_ip, + msg.group_ip); zlog_debug("owner_id: %d, vrf_id: 0x%x intf_name: %s", - msg.owner_id, msg.vrf_id, msg.intf_name); + msg.owner_id, msg.vrf_id, msg.intf_name); } -} + if (!(router->mlag_flags & PIM_MLAGF_LOCAL_CONN_UP)) { + if (PIM_DEBUG_MLAG) + zlog_debug("%s: msg ignored mlagd process state down", + __func__); + return; + } + + ++router->mlag_stats.msg.mroute_del_rx; + + pim_mlag_up_peer_del(&msg); +} int pim_zebra_mlag_handle_msg(struct stream *s, int len) { @@ -179,11 +784,40 @@ int pim_zebra_mlag_process_up(void) return 0; } +static void pim_mlag_param_reset(void) +{ + /* reset the cached params and stats */ + router->mlag_flags &= ~(PIM_MLAGF_STATUS_RXED | + PIM_MLAGF_LOCAL_CONN_UP | + PIM_MLAGF_PEER_CONN_UP | + PIM_MLAGF_PEER_ZEBRA_UP); + router->local_vtep_ip.s_addr = INADDR_ANY; + router->anycast_vtep_ip.s_addr = INADDR_ANY; + router->mlag_role = MLAG_ROLE_NONE; + memset(&router->mlag_stats.msg, 0, sizeof(router->mlag_stats.msg)); + router->peerlink_rif[0] = '\0'; +} + int pim_zebra_mlag_process_down(void) { if (PIM_DEBUG_MLAG) zlog_debug("%s: Received Process-Down from Mlag", __func__); + /* Local CLAG is down, reset peer data and forward the traffic if + * we are DR + */ + if (router->mlag_flags & PIM_MLAGF_PEER_CONN_UP) + ++router->mlag_stats.peer_session_downs; + if (router->mlag_flags & PIM_MLAGF_PEER_ZEBRA_UP) + ++router->mlag_stats.peer_zebra_downs; + router->connected_to_mlag = false; + pim_mlag_param_reset(); + /* on mlagd session down re-eval DF status */ + pim_mlag_up_local_reeval(false /*mlagd_send*/, "mlagd_down"); + /* flush all peer references */ + pim_mlag_up_peer_del_all(); + /* notify the vxlan component */ + pim_mlag_vxlan_state_update(); return 0; } @@ -339,6 +973,7 @@ void pim_instance_mlag_terminate(struct pim_instance *pim) void pim_mlag_init(void) { + pim_mlag_param_reset(); router->pim_mlag_intf_cnt = 0; router->connected_to_mlag = false; router->mlag_fifo = stream_fifo_new(); diff --git a/pimd/pim_mlag.h b/pimd/pim_mlag.h index e86fdae78f..dab29cc9a2 100644 --- a/pimd/pim_mlag.h +++ b/pimd/pim_mlag.h @@ -37,4 +37,10 @@ extern void pim_mlag_deregister(void); extern int pim_zebra_mlag_process_up(void); extern int pim_zebra_mlag_process_down(void); extern int pim_zebra_mlag_handle_msg(struct stream *msg, int len); +extern void pim_mlag_up_local_add(struct pim_instance *pim, + struct pim_upstream *upstream); +extern void pim_mlag_up_local_del(struct pim_instance *pim, + struct pim_upstream *upstream); +extern bool pim_mlag_up_df_role_update(struct pim_instance *pim, + struct pim_upstream *up, bool is_df, const char *reason); #endif diff --git a/pimd/pim_mroute.c b/pimd/pim_mroute.c index 3459abbc19..4afd05ab76 100644 --- a/pimd/pim_mroute.c +++ b/pimd/pim_mroute.c @@ -262,7 +262,7 @@ static int pim_mroute_msg_wholepkt(int fd, struct interface *ifp, up = pim_upstream_find(pim_ifp->pim, &star); - if (up && PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) { + if (up && PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) { up = pim_upstream_add(pim_ifp->pim, &sg, ifp, PIM_UPSTREAM_FLAG_MASK_SRC_LHR, __PRETTY_FUNCTION__, NULL); diff --git a/pimd/pim_nht.c b/pimd/pim_nht.c index 5cb9492ec3..9efeeaee27 100644 --- a/pimd/pim_nht.c +++ b/pimd/pim_nht.c @@ -561,6 +561,13 @@ static int pim_ecmp_nexthop_search(struct pim_instance *pim, "%s: current nexthop does not have nbr ", __PRETTY_FUNCTION__); } else { + /* update metric even if the upstream + * neighbor stays unchanged + */ + nexthop->mrib_metric_preference = + pnc->distance; + nexthop->mrib_route_metric = + pnc->metric; if (PIM_DEBUG_PIM_NHT) { char src_str[INET_ADDRSTRLEN]; pim_inet4_dump("<addr?>", diff --git a/pimd/pim_rpf.c b/pimd/pim_rpf.c index 24519adb1e..b27374e302 100644 --- a/pimd/pim_rpf.c +++ b/pimd/pim_rpf.c @@ -36,6 +36,7 @@ #include "pim_time.h" #include "pim_nht.h" #include "pim_oil.h" +#include "pim_mlag.h" static struct in_addr pim_rpf_find_rpf_addr(struct pim_upstream *up); @@ -194,6 +195,32 @@ static int nexthop_mismatch(const struct pim_nexthop *nh1, || (nh1->mrib_route_metric != nh2->mrib_route_metric); } +static void pim_rpf_cost_change(struct pim_instance *pim, + struct pim_upstream *up, uint32_t old_cost) +{ + struct pim_rpf *rpf = &up->rpf; + uint32_t new_cost; + + new_cost = pim_up_mlag_local_cost(up); + if (PIM_DEBUG_MLAG) + zlog_debug( + "%s: Cost_to_rp of upstream-%s changed to:%u, from:%u", + __func__, up->sg_str, new_cost, old_cost); + + if (old_cost == new_cost) + return; + + /* Cost changed, it might Impact MLAG DF election, update */ + if (PIM_DEBUG_MLAG) + zlog_debug( + "%s: Cost_to_rp of upstream-%s changed to:%u", + __func__, up->sg_str, + rpf->source_nexthop.mrib_route_metric); + + if (pim_up_mlag_is_local(up)) + pim_mlag_up_local_add(pim, up); +} + enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct pim_upstream *up, struct pim_rpf *old, const char *caller) @@ -203,6 +230,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, struct prefix nht_p; struct prefix src, grp; bool neigh_needed = true; + uint32_t saved_mrib_route_metric; if (PIM_UPSTREAM_FLAG_TEST_STATIC_IIF(up->flags)) return PIM_RPF_OK; @@ -215,6 +243,7 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, saved.source_nexthop = rpf->source_nexthop; saved.rpf_addr = rpf->rpf_addr; + saved_mrib_route_metric = pim_up_mlag_local_cost(up); if (old) { old->source_nexthop = saved.source_nexthop; old->rpf_addr = saved.rpf_addr; @@ -236,8 +265,12 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, neigh_needed = false; pim_find_or_track_nexthop(pim, &nht_p, up, NULL, false, NULL); if (!pim_ecmp_nexthop_lookup(pim, &rpf->source_nexthop, &src, &grp, - neigh_needed)) + neigh_needed)) { + /* Route is Deleted in Zebra, reset the stored NH data */ + pim_upstream_rpf_clear(pim, up); + pim_rpf_cost_change(pim, up, saved_mrib_route_metric); return PIM_RPF_FAILURE; + } rpf->rpf_addr.family = AF_INET; rpf->rpf_addr.u.prefix4 = pim_rpf_find_rpf_addr(up); @@ -290,10 +323,18 @@ enum pim_rpf_result pim_rpf_update(struct pim_instance *pim, if (saved.rpf_addr.u.prefix4.s_addr != rpf->rpf_addr.u.prefix4.s_addr || saved.source_nexthop .interface != rpf->source_nexthop.interface) { - + pim_rpf_cost_change(pim, up, saved_mrib_route_metric); return PIM_RPF_CHANGED; } + if (PIM_DEBUG_MLAG) + zlog_debug( + "%s(%s): Cost_to_rp of upstream-%s changed to:%u", + __func__, caller, up->sg_str, + rpf->source_nexthop.mrib_route_metric); + + pim_rpf_cost_change(pim, up, saved_mrib_route_metric); + return PIM_RPF_OK; } diff --git a/pimd/pim_upstream.c b/pimd/pim_upstream.c index c899e403c8..444ab938f2 100644 --- a/pimd/pim_upstream.c +++ b/pimd/pim_upstream.c @@ -52,6 +52,7 @@ #include "pim_nht.h" #include "pim_ssm.h" #include "pim_vxlan.h" +#include "pim_mlag.h" static void join_timer_stop(struct pim_upstream *up); static void @@ -193,6 +194,9 @@ struct pim_upstream *pim_upstream_del(struct pim_instance *pim, zlog_debug("pim_upstream free vrf:%s %s flags 0x%x", pim->vrf->name, up->sg_str, up->flags); + if (pim_up_mlag_is_local(up)) + pim_mlag_up_local_del(pim, up); + THREAD_OFF(up->t_ka_timer); THREAD_OFF(up->t_rs_timer); THREAD_OFF(up->t_msdp_reg_timer); @@ -883,6 +887,26 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, } } + /* If (S, G) inherit the MLAG_VXLAN from the parent + * (*, G) entry. + */ + if ((up->sg.src.s_addr != INADDR_ANY) && + up->parent && + PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->parent->flags) && + !PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN_ORIG(up->flags)) { + PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(up->flags); + if (PIM_DEBUG_VXLAN) + zlog_debug("upstream %s inherited mlag vxlan flag from parent", + up->sg_str); + } + + /* send the entry to the MLAG peer */ + /* XXX - duplicate send is possible here if pim_rpf_update + * successfully resolved the nexthop + */ + if (pim_up_mlag_is_local(up)) + pim_mlag_up_local_add(pim, up); + if (PIM_DEBUG_PIM_TRACE) { zlog_debug( "%s: Created Upstream %s upstream_addr %s ref count %d increment", @@ -893,6 +917,30 @@ static struct pim_upstream *pim_upstream_new(struct pim_instance *pim, return up; } +uint32_t pim_up_mlag_local_cost(struct pim_upstream *up) +{ + if (!(pim_up_mlag_is_local(up))) + return router->infinite_assert_metric.route_metric; + + if ((up->rpf.source_nexthop.interface == + up->pim->vxlan.peerlink_rif) && + (up->rpf.source_nexthop.mrib_route_metric < + (router->infinite_assert_metric.route_metric - + PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC))) + return up->rpf.source_nexthop.mrib_route_metric + + PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC; + + return up->rpf.source_nexthop.mrib_route_metric; +} + +uint32_t pim_up_mlag_peer_cost(struct pim_upstream *up) +{ + if (!(up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER)) + return router->infinite_assert_metric.route_metric; + + return up->mlag.peer_mrib_metric; +} + struct pim_upstream *pim_upstream_find(struct pim_instance *pim, struct prefix_sg *sg) { @@ -916,6 +964,15 @@ struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name) { + /* if a local MLAG reference is being created we need to send the mroute + * to the peer + */ + if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags) && + PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags)) { + PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(up->flags); + pim_mlag_up_local_add(up->pim, up); + } + /* when we go from non-FHR to FHR we need to re-eval traffic * forwarding path */ @@ -1950,8 +2007,9 @@ static void pim_upstream_sg_running(void *arg) "source reference created on kat restart %s[%s]", up->sg_str, pim->vrf->name); - pim_upstream_ref(up, PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, - __PRETTY_FUNCTION__); + pim_upstream_ref(up, + PIM_UPSTREAM_FLAG_MASK_SRC_STREAM, + __PRETTY_FUNCTION__); PIM_UPSTREAM_FLAG_SET_SRC_STREAM(up->flags); pim_upstream_fhr_kat_start(up); } @@ -1974,7 +2032,7 @@ void pim_upstream_add_lhr_star_pimreg(struct pim_instance *pim) if (up->sg.src.s_addr != INADDR_ANY) continue; - if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) + if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) continue; pim_channel_add_oif(up->channel_oil, pim->regiface, @@ -2021,7 +2079,7 @@ void pim_upstream_remove_lhr_star_pimreg(struct pim_instance *pim, if (up->sg.src.s_addr != INADDR_ANY) continue; - if (!PIM_UPSTREAM_FLAG_TEST_SRC_IGMP(up->flags)) + if (!PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(up->flags)) continue; if (!nlist) { diff --git a/pimd/pim_upstream.h b/pimd/pim_upstream.h index 1eb2052bb3..c717c467dc 100644 --- a/pimd/pim_upstream.h +++ b/pimd/pim_upstream.h @@ -74,6 +74,8 @@ * blackholing the traffic pulled down to the LHR. */ #define PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF (1 << 17) +/* MLAG mroute rxed from the peer MLAG switch */ +#define PIM_UPSTREAM_FLAG_MASK_MLAG_PEER (1 << 18) /* * We are creating a non-joined upstream data structure * for this S,G as that we want to have a channel oil @@ -86,6 +88,12 @@ * This flag is only relevant for (S,G) entries. */ #define PIM_UPSTREAM_FLAG_MASK_USE_RPT (1 << 20) +/* PIM Syncs upstream entries to peer Nodes via MLAG in 2 cases. + * one is to support plain PIM Redundancy and another one is to support + * PIM REdundancy. + */ +#define PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE (1 << 21) + #define PIM_UPSTREAM_FLAG_ALL 0xFFFFFFFF @@ -108,8 +116,11 @@ #define PIM_UPSTREAM_FLAG_TEST_SRC_VXLAN(flags) ((flags) & (PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_ORIG | PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)) #define PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN) #define PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF) +#define PIM_UPSTREAM_FLAG_TEST_MLAG_PEER(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_MLAG_PEER) #define PIM_UPSTREAM_FLAG_TEST_SRC_NOCACHE(flags) ((flags) &PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE) #define PIM_UPSTREAM_FLAG_TEST_USE_RPT(flags) ((flags) & PIM_UPSTREAM_FLAG_MASK_USE_RPT) +#define PIM_UPSTREAM_FLAG_TEST_CAN_BE_LHR(flags) ((flags) & (PIM_UPSTREAM_FLAG_MASK_SRC_IGMP | PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM)) +#define PIM_UPSTREAM_FLAG_TEST_MLAG_INTERFACE(flags) ((flags)&PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -129,7 +140,9 @@ #define PIM_UPSTREAM_FLAG_SET_SRC_VXLAN_TERM(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM) #define PIM_UPSTREAM_FLAG_SET_MLAG_VXLAN(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN) #define PIM_UPSTREAM_FLAG_SET_MLAG_NON_DF(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF) +#define PIM_UPSTREAM_FLAG_SET_MLAG_PEER(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_PEER) #define PIM_UPSTREAM_FLAG_SET_USE_RPT(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_USE_RPT) +#define PIM_UPSTREAM_FLAG_SET_MLAG_INTERFACE(flags) ((flags) |= PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED) #define PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_DR_JOIN_DESIRED_UPDATED) @@ -149,8 +162,16 @@ #define PIM_UPSTREAM_FLAG_UNSET_SRC_VXLAN_TERM(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM) #define PIM_UPSTREAM_FLAG_UNSET_MLAG_VXLAN(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN) #define PIM_UPSTREAM_FLAG_UNSET_MLAG_NON_DF(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_NON_DF) +#define PIM_UPSTREAM_FLAG_UNSET_MLAG_PEER(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_PEER) #define PIM_UPSTREAM_FLAG_UNSET_SRC_NOCACHE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_SRC_NOCACHE) #define PIM_UPSTREAM_FLAG_UNSET_USE_RPT(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_USE_RPT) +#define PIM_UPSTREAM_FLAG_UNSET_MLAG_INTERFACE(flags) ((flags) &= ~PIM_UPSTREAM_FLAG_MASK_MLAG_INTERFACE) + +/* The RPF cost is incremented by 10 if the RPF interface is the peerlink-rif. + * This is used to force the MLAG switch with the lowest cost to the RPF + * to become the MLAG DF. + */ +#define PIM_UPSTREAM_MLAG_PEERLINK_PLUS_METRIC 10 enum pim_upstream_state { PIM_UPSTREAM_NOTJOINED, @@ -169,6 +190,13 @@ enum pim_upstream_sptbit { PIM_UPSTREAM_SPTBIT_TRUE }; +struct pim_up_mlag { + /* MRIB.metric(S) from the peer switch. This is used for DF election + * and switch with the lowest cost wins. + */ + uint32_t peer_mrib_metric; +}; + PREDECL_RBTREE_UNIQ(rb_pim_upstream); /* Upstream (S,G) channel in Joined state @@ -218,6 +246,8 @@ struct pim_upstream { struct pim_rpf rpf; + struct pim_up_mlag mlag; + struct thread *t_join_timer; /* @@ -249,6 +279,14 @@ static inline bool pim_upstream_is_kat_running(struct pim_upstream *up) return (up->t_ka_timer != NULL); } +static inline bool pim_up_mlag_is_local(struct pim_upstream *up) +{ + /* XXX: extend this to also return true if the channel-oil has + * any AA devices + */ + return (up->flags & PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN); +} + struct pim_upstream *pim_upstream_find(struct pim_instance *pim, struct prefix_sg *sg); struct pim_upstream *pim_upstream_find_or_add(struct prefix_sg *sg, @@ -259,7 +297,8 @@ struct pim_upstream *pim_upstream_add(struct pim_instance *pim, struct interface *ifp, int flags, const char *name, struct pim_ifchannel *ch); -void pim_upstream_ref(struct pim_upstream *up, int flags, const char *name); +void pim_upstream_ref(struct pim_upstream *up, + int flags, const char *name); struct pim_upstream *pim_upstream_del(struct pim_instance *pim, struct pim_upstream *up, const char *name); @@ -350,5 +389,7 @@ void pim_upstream_fill_static_iif(struct pim_upstream *up, struct interface *incoming); void pim_upstream_update_use_rpt(struct pim_upstream *up, bool update_mroute); +uint32_t pim_up_mlag_local_cost(struct pim_upstream *up); +uint32_t pim_up_mlag_peer_cost(struct pim_upstream *up); void pim_upstream_reeval_use_rpt(struct pim_instance *pim); #endif /* PIM_UPSTREAM_H */ diff --git a/pimd/pim_vty.c b/pimd/pim_vty.c index c48ec373f8..b5a5089ae7 100644 --- a/pimd/pim_vty.c +++ b/pimd/pim_vty.c @@ -242,8 +242,6 @@ int pim_global_config_write_worker(struct pim_instance *pim, struct vty *vty) } } - pim_vxlan_config_write(vty, spaces, &writes); - return writes; } diff --git a/pimd/pim_vxlan.c b/pimd/pim_vxlan.c index fc34f3f600..57b922a531 100644 --- a/pimd/pim_vxlan.c +++ b/pimd/pim_vxlan.c @@ -38,6 +38,7 @@ #include "pim_nht.h" #include "pim_zebra.h" #include "pim_vxlan.h" +#include "pim_mlag.h" /* pim-vxlan global info */ struct pim_vxlan vxlan_info, *pim_vxlan_p = &vxlan_info; @@ -476,13 +477,14 @@ static void pim_vxlan_orig_mr_del(struct pim_vxlan_sg *vxlan_sg) static void pim_vxlan_orig_mr_iif_update(struct hash_backet *backet, void *arg) { - struct interface *ifp = (struct interface *)arg; + struct interface *ifp; struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data; struct interface *old_iif = vxlan_sg->iif; if (!pim_vxlan_is_orig_mroute(vxlan_sg)) return; + ifp = pim_vxlan_orig_mr_iif_get(vxlan_sg->pim); if (PIM_DEBUG_VXLAN) zlog_debug("vxlan SG %s iif changed from %s to %s", vxlan_sg->sg_str, @@ -529,8 +531,15 @@ static void pim_vxlan_term_mr_oif_add(struct pim_vxlan_sg *vxlan_sg) vxlan_sg->sg_str, vxlan_sg->term_oif->name); if (pim_ifchannel_local_membership_add(vxlan_sg->term_oif, - &vxlan_sg->sg)) { + &vxlan_sg->sg, true /*is_vxlan */)) { vxlan_sg->flags |= PIM_VXLAN_SGF_OIF_INSTALLED; + /* update the inherited OIL */ + /* XXX - I don't see the inherited OIL updated when a local + * member is added. And that probably needs to be fixed. Till + * that happens we do a force update on the inherited OIL + * here. + */ + pim_upstream_inherited_olist(vxlan_sg->pim, vxlan_sg->up); } else { zlog_warn("vxlan SG %s term-oif %s add failed", vxlan_sg->sg_str, vxlan_sg->term_oif->name); @@ -548,6 +557,43 @@ static void pim_vxlan_term_mr_oif_del(struct pim_vxlan_sg *vxlan_sg) vxlan_sg->flags &= ~PIM_VXLAN_SGF_OIF_INSTALLED; pim_ifchannel_local_membership_del(vxlan_sg->term_oif, &vxlan_sg->sg); + /* update the inherited OIL */ + /* XXX - I don't see the inherited OIL updated when a local member + * is deleted. And that probably needs to be fixed. Till that happens + * we do a force update on the inherited OIL here. + */ + pim_upstream_inherited_olist(vxlan_sg->pim, vxlan_sg->up); +} + +static void pim_vxlan_update_sg_entry_mlag(struct pim_instance *pim, + struct pim_upstream *up, bool inherit) +{ + bool is_df = true; + + if (inherit && up->parent && + PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->parent->flags) && + PIM_UPSTREAM_FLAG_TEST_MLAG_NON_DF(up->parent->flags)) + is_df = false; + + pim_mlag_up_df_role_update(pim, up, is_df, "inherit_xg_df"); +} + +/* We run MLAG DF election only on mroutes that have the termination + * device ipmr-lo in the immediate OIL. This is only (*, G) entries at the + * moment. For (S, G) entries that (with ipmr-lo in the inherited OIL) we + * inherit the DF role from the (*, G) entry. + */ +void pim_vxlan_inherit_mlag_flags(struct pim_instance *pim, + struct pim_upstream *up, bool inherit) +{ + struct listnode *listnode; + struct pim_upstream *child; + + for (ALL_LIST_ELEMENTS_RO(up->sources, listnode, + child)) { + pim_vxlan_update_sg_entry_mlag(pim, + child, true /* inherit */); + } } static void pim_vxlan_term_mr_up_add(struct pim_vxlan_sg *vxlan_sg) @@ -576,7 +622,11 @@ static void pim_vxlan_term_mr_up_add(struct pim_vxlan_sg *vxlan_sg) if (!up) { zlog_warn("vxlan SG %s term mroute-up add failed", vxlan_sg->sg_str); + return; } + + /* update existing SG entries with the parent's MLAG flag */ + pim_vxlan_inherit_mlag_flags(vxlan_sg->pim, up, true /*enable*/); } static void pim_vxlan_term_mr_up_del(struct pim_vxlan_sg *vxlan_sg) @@ -591,10 +641,13 @@ static void pim_vxlan_term_mr_up_del(struct pim_vxlan_sg *vxlan_sg) vxlan_sg->sg_str); vxlan_sg->up = NULL; if (up->flags & PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM) { + /* update SG entries that are inheriting from this XG entry */ + pim_vxlan_inherit_mlag_flags(vxlan_sg->pim, up, + false /*enable*/); /* clear out all the vxlan related flags */ up->flags &= ~(PIM_UPSTREAM_FLAG_MASK_SRC_VXLAN_TERM | PIM_UPSTREAM_FLAG_MASK_MLAG_VXLAN); - + pim_mlag_up_local_del(vxlan_sg->pim, up); pim_upstream_del(vxlan_sg->pim, up, __PRETTY_FUNCTION__); } @@ -660,6 +713,14 @@ static struct pim_vxlan_sg *pim_vxlan_sg_new(struct pim_instance *pim, vxlan_sg = hash_get(pim->vxlan.sg_hash, vxlan_sg, hash_alloc_intern); + /* we register with the MLAG daemon in the first VxLAN SG and never + * de-register during that life of the pimd + */ + if (pim->vxlan.sg_hash->count == 1) { + vxlan_mlag.flags |= PIM_VXLAN_MLAGF_DO_REG; + pim_mlag_register(); + } + return vxlan_sg; } @@ -717,12 +778,18 @@ void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg) } /******************************* MLAG handling *******************************/ +bool pim_vxlan_do_mlag_reg(void) +{ + return (vxlan_mlag.flags & PIM_VXLAN_MLAGF_DO_REG); +} + /* The peerlink sub-interface is added as an OIF to the origination-mroute. * This is done to send a copy of the multicast-vxlan encapsulated traffic * to the MLAG peer which may mroute it over the underlay if there are any * interested receivers. */ -static void pim_vxlan_sg_peerlink_update(struct hash_backet *backet, void *arg) +static void pim_vxlan_sg_peerlink_oif_update(struct hash_backet *backet, + void *arg) { struct interface *new_oif = (struct interface *)arg; struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data; @@ -761,8 +828,6 @@ void pim_vxlan_mlag_update(bool enable, bool peer_state, uint32_t role, struct in_addr *reg_addr) { struct pim_instance *pim; - struct interface *old_oif; - struct interface *new_oif; char addr_buf[INET_ADDRSTRLEN]; struct pim_interface *pim_ifp = NULL; @@ -782,8 +847,6 @@ void pim_vxlan_mlag_update(bool enable, bool peer_state, uint32_t role, */ pim = pim_get_pim_instance(VRF_DEFAULT); - old_oif = pim_vxlan_orig_mr_oif_get(pim); - if (enable) vxlan_mlag.flags |= PIM_VXLAN_MLAGF_ENABLED; else @@ -804,35 +867,9 @@ void pim_vxlan_mlag_update(bool enable, bool peer_state, uint32_t role, pim_vxlan_set_peerlink_rif(pim, peerlink_rif); else pim_vxlan_set_peerlink_rif(pim, NULL); - - new_oif = pim_vxlan_orig_mr_oif_get(pim); - if (old_oif != new_oif) - hash_iterate(pim->vxlan.sg_hash, pim_vxlan_sg_peerlink_update, - new_oif); } /****************************** misc callbacks *******************************/ -void pim_vxlan_config_write(struct vty *vty, char *spaces, int *writes) -{ - char addr_buf[INET_ADDRSTRLEN]; - - if ((vxlan_mlag.flags & PIM_VXLAN_MLAGF_ENABLED) && - vxlan_mlag.peerlink_rif) { - - inet_ntop(AF_INET, &vxlan_mlag.reg_addr, - addr_buf, sizeof(addr_buf)); - vty_out(vty, - "%sip pim mlag %s role %s state %s addr %s\n", - spaces, - vxlan_mlag.peerlink_rif->name, - (vxlan_mlag.role == PIM_VXLAN_MLAG_ROLE_PRIMARY) ? - "primary":"secondary", - vxlan_mlag.peer_state ? "up" : "down", - addr_buf); - *writes += 1; - } -} - static void pim_vxlan_set_default_iif(struct pim_instance *pim, struct interface *ifp) { @@ -864,13 +901,72 @@ static void pim_vxlan_set_default_iif(struct pim_instance *pim, */ if (pim->vxlan.sg_hash) hash_iterate(pim->vxlan.sg_hash, - pim_vxlan_orig_mr_iif_update, ifp); + pim_vxlan_orig_mr_iif_update, NULL); +} + +static void pim_vxlan_up_cost_update(struct pim_instance *pim, + struct pim_upstream *up, + struct interface *old_peerlink_rif) +{ + if (!PIM_UPSTREAM_FLAG_TEST_MLAG_VXLAN(up->flags)) + return; + + if (up->rpf.source_nexthop.interface && + ((up->rpf.source_nexthop.interface == + pim->vxlan.peerlink_rif) || + (up->rpf.source_nexthop.interface == + old_peerlink_rif))) { + if (PIM_DEBUG_VXLAN) + zlog_debug("RPF cost adjust for %s on peerlink-rif (old: %s, new: %s) change", + up->sg_str, + old_peerlink_rif ? + old_peerlink_rif->name : "-", + pim->vxlan.peerlink_rif ? + pim->vxlan.peerlink_rif->name : "-"); + pim_mlag_up_local_add(pim, up); + } +} + +static void pim_vxlan_term_mr_cost_update(struct hash_backet *backet, + void *arg) +{ + struct interface *old_peerlink_rif = (struct interface *)arg; + struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data; + struct pim_upstream *up; + struct listnode *listnode; + struct pim_upstream *child; + + if (pim_vxlan_is_orig_mroute(vxlan_sg)) + return; + + /* Lookup all XG and SG entries with RPF-interface peerlink_rif */ + up = vxlan_sg->up; + if (!up) + return; + + pim_vxlan_up_cost_update(vxlan_sg->pim, up, + old_peerlink_rif); + + for (ALL_LIST_ELEMENTS_RO(up->sources, listnode, + child)) + pim_vxlan_up_cost_update(vxlan_sg->pim, child, + old_peerlink_rif); +} + +static void pim_vxlan_sg_peerlink_rif_update(struct hash_backet *backet, + void *arg) +{ + pim_vxlan_orig_mr_iif_update(backet, NULL); + pim_vxlan_term_mr_cost_update(backet, arg); } static void pim_vxlan_set_peerlink_rif(struct pim_instance *pim, struct interface *ifp) { struct interface *old_iif; + struct interface *new_iif; + struct interface *old_oif; + struct interface *new_oif; if (pim->vxlan.peerlink_rif == ifp) return; @@ -882,22 +978,77 @@ static void pim_vxlan_set_peerlink_rif(struct pim_instance *pim, ifp ? ifp->name : "-"); old_iif = pim_vxlan_orig_mr_iif_get(pim); + old_oif = pim_vxlan_orig_mr_oif_get(pim); pim->vxlan.peerlink_rif = ifp; - ifp = pim_vxlan_orig_mr_iif_get(pim); - if (old_iif == ifp) + + new_iif = pim_vxlan_orig_mr_iif_get(pim); + if (old_iif != new_iif) { + if (PIM_DEBUG_VXLAN) + zlog_debug("%s: vxlan orig iif changed from %s to %s", + __PRETTY_FUNCTION__, + old_iif ? old_iif->name : "-", + new_iif ? new_iif->name : "-"); + + /* add/del upstream entries for the existing vxlan SG when the + * interface becomes available + */ + if (pim->vxlan.sg_hash) + hash_iterate(pim->vxlan.sg_hash, + pim_vxlan_sg_peerlink_rif_update, + old_iif); + } + + new_oif = pim_vxlan_orig_mr_oif_get(pim); + if (old_oif != new_oif) { + if (PIM_DEBUG_VXLAN) + zlog_debug("%s: vxlan orig oif changed from %s to %s", + __PRETTY_FUNCTION__, + old_oif ? old_oif->name : "-", + new_oif ? new_oif->name : "-"); + if (pim->vxlan.sg_hash) + hash_iterate(pim->vxlan.sg_hash, + pim_vxlan_sg_peerlink_oif_update, + new_oif); + } +} + +static void pim_vxlan_term_mr_oif_update(struct hash_backet *backet, void *arg) +{ + struct interface *ifp = (struct interface *)arg; + struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data; + + if (pim_vxlan_is_orig_mroute(vxlan_sg)) + return; + + if (vxlan_sg->term_oif == ifp) return; if (PIM_DEBUG_VXLAN) - zlog_debug("%s: vxlan orig iif changed from %s to %s", - __PRETTY_FUNCTION__, old_iif ? old_iif->name : "-", + zlog_debug("vxlan SG %s term oif changed from %s to %s", + vxlan_sg->sg_str, + vxlan_sg->term_oif ? vxlan_sg->term_oif->name : "-", ifp ? ifp->name : "-"); - /* add/del upstream entries for the existing vxlan SG when the - * interface becomes available - */ + pim_vxlan_term_mr_del(vxlan_sg); + vxlan_sg->term_oif = ifp; + pim_vxlan_term_mr_add(vxlan_sg); +} + +static void pim_vxlan_term_oif_update(struct pim_instance *pim, + struct interface *ifp) +{ + if (pim->vxlan.term_if == ifp) + return; + + if (PIM_DEBUG_VXLAN) + zlog_debug("vxlan term oif changed from %s to %s", + pim->vxlan.term_if ? pim->vxlan.term_if->name : "-", + ifp ? ifp->name : "-"); + + pim->vxlan.term_if = ifp; if (pim->vxlan.sg_hash) hash_iterate(pim->vxlan.sg_hash, - pim_vxlan_orig_mr_iif_update, ifp); + pim_vxlan_term_mr_oif_update, ifp); } void pim_vxlan_add_vif(struct interface *ifp) @@ -914,6 +1065,9 @@ void pim_vxlan_add_vif(struct interface *ifp) if (vxlan_mlag.flags & PIM_VXLAN_MLAGF_ENABLED && (ifp == vxlan_mlag.peerlink_rif)) pim_vxlan_set_peerlink_rif(pim, ifp); + + if (pim->vxlan.term_if_cfg == ifp) + pim_vxlan_term_oif_update(pim, ifp); } void pim_vxlan_del_vif(struct interface *ifp) @@ -929,76 +1083,56 @@ void pim_vxlan_del_vif(struct interface *ifp) if (pim->vxlan.peerlink_rif == ifp) pim_vxlan_set_peerlink_rif(pim, NULL); -} - -static void pim_vxlan_term_mr_oif_update(struct hash_backet *backet, void *arg) -{ - struct interface *ifp = (struct interface *)arg; - struct pim_vxlan_sg *vxlan_sg = (struct pim_vxlan_sg *)backet->data; - if (pim_vxlan_is_orig_mroute(vxlan_sg)) - return; - - if (vxlan_sg->term_oif == ifp) - return; - - if (PIM_DEBUG_VXLAN) - zlog_debug("vxlan SG %s term oif changed from %s to %s", - vxlan_sg->sg_str, - vxlan_sg->term_oif ? vxlan_sg->term_oif->name : "-", - ifp ? ifp->name : "-"); - - pim_vxlan_term_mr_del(vxlan_sg); - vxlan_sg->term_oif = ifp; - pim_vxlan_term_mr_add(vxlan_sg); + if (pim->vxlan.term_if == ifp) + pim_vxlan_term_oif_update(pim, NULL); } +/* enable pim implicitly on the termination device add */ void pim_vxlan_add_term_dev(struct pim_instance *pim, struct interface *ifp) { struct pim_interface *pim_ifp; - if (pim->vxlan.term_if == ifp) + if (pim->vxlan.term_if_cfg == ifp) return; if (PIM_DEBUG_VXLAN) - zlog_debug("vxlan term oif changed from %s to %s", - pim->vxlan.term_if ? pim->vxlan.term_if->name : "-", - ifp->name); + zlog_debug("vxlan term oif cfg changed from %s to %s", + pim->vxlan.term_if_cfg ? + pim->vxlan.term_if_cfg->name : "-", + ifp->name); + + pim->vxlan.term_if_cfg = ifp; /* enable pim on the term ifp */ pim_ifp = (struct pim_interface *)ifp->info; if (pim_ifp) { PIM_IF_DO_PIM(pim_ifp->options); + /* ifp is already oper up; activate it as a term dev */ + if (pim_ifp->mroute_vif_index >= 0) + pim_vxlan_term_oif_update(pim, ifp); } else { - pim_ifp = pim_if_new(ifp, false /*igmp*/, true /*pim*/, - false /*pimreg*/, true /*vxlan_term*/); - /* ensure that pimreg existss before using the newly created + /* ensure that pimreg exists before using the newly created * vxlan termination device */ pim_if_create_pimreg(pim); + (void)pim_if_new(ifp, false /*igmp*/, true /*pim*/, + false /*pimreg*/, true /*vxlan_term*/); } - - pim->vxlan.term_if = ifp; - - if (pim->vxlan.sg_hash) - hash_iterate(pim_ifp->pim->vxlan.sg_hash, - pim_vxlan_term_mr_oif_update, ifp); } +/* disable pim implicitly, if needed, on the termination device deletion */ void pim_vxlan_del_term_dev(struct pim_instance *pim) { - struct interface *ifp = pim->vxlan.term_if; + struct interface *ifp = pim->vxlan.term_if_cfg; struct pim_interface *pim_ifp; if (PIM_DEBUG_VXLAN) - zlog_debug("vxlan term oif changed from %s to -", ifp->name); + zlog_debug("vxlan term oif cfg changed from %s to -", + ifp->name); - pim->vxlan.term_if = NULL; - - if (pim->vxlan.sg_hash) - hash_iterate(pim->vxlan.sg_hash, - pim_vxlan_term_mr_oif_update, NULL); + pim->vxlan.term_if_cfg = NULL; pim_ifp = (struct pim_interface *)ifp->info; if (pim_ifp) { @@ -1006,7 +1140,6 @@ void pim_vxlan_del_term_dev(struct pim_instance *pim) if (!PIM_IF_TEST_IGMP(pim_ifp->options)) pim_if_delete(ifp); } - } void pim_vxlan_init(struct pim_instance *pim) diff --git a/pimd/pim_vxlan.h b/pimd/pim_vxlan.h index c6507a474c..198d1c3281 100644 --- a/pimd/pim_vxlan.h +++ b/pimd/pim_vxlan.h @@ -66,17 +66,14 @@ struct pim_vxlan_sg { enum pim_vxlan_mlag_flags { PIM_VXLAN_MLAGF_NONE = 0, - PIM_VXLAN_MLAGF_ENABLED = (1 << 0) -}; - -enum pim_vxlan_mlag_role { - PIM_VXLAN_MLAG_ROLE_SECONDARY = 0, - PIM_VXLAN_MLAG_ROLE_PRIMARY + PIM_VXLAN_MLAGF_ENABLED = (1 << 0), + PIM_VXLAN_MLAGF_DO_REG = (1 << 1) }; struct pim_vxlan_mlag { enum pim_vxlan_mlag_flags flags; - enum pim_vxlan_mlag_role role; + /* XXX - remove this variable from here */ + int role; bool peer_state; /* routed interface setup on top of MLAG peerlink */ struct interface *peerlink_rif; @@ -122,6 +119,12 @@ static inline bool pim_vxlan_is_local_sip(struct pim_upstream *up) if_is_loopback_or_vrf(up->rpf.source_nexthop.interface); } +static inline bool pim_vxlan_is_term_dev_cfg(struct pim_instance *pim, + struct interface *ifp) +{ + return pim->vxlan.term_if_cfg == ifp; +} + extern struct pim_vxlan *pim_vxlan_p; extern struct pim_vxlan_sg *pim_vxlan_sg_find(struct pim_instance *pim, struct prefix_sg *sg); @@ -141,6 +144,8 @@ extern bool pim_vxlan_get_register_src(struct pim_instance *pim, extern void pim_vxlan_mlag_update(bool enable, bool peer_state, uint32_t role, struct interface *peerlink_rif, struct in_addr *reg_addr); -extern void pim_vxlan_config_write(struct vty *vty, char *spaces, int *writes); +extern bool pim_vxlan_do_mlag_reg(void); +extern void pim_vxlan_inherit_mlag_flags(struct pim_instance *pim, + struct pim_upstream *up, bool inherit); #endif /* PIM_VXLAN_H */ diff --git a/pimd/pim_vxlan_instance.h b/pimd/pim_vxlan_instance.h index 3f99483fbe..5b35bcbeaa 100644 --- a/pimd/pim_vxlan_instance.h +++ b/pimd/pim_vxlan_instance.h @@ -36,6 +36,7 @@ struct pim_vxlan_instance { /* device used by the dataplane to terminate multicast encapsulated * vxlan traffic */ + struct interface *term_if_cfg; struct interface *term_if; }; diff --git a/pimd/pim_zebra.c b/pimd/pim_zebra.c index 06507b1f4c..baa6216df2 100644 --- a/pimd/pim_zebra.c +++ b/pimd/pim_zebra.c @@ -452,7 +452,7 @@ static void pim_zebra_connected(struct zclient *zclient) static void pim_zebra_capabilities(struct zclient_capabilities *cap) { - router->role = cap->role; + router->mlag_role = cap->role; } void pim_zebra_init(void) @@ -547,7 +547,8 @@ static void igmp_source_forward_reevaluate_one(struct pim_instance *pim, "local membership add for %s as G is now ASM", pim_str_sg_dump(&sg)); pim_ifchannel_local_membership_add( - group->group_igmp_sock->interface, &sg); + group->group_igmp_sock->interface, &sg, + false /*is_vxlan*/); } } } @@ -765,7 +766,8 @@ void igmp_source_forward_start(struct pim_instance *pim, per-interface (S,G) state. */ if (!pim_ifchannel_local_membership_add( - group->group_igmp_sock->interface, &sg)) { + group->group_igmp_sock->interface, &sg, + false /*is_vxlan*/)) { if (PIM_DEBUG_MROUTE) zlog_warn("%s: Failure to add local membership for %s", __PRETTY_FUNCTION__, pim_str_sg_dump(&sg)); diff --git a/pimd/pimd.c b/pimd/pimd.c index 889a83a136..0a7ac3b31f 100644 --- a/pimd/pimd.c +++ b/pimd/pimd.c @@ -50,6 +50,7 @@ const char *const PIM_ALL_IGMP_ROUTERS = MCAST_ALL_IGMP_ROUTERS; DEFINE_MTYPE_STATIC(PIMD, ROUTER, "PIM Router information"); struct pim_router *router = NULL; +struct in_addr qpim_all_pim_routers_addr; void pim_prefix_list_update(struct prefix_list *plist) { diff --git a/pimd/pimd.h b/pimd/pimd.h index 70d2766220..88e692b50d 100644 --- a/pimd/pimd.h +++ b/pimd/pimd.h @@ -131,14 +131,14 @@ #define PIM_UPDATE_SOURCE_DUP -10 #define PIM_GROUP_BAD_ADDR_MASK_COMBO -11 -const char *const PIM_ALL_SYSTEMS; -const char *const PIM_ALL_ROUTERS; -const char *const PIM_ALL_PIM_ROUTERS; -const char *const PIM_ALL_IGMP_ROUTERS; +extern const char *const PIM_ALL_SYSTEMS; +extern const char *const PIM_ALL_ROUTERS; +extern const char *const PIM_ALL_PIM_ROUTERS; +extern const char *const PIM_ALL_IGMP_ROUTERS; extern struct pim_router *router; extern struct zebra_privs_t pimd_privs; -struct in_addr qpim_all_pim_routers_addr; +extern struct in_addr qpim_all_pim_routers_addr; extern uint8_t qpim_ecmp_enable; extern uint8_t qpim_ecmp_rebalance_enable; diff --git a/ripd/rip_interface.c b/ripd/rip_interface.c index d07cc894a5..2ed8d5394d 100644 --- a/ripd/rip_interface.c +++ b/ripd/rip_interface.c @@ -351,11 +351,14 @@ static int rip_ifp_down(struct interface *ifp) rip_interface_sync(ifp); rip_if_down(ifp); - if (IS_RIP_DEBUG_ZEBRA) + if (IS_RIP_DEBUG_ZEBRA) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + zlog_debug( - "interface %s vrf %u index %d flags %llx metric %d mtu %d is down", - ifp->name, ifp->vrf_id, ifp->ifindex, + "interface %s vrf %s(%u) index %d flags %llx metric %d mtu %d is down", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); + } return 0; } @@ -363,11 +366,14 @@ static int rip_ifp_down(struct interface *ifp) /* Inteface link up message processing */ static int rip_ifp_up(struct interface *ifp) { - if (IS_RIP_DEBUG_ZEBRA) + if (IS_RIP_DEBUG_ZEBRA) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + zlog_debug( - "interface %s vrf %u index %d flags %#llx metric %d mtu %d is up", - ifp->name, ifp->vrf_id, ifp->ifindex, + "interface %s vrf %s(%u) index %d flags %#llx metric %d mtu %d is up", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); + } rip_interface_sync(ifp); @@ -388,11 +394,13 @@ static int rip_ifp_create(struct interface *ifp) { rip_interface_sync(ifp); - if (IS_RIP_DEBUG_ZEBRA) + if (IS_RIP_DEBUG_ZEBRA) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); zlog_debug( - "interface add %s vrf %u index %d flags %#llx metric %d mtu %d", - ifp->name, ifp->vrf_id, ifp->ifindex, + "interface add %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); + } /* Check if this interface is RIP enabled or not.*/ rip_enable_apply(ifp); @@ -413,14 +421,16 @@ static int rip_ifp_create(struct interface *ifp) static int rip_ifp_destroy(struct interface *ifp) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + rip_interface_sync(ifp); if (if_is_up(ifp)) { rip_if_down(ifp); } zlog_info( - "interface delete %s vrf %u index %d flags %#llx metric %d mtu %d", - ifp->name, ifp->vrf_id, ifp->ifindex, + "interface delete %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu); return 0; @@ -437,9 +447,14 @@ int rip_interface_vrf_update(ZAPI_CALLBACK_ARGS) if (!ifp) return 0; - if (IS_RIP_DEBUG_ZEBRA) - zlog_debug("interface %s VRF change vrf_id %u new vrf id %u", - ifp->name, vrf_id, new_vrf_id); + if (IS_RIP_DEBUG_ZEBRA) { + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id); + + zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)", + ifp->name, VRF_LOGNAME(vrf), vrf_id, + VRF_LOGNAME(nvrf), new_vrf_id); + } if_update_to_new_vrf(ifp, new_vrf_id); rip_interface_sync(ifp); diff --git a/ripngd/ripng_interface.c b/ripngd/ripng_interface.c index 250c7803f7..6a30c07d99 100644 --- a/ripngd/ripng_interface.c +++ b/ripngd/ripng_interface.c @@ -198,11 +198,14 @@ static int ripng_if_down(struct interface *ifp) /* Inteface link up message processing. */ static int ripng_ifp_up(struct interface *ifp) { - if (IS_RIPNG_DEBUG_ZEBRA) + if (IS_RIPNG_DEBUG_ZEBRA) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + zlog_debug( - "interface up %s vrf %u index %d flags %llx metric %d mtu %d", - ifp->name, ifp->vrf_id, ifp->ifindex, + "interface up %s vrf %s(%u) index %d flags %llx metric %d mtu %d", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); + } ripng_interface_sync(ifp); @@ -224,11 +227,14 @@ static int ripng_ifp_down(struct interface *ifp) ripng_interface_sync(ifp); ripng_if_down(ifp); - if (IS_RIPNG_DEBUG_ZEBRA) + if (IS_RIPNG_DEBUG_ZEBRA) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + zlog_debug( - "interface down %s vrf %u index %d flags %#llx metric %d mtu %d", - ifp->name, ifp->vrf_id, ifp->ifindex, + "interface down %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); + } return 0; } @@ -238,11 +244,14 @@ static int ripng_ifp_create(struct interface *ifp) { ripng_interface_sync(ifp); - if (IS_RIPNG_DEBUG_ZEBRA) + if (IS_RIPNG_DEBUG_ZEBRA) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + zlog_debug( - "RIPng interface add %s vrf %u index %d flags %#llx metric %d mtu %d", - ifp->name, ifp->vrf_id, ifp->ifindex, + "RIPng interface add %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); + } /* Check is this interface is RIP enabled or not.*/ ripng_enable_apply(ifp); @@ -258,14 +267,16 @@ static int ripng_ifp_create(struct interface *ifp) static int ripng_ifp_destroy(struct interface *ifp) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + ripng_interface_sync(ifp); if (if_is_up(ifp)) { ripng_if_down(ifp); } zlog_info( - "interface delete %s vrf %u index %d flags %#llx metric %d mtu %d", - ifp->name, ifp->vrf_id, ifp->ifindex, + "interface delete %s vrf %s(%u) index %d flags %#llx metric %d mtu %d", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex, (unsigned long long)ifp->flags, ifp->metric, ifp->mtu6); return 0; @@ -282,9 +293,14 @@ int ripng_interface_vrf_update(ZAPI_CALLBACK_ARGS) if (!ifp) return 0; - if (IS_RIPNG_DEBUG_ZEBRA) - zlog_debug("interface %s VRF change vrf_id %u new vrf id %u", - ifp->name, vrf_id, new_vrf_id); + if (IS_RIPNG_DEBUG_ZEBRA) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + struct vrf *nvrf = vrf_lookup_by_id(new_vrf_id); + + zlog_debug("interface %s VRF change vrf %s(%u) new vrf %s(%u)", + ifp->name, VRF_LOGNAME(vrf), vrf_id, + VRF_LOGNAME(nvrf), new_vrf_id); + } if_update_to_new_vrf(ifp, new_vrf_id); ripng_interface_sync(ifp); diff --git a/tests/topotests/bgp-route-map/test_route_map_topo1.py b/tests/topotests/bgp-route-map/test_route_map_topo1.py index 86ec6c82d2..22dd3a6380 100755 --- a/tests/topotests/bgp-route-map/test_route_map_topo1.py +++ b/tests/topotests/bgp-route-map/test_route_map_topo1.py @@ -71,7 +71,7 @@ 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, "../")) # pylint: disable=C0413 # Import topogen and topotest helpers @@ -102,7 +102,7 @@ ADDR_TYPES = check_address_types() # Reading the data from JSON File for topology and configuration creation jsonFile = "{}/bgp_route_map_topo1.json".format(CWD) try: - with open(jsonFile, 'r') as topoJson: + with open(jsonFile, "r") as topoJson: topo = json.load(topoJson) except IOError: assert False, "Could not read file {}".format(jsonFile) @@ -442,11 +442,12 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request): } } - result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol) + result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol, + expected=False) assert result is not True, "Testcase {} : Failed \n" - "Expected behavior: routes are not present in rib \n" - "Error: {}".format( + "routes are not present in rib \n Error: {}".format( tc_name, result) + logger.info("Expected behaviour: {}".format(result)) # Verifying RIB routes dut = "r4" @@ -461,11 +462,12 @@ def test_route_map_inbound_outbound_same_neighbor_p0(request): ] } } - result = verify_rib(tgen, adt, dut, input_dict, protocol=protocol) + result = verify_rib(tgen, adt, dut, input_dict, protocol=protocol, + expected=False) assert result is not True, "Testcase {} : Failed \n " - "Expected behavior: routes are not present in rib \n " - "Error: {}".format( + "routes are not present in rib \n Error: {}".format( tc_name, result) + logger.info("Expected behaviour: {}".format(result)) write_test_footer(tc_name) @@ -649,10 +651,14 @@ def test_route_map_with_action_values_combination_of_prefix_action_p0( } } - result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol) + #tgen.mininet_cli() + result = verify_rib(tgen, adt, dut, input_dict_2, protocol=protocol, + expected=False) if "deny" in [prefix_action, rmap_action]: - assert result is not True, "Testcase {} : Failed \n Error: {}".\ + assert result is not True, "Testcase {} : Failed \n " + "Routes are still present \n Error: {}".\ format(tc_name, result) + logger.info("Expected behaviour: {}".format(result)) else: assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) diff --git a/tests/topotests/bgp-route-map/test_route_map_topo2.py b/tests/topotests/bgp-route-map/test_route_map_topo2.py index 7009fc97ce..f2398c33ff 100755 --- a/tests/topotests/bgp-route-map/test_route_map_topo2.py +++ b/tests/topotests/bgp-route-map/test_route_map_topo2.py @@ -32,17 +32,17 @@ TC_61: TC_50_1: Test modify/remove prefix-lists referenced by a route-map for match statement. -TC_50_1: +TC_50_2: Remove prefix-list referencec by route-map match cluase and verifying it reflecting as intended TC_51: Add and remove community-list referencec by route-map match cluase and verifying it reflecting as intended TC_45: - Test multiple match statements as part of a route-map's single + Test multiple match statements as part of a route-map"s single sequence number. (Logical OR-ed of multiple match statements) TC_44: - Test multiple match statements as part of a route-map's single + Test multiple match statements as part of a route-map"s single sequence number. (Logical AND of multiple match statements) TC_41: Test add/remove route-maps to specific neighbor and see if @@ -57,7 +57,7 @@ TC_48: Create route map setting local preference and weight to eBGP peeer and metric to ibgp peer and verifying it should not get advertised TC_43: - Test multiple set statements as part of a route-map's + Test multiple set statements as part of a route-map"s single sequence number. TC_54: Verify route-maps continue clause functionality. @@ -112,7 +112,7 @@ 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, "../")) # pylint: disable=C0413 # Import topogen and topotest helpers @@ -127,7 +127,8 @@ from lib.common_config import ( verify_rib, delete_route_maps, create_bgp_community_lists, interface_status, create_route_maps, create_prefix_lists, verify_route_maps, check_address_types, verify_bgp_community, - shutdown_bringup_interface, verify_prefix_lists, reset_config_on_routers) + shutdown_bringup_interface, verify_prefix_lists, reset_config_on_routers, + verify_create_community_list) from lib.topolog import logger from lib.bgp import ( verify_bgp_convergence, create_router_bgp, @@ -138,7 +139,7 @@ from lib.topojson import build_topo_from_json, build_config_from_json jsonFile = "{}/bgp_route_map_topo2.json".format(CWD) try: - with open(jsonFile, 'r') as topoJson: + with open(jsonFile, "r") as topoJson: topo = json.load(topoJson) except IOError: assert False, "Could not read file {}".format(jsonFile) @@ -198,14 +199,14 @@ def setup_module(mod): global bgp_convergence global ADDR_TYPES - # Don't run this test if we have any failure. + # 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 bgp_convergence = verify_bgp_convergence(tgen, topo) - assert bgp_convergence is True, ('setup_module :Failed \n Error:' - ' {}'.format(bgp_convergence)) + assert bgp_convergence is True, ("setup_module :Failed \n Error:" + " {}".format(bgp_convergence)) logger.info("Running setup_module() done") @@ -241,7 +242,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -250,20 +251,20 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit', + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit", }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit', + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 10, + "network": "any", + "action": "permit", }] } } @@ -271,7 +272,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) for addr_type in ADDR_TYPES: # Create route map @@ -280,7 +281,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_" + addr_type @@ -294,7 +295,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): ], "rmap_match_pf_2_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_" + addr_type @@ -309,12 +310,12 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -326,7 +327,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -337,7 +338,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -354,7 +355,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -365,7 +366,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -379,23 +380,23 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] # dual stack changes for addr_type in ADDR_TYPES: result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result4 is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result4) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -405,21 +406,21 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result4 = verify_bgp_attributes(tgen, addr_type, dut, routes[ addr_type],rmap_name, input_dict_3) - assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result4 is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result4) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" # dual stack changes for addr_type in ADDR_TYPES: result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result4 is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result4) # Verifying BGP set attributes - dut = 'r4' + dut = "r4" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -429,7 +430,7 @@ def test_rmap_match_prefix_list_permit_in_and_outbound_prefixes_p0(): rmap_name = "rmap_match_pf_2_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -448,7 +449,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -458,37 +459,37 @@ def test_modify_set_match_clauses_in_rmap_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit', + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit", }], - 'pf_list_2_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "pf_list_2_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit', + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 10, + "network": "any", + "action": "permit", }], - 'pf_list_2_ipv6': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "pf_list_2_ipv6": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -498,7 +499,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -510,7 +511,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): }], "rmap_match_pf_2_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -524,12 +525,12 @@ def test_modify_set_match_clauses_in_rmap_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -541,7 +542,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -552,7 +553,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -569,7 +570,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -580,7 +581,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -593,21 +594,21 @@ def test_modify_set_match_clauses_in_rmap_p0(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -617,21 +618,21 @@ def test_modify_set_match_clauses_in_rmap_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result4 = verify_bgp_attributes(tgen, addr_type, dut, routes[ addr_type],rmap_name, input_dict_3) - assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result4 is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result4) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" # dual stack changes for addr_type in ADDR_TYPES: result4 = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result4 is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result4 is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result4) # Verifying BGP set attributes - dut = 'r4' + dut = "r4" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -640,7 +641,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): rmap_name = "rmap_match_pf_2_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[ addr_type],rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Modify set/match clause of in-used route map @@ -650,7 +651,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -662,7 +663,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): }], "rmap_match_pf_2_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -676,20 +677,20 @@ def test_modify_set_match_clauses_in_rmap_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -698,20 +699,20 @@ def test_modify_set_match_clauses_in_rmap_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r4' + dut = "r4" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -720,7 +721,7 @@ def test_modify_set_match_clauses_in_rmap_p0(): rmap_name = "rmap_match_pf_2_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -739,7 +740,7 @@ def test_delete_route_maps_p1(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -763,22 +764,22 @@ def test_delete_route_maps_p1(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Delete route maps for addr_type in ADDR_TYPES: input_dict = { - 'r3': { - 'route_maps': ['rmap_match_tag_1_{}'.format(addr_type)] + "r3": { + "route_maps": ["rmap_match_tag_1_{}".format(addr_type)] } } result = delete_route_maps(tgen, input_dict) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) result = verify_route_maps(tgen, input_dict) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -797,7 +798,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -806,27 +807,27 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit', + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit", }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit', + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit", }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -836,7 +837,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -849,7 +850,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): }], "rmap_match_pf_2_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -863,12 +864,12 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -880,7 +881,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -891,7 +892,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -908,7 +909,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -919,7 +920,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -933,21 +934,21 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -956,20 +957,20 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r4' + dut = "r4" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -979,55 +980,55 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): rmap_name = "rmap_match_pf_2_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Modify ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'deny' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "deny" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'deny' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "deny" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) sleep(5) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, - protocol=protocol) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behaviour: routes are not present \n ' - 'Error: {}'.format( + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n" + "routes are not present \n Error: {}".format( tc_name, result) + logger.info("Expected behaviour: {}".format(result)) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, - protocol=protocol) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behaviour: routes are not present \n ' - 'Error: {}'.format( + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n" + "Expected behaviour: routes are not present \n " + "Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -1038,7 +1039,7 @@ def test_modify_prefix_list_referenced_by_rmap_p0(): def test_remove_prefix_list_referenced_by_rmap_p0(): """ - TC_50_1: + TC_50_2: Remove prefix-list referencec by route-map match cluase and verifying it reflecting as intended """ @@ -1046,7 +1047,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -1055,27 +1056,27 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -1085,7 +1086,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -1097,7 +1098,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): }], "rmap_match_pf_2_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -1111,13 +1112,13 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map for addr_type in ADDR_TYPES: input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -1129,7 +1130,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -1140,7 +1141,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -1157,7 +1158,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -1168,7 +1169,7 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -1181,21 +1182,21 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -1204,20 +1205,20 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r4' + dut = "r4" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -1226,67 +1227,67 @@ def test_remove_prefix_list_referenced_by_rmap_p0(): rmap_name = "rmap_match_pf_2_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Remove/Delete prefix list input_dict_3 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit', - 'delete': True + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit", + "delete": True }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit', - 'delete': True + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit", + "delete": True }] } } } } result = create_prefix_lists(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) result = verify_prefix_lists(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Api call to clear bgp, so config changes would be reflected - dut = 'r3' + dut = "r3" result = clear_bgp_and_verify(tgen, topo, dut) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, - protocol=protocol) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behaviour: routes are not present \n ' - 'Error: {}'.format( + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n" + "routes are not present \n Error: {}".format( tc_name, result) + logger.info("Expected behaviour: {}".format(result)) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, - protocol=protocol) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behaviour: routes are not present \n ' - 'Error: {}'.format( - tc_name, result) + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n" + "routes are not present \n Error: {}".\ + format(tc_name, result) + logger.info("Expected behaviour: {}".format(result)) write_test_footer(tc_name) @@ -1304,7 +1305,7 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -1329,12 +1330,12 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): } } result = create_route_maps(tgen, input_dict_5) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_6 = { - 'r1': { + "r1": { "bgp": { "address_family": { "ipv4": { @@ -1345,7 +1346,7 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): "r1": { "route_maps": [{ "name": "rm_r1_out_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -1361,7 +1362,7 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): "r1": { "route_maps": [{ "name": "rm_r1_out_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -1375,7 +1376,7 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): } result = create_router_bgp(tgen, topo, input_dict_6) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) for addr_type in ADDR_TYPES: @@ -1394,9 +1395,14 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): } } result = create_bgp_community_lists(tgen, input_dict_1) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) + # Verify BGP large community is created + result = verify_create_community_list(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + for addr_type in ADDR_TYPES: # Create route map input_dict_2 = { @@ -1415,12 +1421,12 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): } } result = create_route_maps(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_3 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -1431,7 +1437,7 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): "r3": { "route_maps": [{ "name": "rm_r3_in_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -1447,7 +1453,7 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): "r3": { "route_maps": [{ "name": "rm_r3_in_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -1461,33 +1467,33 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): } result = create_router_bgp(tgen, topo, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) sleep(5) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verify large-community-list - dut = 'r3' + dut = "r3" networks = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] } input_dict_4 = { - 'largeCommunity': '1:1:1 1:2:3 2:1:1 2:2:2' + "largeCommunity": "1:1:1 1:2:3 2:1:1 2:2:2" } for addr_type in ADDR_TYPES: result = verify_bgp_community(tgen, addr_type, dut, networks[ addr_type],input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -1498,14 +1504,14 @@ def test_add_and_remove_community_list_referenced_by_rmap_p0(): def test_multiple_match_statement_in_route_map_logical_ORed_p0(): """ TC_45: - Test multiple match statements as part of a route-map's single + Test multiple match statements as part of a route-map"s single sequence number. (Logical OR-ed of multiple match statements) """ tgen = get_topogen() global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -1514,20 +1520,20 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): # Api call to advertise networks input_dict_nw1 = { - 'r1': { + "r1": { "bgp": { "address_family": { "ipv4": { "unicast": { "advertise_networks": [ - {"network": '10.0.30.1/32'} + {"network": "10.0.30.1/32"} ] } }, "ipv6": { "unicast": { "advertise_networks": [ - {"network": '1::1/128'} + {"network": "1::1/128"} ] } } @@ -1537,25 +1543,25 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): } result = create_router_bgp(tgen, topo, input_dict_nw1) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Api call to advertise networks input_dict_nw2 = { - 'r1': { + "r1": { "bgp": { "address_family": { "ipv4": { "unicast": { "advertise_networks": [ - {"network": '20.0.30.1/32'} + {"network": "20.0.30.1/32"} ] } }, "ipv6": { "unicast": { "advertise_networks": [ - {"network": '2::1/128'} + {"network": "2::1/128"} ] } } @@ -1565,57 +1571,57 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): } result = create_router_bgp(tgen, topo, input_dict_nw2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_2_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_2_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_2_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_2_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) input_dict_3_addr_type ={} @@ -1626,7 +1632,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -1641,7 +1647,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): } input_dict_3_addr_type[addr_type] = input_dict_3 result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -1651,7 +1657,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -1666,12 +1672,12 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): } input_dict_3_addr_type[addr_type] = input_dict_3 result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_6 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -1683,7 +1689,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -1700,7 +1706,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -1714,21 +1720,21 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): } result = create_router_bgp(tgen, topo, input_dict_6) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.30.1/32"], "ipv6": ["1::1/128"] @@ -1737,7 +1743,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3_addr_type[addr_type]) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes @@ -1748,7 +1754,7 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): for addr_type in ADDR_TYPES: result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -1757,17 +1763,17 @@ def test_multiple_match_statement_in_route_map_logical_ORed_p0(): # tgen.mininet_cli() -def test_multiple_match_statement_in_route_map_logical_ANDed(): +def test_multiple_match_statement_in_route_map_logical_ANDed_p1(): """ TC_44: - Test multiple match statements as part of a route-map's single + Test multiple match statements as part of a route-map"s single sequence number. (Logical AND of multiple match statements) """ tgen = get_topogen() global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -1790,13 +1796,13 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): } } result = create_route_maps(tgen, input_dict_5) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map for addr_type in ADDR_TYPES: input_dict_6 = { - 'r1': { + "r1": { "bgp": { "address_family": { addr_type: { @@ -1808,7 +1814,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): "route_maps": [{ "name": "rm_r1_out_{}".format(addr_type), - "direction": 'out' + "direction": "out" }] } } @@ -1821,25 +1827,25 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): } } result = create_router_bgp(tgen, topo, input_dict_6) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } @@ -1847,7 +1853,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) for addr_type in ADDR_TYPES: @@ -1866,9 +1872,14 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): } } result = create_bgp_community_lists(tgen, input_dict_1) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) + # Verify BGP large community is created + result = verify_create_community_list(tgen, input_dict_1) + assert result is True, "Testcase {} : Failed \n Error: {}".format( + tc_name, result) + # Create route map for addr_type in ADDR_TYPES: input_dict_3 = { @@ -1876,7 +1887,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -1890,7 +1901,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) for addr_type in ADDR_TYPES: @@ -1900,7 +1911,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type : { "large_community_list": {"id": "rmap_lcomm_"+ @@ -1915,12 +1926,12 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map for addr_type in ADDR_TYPES: input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { addr_type: { @@ -1932,7 +1943,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): "route_maps": [{ "name": "rmap_match_pf_1_{}".format(addr_type), - "direction": 'in' + "direction": "in" }] } } @@ -1945,20 +1956,20 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # sleep(10) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -1967,7 +1978,7 @@ def test_multiple_match_statement_in_route_map_logical_ANDed(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -1986,7 +1997,7 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -1995,27 +2006,27 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'deny' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "deny" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'deny' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "deny" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -2025,7 +2036,7 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -2039,12 +2050,12 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -2056,7 +2067,7 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -2073,7 +2084,7 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -2087,24 +2098,24 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, - protocol=protocol) - assert result is not True, 'Testcase {} : \n' - 'Expected Behavior: Routes are not present in RIB \n' - ' Error: {}'.format( + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n Error" + "Routes are still present: {}".format( tc_name, result) + logger.info("Expected behaviour: {}".format(result)) # Remove applied rmap from neighbor input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -2116,7 +2127,7 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in', + "direction": "in", "delete": True }] } @@ -2134,7 +2145,7 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in', + "direction": "in", "delete": True }] } @@ -2149,16 +2160,16 @@ def test_add_remove_rmap_to_specific_neighbor_p0(): } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -2177,7 +2188,7 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -2186,27 +2197,27 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -2216,7 +2227,7 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5', + "seq_id": "5", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -2231,12 +2242,12 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -2248,7 +2259,7 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -2265,7 +2276,7 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -2279,20 +2290,20 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -2301,26 +2312,26 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # clear bgp, so config changes would be reflected - dut = 'r3' + dut = "r3" result = clear_bgp_and_verify(tgen, topo, dut) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -2329,7 +2340,7 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Flap interface to see if route-map properties are intact @@ -2348,19 +2359,19 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): # Verify BGP convergence once interface is up result = verify_bgp_convergence(tgen, topo) assert result is True, ( - 'setup_module :Failed \n Error:' ' {}'.format(result)) + "setup_module :Failed \n Error:" " {}".format(result)) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -2369,7 +2380,7 @@ def test_clear_bgp_and_flap_interface_to_verify_rmap_properties_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -2388,7 +2399,7 @@ def test_rmap_without_match_and_set_clause_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -2402,22 +2413,22 @@ def test_rmap_without_match_and_set_clause_p0(): "route_maps": { "rmap_no_match_set_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '5' + "seq_id": "5" }], "rmap_no_match_set_2_{}".format(addr_type): [{ "action": "deny", - 'seq_id': '5' + "seq_id": "5" }] } } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -2429,7 +2440,7 @@ def test_rmap_without_match_and_set_clause_p0(): "route_maps": [{ "name": "rmap_no_match_set_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -2440,7 +2451,7 @@ def test_rmap_without_match_and_set_clause_p0(): "route_maps": [{ "name": "rmap_no_match_set_2_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -2457,7 +2468,7 @@ def test_rmap_without_match_and_set_clause_p0(): "route_maps": [{ "name": "rmap_no_match_set_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -2468,7 +2479,7 @@ def test_rmap_without_match_and_set_clause_p0(): "route_maps": [{ "name": "rmap_no_match_set_2_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -2482,30 +2493,30 @@ def test_rmap_without_match_and_set_clause_p0(): } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" for addr_type in ADDR_TYPES: - result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behaviour: routes are not present \n ' - 'Error: {}'.format( + result = verify_rib(tgen, addr_type, dut, input_dict, + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n" + "routes are not present \n Error: {}".format( tc_name, result) + logger.info("Expected behaviour: {}".format(result)) write_test_footer(tc_name) - # Uncomment next line for debugging # tgen.mininet_cli() @@ -2520,7 +2531,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -2529,27 +2540,27 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -2597,12 +2608,12 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): } input_dict_3_addr_type[addr_type] = input_dict_3 result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -2614,7 +2625,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -2625,7 +2636,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -2636,7 +2647,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): "route_maps": [{ "name": "rmap_match_pf_3_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -2653,7 +2664,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -2664,7 +2675,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -2675,7 +2686,7 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): "route_maps": [{ "name": "rmap_match_pf_3_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -2689,21 +2700,21 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -2713,20 +2724,20 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[ addr_type],rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r4' + dut = "r4" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -2736,22 +2747,23 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): rmap_name = "rmap_match_pf_2_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], - rmap_name, input_dict_3_addr_type[addr_type]) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behaviour: Attributes are not set \n' - 'Error: {}'.format( + rmap_name, input_dict_3_addr_type[addr_type], + expected=False) + assert result is not True, "Testcase {} : Failed \n" + "Attributes are not set \n Error: {}".format( tc_name, result) + logger.info("Expected behaviour: {}".format(result)) # Verifying RIB routes - dut = 'r5' - protocol = 'bgp' + dut = "r5" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r5' + dut = "r5" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -2761,12 +2773,11 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): for addr_type in ADDR_TYPES: rmap_name = "rmap_match_pf_3_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], - rmap_name, input_dict_3_addr_type[addr_type]) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behaviour: Attributes are not set \n' - 'Error: {}'.format( + rmap_name, input_dict_3_addr_type[addr_type], + expected=False) + assert result is not True, "Testcase {} : Failed \n" + "Attributes are not set \n Error: {}".format( tc_name, result) - logger.info("Expected behaviour: {}".format(result)) write_test_footer(tc_name) @@ -2778,14 +2789,14 @@ def test_set_localpref_weight_to_ebgp_and_med_to_ibgp_peers_p0(): def test_multiple_set_on_single_sequence_in_rmap_p0(): """ TC_43: - Test multiple set statements as part of a route-map's + Test multiple set statements as part of a route-map"s single sequence number. """ tgen = get_topogen() global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -2794,27 +2805,27 @@ def test_multiple_set_on_single_sequence_in_rmap_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -2839,12 +2850,12 @@ def test_multiple_set_on_single_sequence_in_rmap_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -2856,7 +2867,7 @@ def test_multiple_set_on_single_sequence_in_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -2873,7 +2884,7 @@ def test_multiple_set_on_single_sequence_in_rmap_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -2886,20 +2897,20 @@ def test_multiple_set_on_single_sequence_in_rmap_p0(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -2910,7 +2921,7 @@ def test_multiple_set_on_single_sequence_in_rmap_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -2928,7 +2939,7 @@ def test_route_maps_with_continue_clause_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -2937,27 +2948,27 @@ def test_route_maps_with_continue_clause_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -2967,7 +2978,7 @@ def test_route_maps_with_continue_clause_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '10', + "seq_id": "10", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -2980,7 +2991,7 @@ def test_route_maps_with_continue_clause_p0(): }, { "action": "permit", - 'seq_id': '20', + "seq_id": "20", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -2992,7 +3003,7 @@ def test_route_maps_with_continue_clause_p0(): }, { "action": "permit", - 'seq_id': '30', + "seq_id": "30", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -3007,12 +3018,12 @@ def test_route_maps_with_continue_clause_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -3024,7 +3035,7 @@ def test_route_maps_with_continue_clause_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -3041,7 +3052,7 @@ def test_route_maps_with_continue_clause_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -3054,21 +3065,21 @@ def test_route_maps_with_continue_clause_p0(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" rmap_name = "rmap_match_pf_1" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], @@ -3082,7 +3093,7 @@ def test_route_maps_with_continue_clause_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[ addr_type],rmap_name, input_dict_3, seq_id[addr_type]) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -3100,7 +3111,7 @@ def test_route_maps_with_goto_clause_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -3109,27 +3120,27 @@ def test_route_maps_with_goto_clause_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -3139,7 +3150,7 @@ def test_route_maps_with_goto_clause_p0(): "route_maps": { "rmap_match_pf_1_{}".format(addr_type): [{ "action": "permit", - 'seq_id': '10', + "seq_id": "10", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -3149,7 +3160,7 @@ def test_route_maps_with_goto_clause_p0(): }, { "action": "permit", - 'seq_id': '20', + "seq_id": "20", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -3161,7 +3172,7 @@ def test_route_maps_with_goto_clause_p0(): }, { "action": "permit", - 'seq_id': '30', + "seq_id": "30", "match": { addr_type: { "prefix_lists": "pf_list_1_{}".format(addr_type) @@ -3176,12 +3187,13 @@ def test_route_maps_with_goto_clause_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + # tgen.mininet_cli() + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -3193,7 +3205,7 @@ def test_route_maps_with_goto_clause_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -3210,7 +3222,7 @@ def test_route_maps_with_goto_clause_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -3223,20 +3235,20 @@ def test_route_maps_with_goto_clause_p0(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" rmap_name = "rmap_match_pf_1" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], @@ -3250,7 +3262,7 @@ def test_route_maps_with_goto_clause_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[ addr_type],rmap_name, input_dict_3, seq_id[addr_type]) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -3268,7 +3280,7 @@ def test_route_maps_with_call_clause_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -3277,27 +3289,27 @@ def test_route_maps_with_call_clause_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -3332,12 +3344,12 @@ def test_route_maps_with_call_clause_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -3349,7 +3361,7 @@ def test_route_maps_with_call_clause_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -3366,7 +3378,7 @@ def test_route_maps_with_call_clause_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv6", - "direction": 'in' + "direction": "in" }] } } @@ -3379,20 +3391,20 @@ def test_route_maps_with_call_clause_p0(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying BGP set attributes - dut = 'r3' + dut = "r3" routes = { "ipv4": ["10.0.20.1/32", "10.0.20.2/32"], "ipv6": ["1::1/128", "1::2/128"] @@ -3402,7 +3414,7 @@ def test_route_maps_with_call_clause_p0(): rmap_name = "rmap_match_pf_1_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) rmap_name = "rmap_match_pf_2" @@ -3410,7 +3422,7 @@ def test_route_maps_with_call_clause_p0(): rmap_name = "rmap_match_pf_2_{}".format(addr_type) result = verify_bgp_attributes(tgen, addr_type, dut, routes[addr_type], rmap_name, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -3429,7 +3441,7 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -3438,27 +3450,27 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): # Create ip prefix list input_dict_2 = { - 'r3': { - 'prefix_lists': { - 'ipv4': { - 'pf_list_1_ipv4': [{ - 'seqid': 10, - 'network': 'any', - 'action': 'permit' + "r3": { + "prefix_lists": { + "ipv4": { + "pf_list_1_ipv4": [{ + "seqid": 10, + "network": "any", + "action": "permit" }] }, - 'ipv6': { - 'pf_list_1_ipv6': [{ - 'seqid': 100, - 'network': 'any', - 'action': 'permit' + "ipv6": { + "pf_list_1_ipv6": [{ + "seqid": 100, + "network": "any", + "action": "permit" }] } } } } result = create_prefix_lists(tgen, input_dict_2) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Create route map @@ -3492,12 +3504,12 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r3': { + "r3": { "bgp": { "address_family": { "ipv4": { @@ -3509,7 +3521,7 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -3520,7 +3532,7 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -3537,7 +3549,7 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_pf_1_ipv4", - "direction": 'in' + "direction": "in" }] } } @@ -3548,7 +3560,7 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_pf_2_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -3561,31 +3573,31 @@ def test_create_rmap_match_prefix_list_to_deny_in_and_outbound_prefixes_p0(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" input_dict = topo["routers"] for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, - protocol=protocol) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behaviour: routes are not present \n ' - 'Error: {}'.format( - tc_name, result) + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n" + "routes are not present \n Error: {}".\ + format(tc_name, result) + logger.info("Expected behaviour: {}".format(result)) # Verifying RIB routes - dut = 'r4' - protocol = 'bgp' + dut = "r4" + protocol = "bgp" for addr_type in ADDR_TYPES: result = verify_rib(tgen, addr_type, dut, input_dict, - protocol=protocol) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behaviour: routes are not present \n ' - 'Error: {}'.format( - tc_name, result) + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n" + "routes are not present \n Error: {}".\ + format(tc_name, result) + logger.info("Expected behaviour: {}".format(result)) write_test_footer(tc_name) @@ -3603,7 +3615,7 @@ def test_create_rmap_to_match_tag_permit_inbound_prefixes_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -3675,12 +3687,12 @@ def test_create_rmap_to_match_tag_permit_inbound_prefixes_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r1': { + "r1": { "bgp": { "address_family": { "ipv4": { @@ -3692,7 +3704,7 @@ def test_create_rmap_to_match_tag_permit_inbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_tag_1_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -3709,7 +3721,7 @@ def test_create_rmap_to_match_tag_permit_inbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_tag_1_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -3722,12 +3734,12 @@ def test_create_rmap_to_match_tag_permit_inbound_prefixes_p0(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" for addr_type in ADDR_TYPES: input_dict = { @@ -3743,7 +3755,7 @@ def test_create_rmap_to_match_tag_permit_inbound_prefixes_p0(): } result = verify_rib(tgen, addr_type, dut, input_dict, protocol=protocol) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) write_test_footer(tc_name) @@ -3762,7 +3774,7 @@ def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0(): global bgp_convergence if bgp_convergence is not True: - pytest.skip('skipped because of BGP Convergence failure') + pytest.skip("skipped because of BGP Convergence failure") # test case name tc_name = inspect.stack()[0][3] @@ -3834,12 +3846,12 @@ def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0(): } } result = create_route_maps(tgen, input_dict_3) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Configure neighbor for route map input_dict_4 = { - 'r1': { + "r1": { "bgp": { "address_family": { "ipv4": { @@ -3851,7 +3863,7 @@ def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_tag_1_ipv4", - "direction": 'out' + "direction": "out" }] } } @@ -3868,7 +3880,7 @@ def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0(): "route_maps": [{ "name": "rmap_match_tag_1_ipv6", - "direction": 'out' + "direction": "out" }] } } @@ -3881,12 +3893,12 @@ def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0(): } } result = create_router_bgp(tgen, topo, input_dict_4) - assert result is True, 'Testcase {} : Failed \n Error: {}'.format( + assert result is True, "Testcase {} : Failed \n Error: {}".format( tc_name, result) # Verifying RIB routes - dut = 'r3' - protocol = 'bgp' + dut = "r3" + protocol = "bgp" for addr_type in ADDR_TYPES: input_dict = { @@ -3901,16 +3913,17 @@ def test_create_rmap_to_match_tag_deny_outbound_prefixes_p0(): } } result = verify_rib(tgen, addr_type, dut, input_dict, - protocol=protocol) - assert result is not True, 'Testcase {} : Failed \n' - 'Expected behavior: routes are denied \n Error: {}'.format( + protocol=protocol, expected=False) + assert result is not True, "Testcase {} : Failed \n" + "routes are denied \n Error: {}".format( tc_name, result) + logger.info("Expected behaviour: {}".format(result)) write_test_footer(tc_name) # Uncomment next line for debugging # tgen.mininet_cli() -if __name__ == '__main__': +if __name__ == "__main__": args = ["-s"] + sys.argv[1:] sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_aggregate-address_origin/__init__.py b/tests/topotests/bgp_aggregate-address_origin/__init__.py new file mode 100644 index 0000000000..e69de29bb2 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_origin/__init__.py diff --git a/tests/topotests/bgp_aggregate-address_origin/r1/bgpd.conf b/tests/topotests/bgp_aggregate-address_origin/r1/bgpd.conf new file mode 100644 index 0000000000..528d02af36 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_origin/r1/bgpd.conf @@ -0,0 +1,7 @@ +router bgp 65000 + neighbor 192.168.255.2 remote-as 65001 + address-family ipv4 unicast + redistribute connected + aggregate-address 172.16.255.0/24 origin igp + exit-address-family +! diff --git a/tests/topotests/bgp_aggregate-address_origin/r1/zebra.conf b/tests/topotests/bgp_aggregate-address_origin/r1/zebra.conf new file mode 100644 index 0000000000..0a283c06d5 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_origin/r1/zebra.conf @@ -0,0 +1,9 @@ +! +interface lo + ip address 172.16.255.254/32 +! +interface r1-eth0 + ip address 192.168.255.1/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_aggregate-address_origin/r2/bgpd.conf b/tests/topotests/bgp_aggregate-address_origin/r2/bgpd.conf new file mode 100644 index 0000000000..73d4d0aeea --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_origin/r2/bgpd.conf @@ -0,0 +1,4 @@ +router bgp 65001 + neighbor 192.168.255.1 remote-as 65000 + exit-address-family +! diff --git a/tests/topotests/bgp_aggregate-address_origin/r2/zebra.conf b/tests/topotests/bgp_aggregate-address_origin/r2/zebra.conf new file mode 100644 index 0000000000..606c17bec9 --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_origin/r2/zebra.conf @@ -0,0 +1,6 @@ +! +interface r2-eth0 + ip address 192.168.255.2/24 +! +ip forwarding +! diff --git a/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py b/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py new file mode 100644 index 0000000000..be29d143dd --- /dev/null +++ b/tests/topotests/bgp_aggregate-address_origin/test_bgp_aggregate-address_origin.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python + +# +# bgp_aggregate-address_origin.py +# Part of NetDEF Topology Tests +# +# Copyright (c) 2020 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. +# + +""" +bgp_aggregate-address_origin.py: + +Test if works the following commands: +router bgp 65031 + address-family ipv4 unicast + aggregate-address 192.168.255.0/24 origin igp +""" + +import os +import sys +import json +import time +import pytest +import functools + +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger +from mininet.topo import Topo + +class TemplateTopo(Topo): + def build(self, *_args, **_opts): + tgen = get_topogen(self) + + for routern in range(1, 3): + tgen.add_router('r{}'.format(routern)) + + switch = tgen.add_switch('s1') + switch.add_link(tgen.gears['r1']) + switch.add_link(tgen.gears['r2']) + +def setup_module(mod): + tgen = Topogen(TemplateTopo, mod.__name__) + tgen.start_topology() + + router_list = tgen.routers() + + for i, (rname, router) in enumerate(router_list.iteritems(), 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_aggregate_address_origin(): + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + router = tgen.gears['r2'] + + def _bgp_converge(router): + output = json.loads(router.vtysh_cmd("show ip bgp neighbor 192.168.255.1 json")) + expected = { + '192.168.255.1': { + 'bgpState': 'Established', + 'addressFamilyInfo': { + 'ipv4Unicast': { + 'acceptedPrefixCounter': 3 + } + } + } + } + return topotest.json_cmp(output, expected) + + def _bgp_aggregate_address_has_metric(router): + output = json.loads(router.vtysh_cmd("show ip bgp 172.16.255.0/24 json")) + expected = { + 'paths': [ + { + 'origin': 'IGP' + } + ] + } + return topotest.json_cmp(output, expected) + + test_func = functools.partial(_bgp_converge, router) + success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, 'Failed to see bgp convergence in "{}"'.format(router) + + test_func = functools.partial(_bgp_aggregate_address_has_metric, router) + success, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5) + + assert result is None, 'Failed to see applied ORIGIN (igp) for aggregated prefix in "{}"'.format(router) + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) diff --git a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py index 7607fe986b..c851567dda 100755 --- a/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py +++ b/tests/topotests/bgp_multiview_topo1/test_bgp_multiview_topo1.py @@ -151,8 +151,7 @@ def setup_module(module): net['r%s' % i].startRouter() # Starting PE Hosts and init ExaBGP on each of them - print('*** Starting BGP on all 8 Peers in 10s') - sleep(10) + print('*** Starting BGP on all 8 Peers') for i in range(1, 9): net['peer%s' % i].cmd('cp %s/exabgp.env /etc/exabgp/exabgp.env' % thisDir) net['peer%s' % i].cmd('cp %s/peer%s/* /etc/exabgp/' % (thisDir, i)) @@ -191,7 +190,6 @@ def test_router_running(): print("\n\n** Check if FRR/Quagga is running on each Router node") print("******************************************\n") - sleep(5) # Starting Routers for i in range(1, 2): @@ -215,7 +213,7 @@ def test_bgp_converge(): # Wait for BGP to converge (All Neighbors in either Full or TwoWay State) print("\n\n** Verify for BGP to converge") print("******************************************\n") - timeout = 60 + timeout = 125 while timeout > 0: print("Timeout in %s: " % timeout), sys.stdout.flush() @@ -240,9 +238,9 @@ def test_bgp_converge(): bgpStatus = net['r%s' % i].cmd('vtysh -c "show ip bgp view %s summary"' % view) assert False, "BGP did not converge:\n%s" % bgpStatus - # Wait for an extra 30s to announce all routes - print('Waiting 30s for routes to be announced'); - sleep(30) + # Wait for an extra 5s to announce all routes + print('Waiting 5s for routes to be announced'); + sleep(5) print("BGP converged.") diff --git a/tests/topotests/evpn-pim-1/host1/bgpd.conf b/tests/topotests/evpn-pim-1/host1/bgpd.conf new file mode 100644 index 0000000000..cdf4cb4feb --- /dev/null +++ b/tests/topotests/evpn-pim-1/host1/bgpd.conf @@ -0,0 +1 @@ +! diff --git a/tests/topotests/evpn-pim-1/host1/pimd.conf b/tests/topotests/evpn-pim-1/host1/pimd.conf new file mode 100644 index 0000000000..63a44c1333 --- /dev/null +++ b/tests/topotests/evpn-pim-1/host1/pimd.conf @@ -0,0 +1,4 @@ +int lo +! + + diff --git a/tests/topotests/evpn-pim-1/host1/zebra.conf b/tests/topotests/evpn-pim-1/host1/zebra.conf new file mode 100644 index 0000000000..45ad031017 --- /dev/null +++ b/tests/topotests/evpn-pim-1/host1/zebra.conf @@ -0,0 +1,5 @@ +int host1-eth0 + ip addr 192.168.3.4/24 + +int lo + ip addr 192.168.100.4/32 diff --git a/tests/topotests/evpn-pim-1/host2/bgpd.conf b/tests/topotests/evpn-pim-1/host2/bgpd.conf new file mode 100644 index 0000000000..cdf4cb4feb --- /dev/null +++ b/tests/topotests/evpn-pim-1/host2/bgpd.conf @@ -0,0 +1 @@ +! diff --git a/tests/topotests/evpn-pim-1/host2/pimd.conf b/tests/topotests/evpn-pim-1/host2/pimd.conf new file mode 100644 index 0000000000..63a44c1333 --- /dev/null +++ b/tests/topotests/evpn-pim-1/host2/pimd.conf @@ -0,0 +1,4 @@ +int lo +! + + diff --git a/tests/topotests/evpn-pim-1/host2/zebra.conf b/tests/topotests/evpn-pim-1/host2/zebra.conf new file mode 100644 index 0000000000..bfae53017f --- /dev/null +++ b/tests/topotests/evpn-pim-1/host2/zebra.conf @@ -0,0 +1,5 @@ +int host-eth0 + ip addr 192.168.4.5/24 + +int lo + ip addr 192.168.100.5/32 diff --git a/tests/topotests/evpn-pim-1/leaf1/bgpd.conf b/tests/topotests/evpn-pim-1/leaf1/bgpd.conf new file mode 100644 index 0000000000..33d34db677 --- /dev/null +++ b/tests/topotests/evpn-pim-1/leaf1/bgpd.conf @@ -0,0 +1,9 @@ + +router bgp 65002 + neighbor 192.168.1.1 remote-as external + redistribute connected + address-family l2vpn evpn + neighbor 192.168.1.1 activate + advertise-all-vni + ! +!
\ No newline at end of file diff --git a/tests/topotests/evpn-pim-1/leaf1/pimd.conf b/tests/topotests/evpn-pim-1/leaf1/pimd.conf new file mode 100644 index 0000000000..293e252086 --- /dev/null +++ b/tests/topotests/evpn-pim-1/leaf1/pimd.conf @@ -0,0 +1,15 @@ +debug pim events +debug pim nht +debug pim zebra +ip pim rp 192.168.100.1 +! +int lo + ip pim +! +int leaf1-eth0 + ip pim +! +int leaf1-eth1 + ip pim + ip igmp + diff --git a/tests/topotests/evpn-pim-1/leaf1/zebra.conf b/tests/topotests/evpn-pim-1/leaf1/zebra.conf new file mode 100644 index 0000000000..581cc6e7be --- /dev/null +++ b/tests/topotests/evpn-pim-1/leaf1/zebra.conf @@ -0,0 +1,6 @@ +int leaf1-eth0 + ip addr 192.168.1.2/24 +int leaf1-eth1 + ip addr 192.168.3.2/24 +int lo + ip addr 192.168.100.2/32 diff --git a/tests/topotests/evpn-pim-1/leaf2/bgpd.conf b/tests/topotests/evpn-pim-1/leaf2/bgpd.conf new file mode 100644 index 0000000000..3dd9f237be --- /dev/null +++ b/tests/topotests/evpn-pim-1/leaf2/bgpd.conf @@ -0,0 +1,9 @@ + +router bgp 65003 + neighbor 192.168.2.1 remote-as external + redistribute connected + address-family l2vpn evpn + neighbor 192.168.2.1 activate + advertise-all-vni + ! +!
\ No newline at end of file diff --git a/tests/topotests/evpn-pim-1/leaf2/pimd.conf b/tests/topotests/evpn-pim-1/leaf2/pimd.conf new file mode 100644 index 0000000000..08d5a19a2a --- /dev/null +++ b/tests/topotests/evpn-pim-1/leaf2/pimd.conf @@ -0,0 +1,13 @@ +ip pim rp 192.168.100.1 +! +int lo + ip pim +! +int leaf2-eth0 + ip pim +! +int leaf2-eth1 + ip pim + ip igmp +! + diff --git a/tests/topotests/evpn-pim-1/leaf2/zebra.conf b/tests/topotests/evpn-pim-1/leaf2/zebra.conf new file mode 100644 index 0000000000..1bcf8e1ded --- /dev/null +++ b/tests/topotests/evpn-pim-1/leaf2/zebra.conf @@ -0,0 +1,6 @@ +int leaf2-eth0 + ip addr 192.168.2.3/24 +int leaf2-eth1 + ip addr 192.168.4.3/24 +int lo + ip addr 192.168.100.3/32 diff --git a/tests/topotests/evpn-pim-1/spine/bgp.summ.json b/tests/topotests/evpn-pim-1/spine/bgp.summ.json new file mode 100644 index 0000000000..faf40c8d43 --- /dev/null +++ b/tests/topotests/evpn-pim-1/spine/bgp.summ.json @@ -0,0 +1,44 @@ +{ + "routerId":"192.168.100.1", + "as":65001, + "vrfId":0, + "vrfName":"default", + "tableVersion":7, + "peerCount":2, + "peers":{ + "192.168.1.2":{ + "remoteAs":65002, + "version":4, + "tableVersion":0, + "outq":0, + "inq":0, + "prefixReceivedCount":3, + "pfxRcd":3, + "pfxSnt":7, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + }, + "192.168.2.3":{ + "remoteAs":65003, + "version":4, + "tableVersion":0, + "outq":0, + "inq":0, + "prefixReceivedCount":3, + "pfxRcd":3, + "pfxSnt":7, + "state":"Established", + "connectionsEstablished":1, + "connectionsDropped":0, + "idType":"ipv4" + } + }, + "failedPeers":0, + "totalPeers":2, + "dynamicPeers":0, + "bestPath":{ + "multiPathRelax":"false" + } +} diff --git a/tests/topotests/evpn-pim-1/spine/bgpd.conf b/tests/topotests/evpn-pim-1/spine/bgpd.conf new file mode 100644 index 0000000000..9a845043e9 --- /dev/null +++ b/tests/topotests/evpn-pim-1/spine/bgpd.conf @@ -0,0 +1,10 @@ + +router bgp 65001 + neighbor 192.168.1.2 remote-as external + neighbor 192.168.2.3 remote-as external + redistribute connected + address-family l2vpn evpn + neighbor 192.168.1.2 activate + neighbor 192.168.2.3 activate + exit-address-family +! diff --git a/tests/topotests/evpn-pim-1/spine/join-info.json b/tests/topotests/evpn-pim-1/spine/join-info.json new file mode 100644 index 0000000000..3d135fb964 --- /dev/null +++ b/tests/topotests/evpn-pim-1/spine/join-info.json @@ -0,0 +1,34 @@ +{ + "spine-eth0":{ + "name":"spine-eth0", + "state":"up", + "address":"192.168.1.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.1.1.1":{ + "*":{ + "source":"*", + "group":"239.1.1.1", + "prune":"--:--", + "channelJoinName":"JOIN" + } + } + }, + "spine-eth1":{ + "name":"spine-eth1", + "state":"up", + "address":"192.168.2.1", + "flagMulticast":true, + "flagBroadcast":true, + "lanDelayEnabled":true, + "239.1.1.1":{ + "*":{ + "source":"*", + "group":"239.1.1.1", + "prune":"--:--", + "channelJoinName":"JOIN" + } + } + } +} diff --git a/tests/topotests/evpn-pim-1/spine/pimd.conf b/tests/topotests/evpn-pim-1/spine/pimd.conf new file mode 100644 index 0000000000..56adda5cc4 --- /dev/null +++ b/tests/topotests/evpn-pim-1/spine/pimd.conf @@ -0,0 +1,13 @@ +ip pim rp 192.168.100.1 +! +int lo + ip pim +! +int spine-eth0 + ip pim +! +int spine-eth1 + ip pim +! + + diff --git a/tests/topotests/evpn-pim-1/spine/zebra.conf b/tests/topotests/evpn-pim-1/spine/zebra.conf new file mode 100644 index 0000000000..2cb719486e --- /dev/null +++ b/tests/topotests/evpn-pim-1/spine/zebra.conf @@ -0,0 +1,8 @@ +int spine-eth0 + ip addr 192.168.1.1/24 +! +int spine-eth1 + ip addr 192.168.2.1/24 +! +int lo + ip addr 192.168.100.1/32 diff --git a/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py new file mode 100755 index 0000000000..dafe2e03ac --- /dev/null +++ b/tests/topotests/evpn-pim-1/test_evpn_pim_topo1.py @@ -0,0 +1,215 @@ +#!/usr/bin/env python + +# +# test_evpn-pim_topo1.py +# +# Copyright (c) 2017 by +# Cumulus Networks, Inc. +# Donald Sharp +# +# 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_evpn_pim_topo1.py: Testing evpn-pim + +""" + +import os +import re +import sys +import pytest +import json +from functools import partial + +# Save the Current Working Directory to find configuration files. +CWD = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(os.path.join(CWD, '../')) + +# pylint: disable=C0413 +# Import topogen and topotest helpers +from lib import topotest +from lib.topogen import Topogen, TopoRouter, get_topogen +from lib.topolog import logger + +# Required to instantiate the topology builder class. +from mininet.topo import Topo + +##################################################### +## +## Network Topology Definition +## +##################################################### + +class NetworkTopo(Topo): + "evpn-pim Topology 1" + + def build(self, **_opts): + "Build function" + + tgen = get_topogen(self) + + tgen.add_router('spine') + tgen.add_router('leaf1') + tgen.add_router('leaf2') + tgen.add_router('host1') + tgen.add_router('host2') + + # On main router + # First switch is for a dummy interface (for local network) + # spine-eth0 is connected to leaf1-eth0 + switch = tgen.add_switch('sw1') + switch.add_link(tgen.gears['spine']) + switch.add_link(tgen.gears['leaf1']) + + # spine-eth1 is connected to leaf2-eth0 + switch = tgen.add_switch('sw2') + switch.add_link(tgen.gears['spine']) + switch.add_link(tgen.gears['leaf2']) + + # leaf1-eth1 is connected to host1-eth0 + switch = tgen.add_switch('sw3') + switch.add_link(tgen.gears['leaf1']) + switch.add_link(tgen.gears['host1']) + + # leaf2-eth1 is connected to host2-eth0 + switch = tgen.add_switch('sw4') + switch.add_link(tgen.gears['leaf2']) + switch.add_link(tgen.gears['host2']) + + + +##################################################### +## +## Tests starting +## +##################################################### + +def setup_module(module): + "Setup topology" + tgen = Topogen(NetworkTopo, module.__name__) + tgen.start_topology() + + leaf1 = tgen.gears['leaf1'] + leaf2 = tgen.gears['leaf2'] + + leaf1.run('brctl addbr brleaf1') + leaf2.run('brctl addbr brleaf2') + leaf1.run('ip link set dev brleaf1 up') + leaf2.run('ip link set dev brleaf2 up') + leaf1.run('ip link add vxlan0 type vxlan id 42 group 239.1.1.1 dev leaf1-eth1 dstport 4789') + leaf2.run('ip link add vxlan0 type vxlan id 42 group 239.1.1.1 dev leaf2-eth1 dstport 4789') + leaf1.run('brctl addif brleaf1 vxlan0') + leaf2.run('brctl addif brleaf2 vxlan0') + leaf1.run('ip link set up dev vxlan0') + leaf2.run('ip link set up dev vxlan0') + #tgen.mininet_cli() + # This is a sample of configuration loading. + router_list = tgen.routers() + for rname, router in router_list.iteritems(): + router.load_config( + TopoRouter.RD_ZEBRA, + os.path.join(CWD, '{}/zebra.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_BGP, + os.path.join(CWD, '{}/bgpd.conf'.format(rname)) + ) + router.load_config( + TopoRouter.RD_PIM, + os.path.join(CWD, '{}/pimd.conf'.format(rname)) + ) + tgen.start_router() + #tgen.mininet_cli() + +def teardown_module(_mod): + "Teardown the pytest environment" + tgen = get_topogen() + + # This function tears down the whole topology. + tgen.stop_topology() + + +def test_converge_protocols(): + "Wait for protocol convergence" + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + spine = tgen.gears['spine'] + json_file = '{}/{}/bgp.summ.json'.format(CWD, spine.name) + expected = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, + spine, 'show bgp ipv4 uni summ json', expected) + _, result = topotest.run_and_expect(test_func, None, count=125, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(spine.name) + assert result is None, assertmsg + #tgen.mininet_cli() + +def test_multicast_groups_on_rp(): + "Ensure the multicast groups show up on the spine" + # This test implicitly tests the auto mcast groups + # of the created vlans and then the auto-joins that + # pim will do to the RP( spine ) + + tgen = get_topogen() + + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + spine = tgen.gears['spine'] + json_file = '{}/{}/join-info.json'.format(CWD, spine.name) + expected = json.loads(open(json_file).read()) + + test_func = partial(topotest.router_json_cmp, + spine, 'show ip pim join json', expected) + _, result = topotest.run_and_expect(test_func, None, count=30, wait=1) + assertmsg = '"{}" JSON output mismatches'.format(spine.name) + assert result is None, assertmsg + #tgen.mininet_cli() + +def test_shutdown_check_stderr(): + if os.environ.get('TOPOTESTS_CHECK_STDERR') is None: + pytest.skip('Skipping test for Stderr output and memory leaks') + + tgen = get_topogen() + # Don't run this test if we have any failure. + if tgen.routers_have_failure(): + pytest.skip(tgen.errors) + + logger.info("Verifying unexpected STDERR output from daemons") + + router_list = tgen.routers().values() + for router in router_list: + router.stop() + + log = tgen.net[router.name].getStdErr('pimd') + if log: + logger.error('PIMd StdErr Log:' + log) + log = tgen.net[router.name].getStdErr('bgpd') + if log: + logger.error('BGPd StdErr Log:' + log) + log = tgen.net[router.name].getStdErr('zebra') + if log: + logger.error('Zebra StdErr Log:' + log) + + +if __name__ == '__main__': + args = ["-s"] + sys.argv[1:] + sys.exit(pytest.main(args)) + diff --git a/tests/topotests/lib/bgp.py b/tests/topotests/lib/bgp.py index a8354f4c77..f3c17be684 100644 --- a/tests/topotests/lib/bgp.py +++ b/tests/topotests/lib/bgp.py @@ -1293,16 +1293,13 @@ def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name, for static_route in static_routes: cmd = "show bgp {} {} json".format(addr_type, static_route) show_bgp_json = run_frr_cmd(rnode, cmd, isjson=True) - print("show_bgp_json $$$$$", show_bgp_json) dict_to_test = [] tmp_list = [] for rmap_router in input_dict.keys(): for rmap, values in input_dict[rmap_router][ "route_maps"].items(): - print("rmap == rmap_name $$$$1", rmap, rmap_name) if rmap == rmap_name: - print("rmap == rmap_name $$$$", rmap, rmap_name) dict_to_test = values for rmap_dict in values: if seq_id is not None: @@ -1318,7 +1315,6 @@ def verify_bgp_attributes(tgen, addr_type, dut, static_routes, rmap_name, if tmp_list: dict_to_test = tmp_list - print("dict_to_test $$$$", dict_to_test) for rmap_dict in dict_to_test: if "set" in rmap_dict: for criteria in rmap_dict["set"].keys(): diff --git a/tests/topotests/rip-topo1/r1/rip_status.ref b/tests/topotests/rip-topo1/r1/rip_status.ref index 30c840e508..d75fbe85bb 100644 --- a/tests/topotests/rip-topo1/r1/rip_status.ref +++ b/tests/topotests/rip-topo1/r1/rip_status.ref @@ -1,6 +1,6 @@ Routing Protocol is "rip" - Sending updates every 30 seconds with +/-50%, next due in XX seconds - Timeout after 180 seconds, garbage collect after 120 seconds + Sending updates every 5 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 5 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 diff --git a/tests/topotests/rip-topo1/r1/ripd.conf b/tests/topotests/rip-topo1/r1/ripd.conf index 70e70d3590..935ec312e5 100644 --- a/tests/topotests/rip-topo1/r1/ripd.conf +++ b/tests/topotests/rip-topo1/r1/ripd.conf @@ -1,6 +1,7 @@ log file ripd.log ! router rip + timers basic 5 180 5 version 2 network 193.1.1.0/26 ! diff --git a/tests/topotests/rip-topo1/r2/rip_status.ref b/tests/topotests/rip-topo1/r2/rip_status.ref index b539d321d5..da1abd041a 100644 --- a/tests/topotests/rip-topo1/r2/rip_status.ref +++ b/tests/topotests/rip-topo1/r2/rip_status.ref @@ -1,6 +1,6 @@ Routing Protocol is "rip" - Sending updates every 30 seconds with +/-50%, next due in XX seconds - Timeout after 180 seconds, garbage collect after 120 seconds + Sending updates every 5 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 5 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 diff --git a/tests/topotests/rip-topo1/r2/ripd.conf b/tests/topotests/rip-topo1/r2/ripd.conf index 179a1ebd0f..2e94cfa262 100644 --- a/tests/topotests/rip-topo1/r2/ripd.conf +++ b/tests/topotests/rip-topo1/r2/ripd.conf @@ -3,6 +3,7 @@ log file ripd.log ! router rip version 2 + timers basic 5 180 5 network 193.1.1.0/26 network 193.1.2.0/24 ! diff --git a/tests/topotests/rip-topo1/r3/rip_status.ref b/tests/topotests/rip-topo1/r3/rip_status.ref index 0e3a4be944..040d3c32a1 100644 --- a/tests/topotests/rip-topo1/r3/rip_status.ref +++ b/tests/topotests/rip-topo1/r3/rip_status.ref @@ -1,6 +1,6 @@ Routing Protocol is "rip" - Sending updates every 30 seconds with +/-50%, next due in XX seconds - Timeout after 180 seconds, garbage collect after 120 seconds + Sending updates every 5 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 5 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 diff --git a/tests/topotests/rip-topo1/r3/ripd.conf b/tests/topotests/rip-topo1/r3/ripd.conf index 363b91b33a..e27e67503f 100644 --- a/tests/topotests/rip-topo1/r3/ripd.conf +++ b/tests/topotests/rip-topo1/r3/ripd.conf @@ -3,6 +3,7 @@ log file ripd.log ! router rip version 2 + timers basic 5 180 5 redistribute connected redistribute static network 193.1.2.0/24 diff --git a/tests/topotests/rip-topo1/test_rip_topo1.py b/tests/topotests/rip-topo1/test_rip_topo1.py index 7aaaacacfb..8f3c25e910 100755 --- a/tests/topotests/rip-topo1/test_rip_topo1.py +++ b/tests/topotests/rip-topo1/test_rip_topo1.py @@ -144,7 +144,6 @@ def test_router_running(): print("\n\n** Check if FRR/Quagga is running on each Router node") print("******************************************\n") - sleep(5) # Make sure that all daemons are running for i in range(1, 4): @@ -168,8 +167,8 @@ def test_converge_protocols(): print("\n\n** Waiting for protocols convergence") print("******************************************\n") - # Not really implemented yet - just sleep 60 secs for now - sleep(60) + # Not really implemented yet - just sleep 11 secs for now + sleep(11) # Make sure that all daemons are still running for i in range(1, 4): diff --git a/tests/topotests/ripng-topo1/r1/ripng_status.ref b/tests/topotests/ripng-topo1/r1/ripng_status.ref index 48816c1a9b..e6197f179b 100644 --- a/tests/topotests/ripng-topo1/r1/ripng_status.ref +++ b/tests/topotests/ripng-topo1/r1/ripng_status.ref @@ -1,6 +1,6 @@ Routing Protocol is "RIPng" - Sending updates every 30 seconds with +/-50%, next due in XX seconds - Timeout after 180 seconds, garbage collect after 120 seconds + Sending updates every 5 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 5 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 diff --git a/tests/topotests/ripng-topo1/r1/ripngd.conf b/tests/topotests/ripng-topo1/r1/ripngd.conf index 5eb78eafe2..dd54c43557 100644 --- a/tests/topotests/ripng-topo1/r1/ripngd.conf +++ b/tests/topotests/ripng-topo1/r1/ripngd.conf @@ -5,6 +5,7 @@ debug ripng packet debug ripng zebra ! router ripng + timers basic 5 180 5 network fc00:5::/64 ! line vty diff --git a/tests/topotests/ripng-topo1/r2/ripng_status.ref b/tests/topotests/ripng-topo1/r2/ripng_status.ref index fddcf63e5b..640df9a4a0 100644 --- a/tests/topotests/ripng-topo1/r2/ripng_status.ref +++ b/tests/topotests/ripng-topo1/r2/ripng_status.ref @@ -1,6 +1,6 @@ Routing Protocol is "RIPng" - Sending updates every 30 seconds with +/-50%, next due in XX seconds - Timeout after 180 seconds, garbage collect after 120 seconds + Sending updates every 5 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 5 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 diff --git a/tests/topotests/ripng-topo1/r2/ripngd.conf b/tests/topotests/ripng-topo1/r2/ripngd.conf index a25a3cd490..ef2c42195d 100644 --- a/tests/topotests/ripng-topo1/r2/ripngd.conf +++ b/tests/topotests/ripng-topo1/r2/ripngd.conf @@ -5,6 +5,7 @@ debug ripng packet debug ripng zebra ! router ripng + timers basic 5 180 5 network fc00:5::/64 network fc00:6::/62 ! diff --git a/tests/topotests/ripng-topo1/r3/ripng_status.ref b/tests/topotests/ripng-topo1/r3/ripng_status.ref index 1a8dabbf5f..f4bfff0c59 100644 --- a/tests/topotests/ripng-topo1/r3/ripng_status.ref +++ b/tests/topotests/ripng-topo1/r3/ripng_status.ref @@ -1,6 +1,6 @@ Routing Protocol is "RIPng" - Sending updates every 30 seconds with +/-50%, next due in XX seconds - Timeout after 180 seconds, garbage collect after 120 seconds + Sending updates every 5 seconds with +/-50%, next due in XX seconds + Timeout after 180 seconds, garbage collect after 5 seconds Outgoing update filter list for all interface is not set Incoming update filter list for all interface is not set Default redistribution metric is 1 diff --git a/tests/topotests/ripng-topo1/r3/ripngd.conf b/tests/topotests/ripng-topo1/r3/ripngd.conf index dfa5700adb..506eaac442 100644 --- a/tests/topotests/ripng-topo1/r3/ripngd.conf +++ b/tests/topotests/ripng-topo1/r3/ripngd.conf @@ -5,6 +5,7 @@ debug ripng packet debug ripng zebra ! router ripng + timers basic 5 180 5 network fc00:6::/62 redistribute connected redistribute static diff --git a/tests/topotests/ripng-topo1/test_ripng_topo1.py b/tests/topotests/ripng-topo1/test_ripng_topo1.py index 145b1a7efe..32b137240c 100755 --- a/tests/topotests/ripng-topo1/test_ripng_topo1.py +++ b/tests/topotests/ripng-topo1/test_ripng_topo1.py @@ -145,7 +145,6 @@ def test_router_running(): print("\n\n** Check if FRR/Quagga is running on each Router node") print("******************************************\n") - sleep(5) # Starting Routers for i in range(1, 4): @@ -169,8 +168,8 @@ def test_converge_protocols(): print("\n\n** Waiting for protocols convergence") print("******************************************\n") - # Not really implemented yet - just sleep 60 secs for now - sleep(60) + # Not really implemented yet - just sleep 11 secs for now + sleep(11) # Make sure that all daemons are running for i in range(1, 4): diff --git a/zebra/debug.c b/zebra/debug.c index 16b1d0057b..68f6b69305 100644 --- a/zebra/debug.c +++ b/zebra/debug.c @@ -544,6 +544,10 @@ static int config_write_debug(struct vty *vty) vty_out(vty, "debug zebra vxlan\n"); write++; } + if (IS_ZEBRA_DEBUG_MLAG) { + vty_out(vty, "debug zebra mlag\n"); + write++; + } if (IS_ZEBRA_DEBUG_PW) { vty_out(vty, "debug zebra pseudowires\n"); write++; @@ -633,4 +637,5 @@ void zebra_debug_init(void) install_element(CONFIG_NODE, &no_debug_zebra_rib_cmd); install_element(CONFIG_NODE, &no_debug_zebra_fpm_cmd); install_element(CONFIG_NODE, &no_debug_zebra_dplane_cmd); + install_element(CONFIG_NODE, &debug_zebra_mlag_cmd); } diff --git a/zebra/interface.c b/zebra/interface.c index 7e7397a3bb..a434ba0d38 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -617,11 +617,14 @@ void if_add_update(struct interface *ifp) SET_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE); if (if_data->shutdown == IF_ZEBRA_SHUTDOWN_ON) { - if (IS_ZEBRA_DEBUG_KERNEL) + if (IS_ZEBRA_DEBUG_KERNEL) { zlog_debug( - "interface %s vrf %u index %d is shutdown. " + "interface %s vrf %s(%u) index %d is shutdown. " "Won't wake it up.", - ifp->name, ifp->vrf_id, ifp->ifindex); + ifp->name, VRF_LOGNAME(zvrf->vrf), + ifp->vrf_id, ifp->ifindex); + } + return; } @@ -629,13 +632,15 @@ void if_add_update(struct interface *ifp) if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "interface %s vrf %u index %d becomes active.", - ifp->name, ifp->vrf_id, ifp->ifindex); + "interface %s vrf %s(%u) index %d becomes active.", + ifp->name, VRF_LOGNAME(zvrf->vrf), ifp->vrf_id, + ifp->ifindex); } else { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("interface %s vrf %u index %d is added.", - ifp->name, ifp->vrf_id, ifp->ifindex); + zlog_debug("interface %s vrf %s(%u) index %d is added.", + ifp->name, VRF_LOGNAME(zvrf->vrf), + ifp->vrf_id, ifp->ifindex); } } @@ -774,10 +779,12 @@ void if_delete_update(struct interface *ifp) struct zebra_if *zif; if (if_is_up(ifp)) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + flog_err( EC_LIB_INTERFACE, - "interface %s vrf %u index %d is still up while being deleted.", - ifp->name, ifp->vrf_id, ifp->ifindex); + "interface %s vrf %s(%u) index %d is still up while being deleted.", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, ifp->ifindex); return; } @@ -787,9 +794,13 @@ void if_delete_update(struct interface *ifp) /* Mark interface as inactive */ UNSET_FLAG(ifp->status, ZEBRA_INTERFACE_ACTIVE); - if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("interface %s vrf %u index %d is now inactive.", - ifp->name, ifp->vrf_id, ifp->ifindex); + if (IS_ZEBRA_DEBUG_KERNEL) { + struct vrf *vrf = vrf_lookup_by_id(ifp->vrf_id); + + zlog_debug("interface %s vrf %s(%u) index %d is now inactive.", + ifp->name, VRF_LOGNAME(vrf), ifp->vrf_id, + ifp->ifindex); + } /* Delete connected routes from the kernel. */ if_delete_connected(ifp); @@ -1863,7 +1874,8 @@ DEFUN (show_interface_desc_vrf_all, RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) if (!RB_EMPTY(if_name_head, &vrf->ifaces_by_name)) { - vty_out(vty, "\n\tVRF %u\n\n", vrf->vrf_id); + vty_out(vty, "\n\tVRF %s(%u)\n\n", VRF_LOGNAME(vrf), + vrf->vrf_id); if_show_description(vty, vrf->vrf_id); } diff --git a/zebra/ipforward_proc.c b/zebra/ipforward_proc.c index 226f722937..4bd160ddbc 100644 --- a/zebra/ipforward_proc.c +++ b/zebra/ipforward_proc.c @@ -34,9 +34,7 @@ static const char proc_net_snmp[] = "/proc/net/snmp"; static void dropline(FILE *fp) { - int c; - - while ((c = getc(fp)) != '\n') + while (getc(fp) != '\n') ; } diff --git a/zebra/irdp_packet.c b/zebra/irdp_packet.c index f6fe6bbf1e..13dcab9294 100644 --- a/zebra/irdp_packet.c +++ b/zebra/irdp_packet.c @@ -78,6 +78,7 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp) int ip_hlen, iplen, datalen; struct zebra_if *zi; struct irdp_interface *irdp; + uint16_t saved_chksum; zi = ifp->info; if (!zi) @@ -121,8 +122,10 @@ static void parse_irdp_packet(char *p, int len, struct interface *ifp) icmp = (struct icmphdr *)(p + ip_hlen); + saved_chksum = icmp->checksum; + icmp->checksum = 0; /* check icmp checksum */ - if (in_cksum(icmp, datalen) != icmp->checksum) { + if (in_cksum(icmp, datalen) != saved_chksum) { flog_warn( EC_ZEBRA_IRDP_BAD_CHECKSUM, "IRDP: RX ICMP packet from %s. Bad checksum, silently ignored", @@ -315,15 +318,20 @@ void send_packet(struct interface *ifp, struct stream *s, uint32_t dst, if (setsockopt(irdp_sock, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) - zlog_debug("sendto %s", safe_strerror(errno)); + flog_err(EC_LIB_SOCKET, + "IRDP: Cannot set IP_HDRINCLU %s(%d) on %s", + safe_strerror(errno), errno, ifp->name); if (dst == INADDR_BROADCAST) { - on = 1; - if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, (char *)&on, - sizeof(on)) + uint32_t bon = 1; + + if (setsockopt(irdp_sock, SOL_SOCKET, SO_BROADCAST, &bon, + sizeof(bon)) < 0) - zlog_debug("sendto %s", safe_strerror(errno)); + flog_err(EC_LIB_SOCKET, + "IRDP: Cannot set SO_BROADCAST %s(%d) on %s", + safe_strerror(errno), errno, ifp->name); } if (dst != INADDR_BROADCAST) @@ -354,8 +362,8 @@ void send_packet(struct interface *ifp, struct stream *s, uint32_t dst, sockopt_iphdrincl_swab_htosys(ip); - if (sendmsg(irdp_sock, msg, 0) < 0) { - zlog_debug("sendto %s", safe_strerror(errno)); - } - /* printf("TX on %s idx %d\n", ifp->name, ifp->ifindex); */ + if (sendmsg(irdp_sock, msg, 0) < 0) + flog_err(EC_LIB_SOCKET, + "IRDP: sendmsg send failure %s(%d) on %s", + safe_strerror(errno), errno, ifp->name); } diff --git a/zebra/redistribute.c b/zebra/redistribute.c index b891fb121f..3d203dea47 100644 --- a/zebra/redistribute.c +++ b/zebra/redistribute.c @@ -339,9 +339,10 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS) if (IS_ZEBRA_DEBUG_EVENT) zlog_debug( - "%s: client proto %s afi=%d, wants %s, vrf %u, instance=%d", + "%s: client proto %s afi=%d, wants %s, vrf %s(%u), instance=%d", __func__, zebra_route_string(client->proto), afi, - zebra_route_string(type), zvrf_id(zvrf), instance); + zebra_route_string(type), VRF_LOGNAME(zvrf->vrf), + zvrf_id(zvrf), instance); if (afi == 0 || afi >= AFI_MAX) { flog_warn(EC_ZEBRA_REDISTRIBUTE_UNKNOWN_AF, @@ -368,8 +369,10 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS) if (!vrf_bitmap_check(client->redist[afi][type], zvrf_id(zvrf))) { if (IS_ZEBRA_DEBUG_EVENT) - zlog_debug("%s: setting vrf %u redist bitmap", - __func__, zvrf_id(zvrf)); + zlog_debug( + "%s: setting vrf %s(%u) redist bitmap", + __func__, VRF_LOGNAME(zvrf->vrf), + zvrf_id(zvrf)); vrf_bitmap_set(client->redist[afi][type], zvrf_id(zvrf)); zebra_redistribute(client, type, 0, zvrf_id(zvrf), afi); @@ -645,7 +648,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, if (rmap_name) ret = zebra_import_table_route_map_check( afi, re->type, re->instance, &rn->p, - re->nhe->nhg->nexthop, + re->nhe->nhg.nexthop, zvrf->vrf->vrf_id, re->tag, rmap_name); if (ret != RMAP_PERMITMATCH) { @@ -682,7 +685,7 @@ int zebra_add_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, newre->instance = re->table; ng = nexthop_group_new(); - copy_nexthops(&ng->nexthop, re->nhe->nhg->nexthop, NULL); + copy_nexthops(&ng->nexthop, re->nhe->nhg.nexthop, NULL); rib_add_multipath(afi, SAFI_UNICAST, &p, NULL, newre, ng); @@ -699,7 +702,7 @@ int zebra_del_import_table_entry(struct zebra_vrf *zvrf, struct route_node *rn, prefix_copy(&p, &rn->p); rib_delete(afi, SAFI_UNICAST, zvrf->vrf->vrf_id, ZEBRA_ROUTE_TABLE, - re->table, re->flags, &p, NULL, re->nhe->nhg->nexthop, + re->table, re->flags, &p, NULL, re->nhe->nhg.nexthop, re->nhe_id, zvrf->table_id, re->metric, re->distance, false); diff --git a/zebra/rib.h b/zebra/rib.h index 927675e3d9..931c97638e 100644 --- a/zebra/rib.h +++ b/zebra/rib.h @@ -515,7 +515,7 @@ static inline struct nexthop_group *rib_active_nhg(struct route_entry *re) if (re->fib_ng.nexthop) return &(re->fib_ng); else - return re->nhe->nhg; + return &(re->nhe->nhg); } extern void zebra_vty_init(void); diff --git a/zebra/rtadv.c b/zebra/rtadv.c index e36af00b4e..829dcfcfd2 100644 --- a/zebra/rtadv.c +++ b/zebra/rtadv.c @@ -2479,4 +2479,25 @@ void rtadv_cmd_init(void) { /* Empty.*/; } + +void rtadv_add_prefix(struct zebra_if *zif, const struct prefix_ipv6 *p) +{ + /* Empty.*/; +} + +void rtadv_delete_prefix(struct zebra_if *zif, const struct prefix *p) +{ + /* Empty.*/; +} + +void rtadv_stop_ra(struct interface *ifp) +{ + /* Empty.*/; +} + +void rtadv_stop_ra_all(void) +{ + /* Empty.*/; +} + #endif /* HAVE_RTADV */ diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index 4d0e34561a..43bad5522c 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -580,7 +580,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client, memcpy(&api.src_prefix, src_p, sizeof(api.src_prefix)); } - for (nexthop = re->nhe->nhg->nexthop; + for (nexthop = re->nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; @@ -689,7 +689,7 @@ static int zsend_ipv4_nexthop_lookup_mrib(struct zserv *client, * nexthop we are looking up. Therefore, we will just iterate * over the top chain of nexthops. */ - for (nexthop = re->nhe->nhg->nexthop; nexthop; + for (nexthop = re->nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) num += zserv_encode_nexthop(s, nexthop); @@ -1823,17 +1823,17 @@ static void zread_mpls_labels_add(ZAPI_HANDLER_ARGS) return; for (int i = 0; i < zl.nexthop_num; i++) { - struct zapi_nexthop_label *znh; + struct zapi_nexthop *znh; znh = &zl.nexthops[i]; - mpls_lsp_install(zvrf, zl.type, zl.local_label, 1, &znh->label, - znh->type, &znh->address, znh->ifindex); + mpls_lsp_install(zvrf, zl.type, zl.local_label, 1, znh->labels, + znh->type, &znh->gate, znh->ifindex); if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix, - znh->type, &znh->address, znh->ifindex, + znh->type, &znh->gate, znh->ifindex, zl.route.type, zl.route.instance, - znh->label); + znh->labels[0]); } } @@ -1866,19 +1866,20 @@ static void zread_mpls_labels_delete(ZAPI_HANDLER_ARGS) if (zl.nexthop_num > 0) { for (int i = 0; i < zl.nexthop_num; i++) { - struct zapi_nexthop_label *znh; + struct zapi_nexthop *znh; znh = &zl.nexthops[i]; mpls_lsp_uninstall(zvrf, zl.type, zl.local_label, - znh->type, &znh->address, + znh->type, &znh->gate, znh->ifindex); if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) mpls_ftn_update(0, zvrf, zl.type, &zl.route.prefix, znh->type, - &znh->address, znh->ifindex, + &znh->gate, znh->ifindex, zl.route.type, - zl.route.instance, znh->label); + zl.route.instance, + znh->labels[0]); } } else { mpls_lsp_uninstall_all_vrf(zvrf, zl.type, zl.local_label); @@ -1924,17 +1925,18 @@ static void zread_mpls_labels_replace(ZAPI_HANDLER_ARGS) zl.route.type, zl.route.instance); for (int i = 0; i < zl.nexthop_num; i++) { - struct zapi_nexthop_label *znh; + struct zapi_nexthop *znh; znh = &zl.nexthops[i]; - mpls_lsp_install(zvrf, zl.type, zl.local_label, 1, &znh->label, - znh->type, &znh->address, znh->ifindex); + mpls_lsp_install(zvrf, zl.type, zl.local_label, + 1, znh->labels, znh->type, + &znh->gate, znh->ifindex); if (CHECK_FLAG(zl.message, ZAPI_LABELS_FTN)) { mpls_ftn_update(1, zvrf, zl.type, &zl.route.prefix, - znh->type, &znh->address, znh->ifindex, + znh->type, &znh->gate, znh->ifindex, zl.route.type, zl.route.instance, - znh->label); + znh->labels[0]); } } } @@ -1946,6 +1948,7 @@ static void zread_table_manager_connect(struct zserv *client, struct stream *s; uint8_t proto; uint16_t instance; + struct vrf *vrf = vrf_lookup_by_id(vrf_id); s = msg; @@ -1961,8 +1964,9 @@ static void zread_table_manager_connect(struct zserv *client, zsend_table_manager_connect_response(client, vrf_id, 1); return; } - zlog_notice("client %d with vrf %u instance %u connected as %s", - client->sock, vrf_id, instance, zebra_route_string(proto)); + zlog_notice("client %d with vrf %s(%u) instance %u connected as %s", + client->sock, VRF_LOGNAME(vrf), vrf_id, instance, + zebra_route_string(proto)); client->proto = proto; client->instance = instance; @@ -2408,15 +2412,14 @@ static inline void zread_rule(ZAPI_HANDLER_ARGS) || zpr.rule.filter.src_ip.family == AF_INET6)) { zlog_warn( "Unsupported PBR source IP family: %s (%" PRIu8 - ")\n", + ")", family2str(zpr.rule.filter.src_ip.family), zpr.rule.filter.src_ip.family); return; } if (!(zpr.rule.filter.dst_ip.family == AF_INET || zpr.rule.filter.dst_ip.family == AF_INET6)) { - zlog_warn("Unsupported PBR IP family: %s (%" PRIu8 - ")\n", + zlog_warn("Unsupported PBR IP family: %s (%" PRIu8 ")", family2str(zpr.rule.filter.dst_ip.family), zpr.rule.filter.dst_ip.family); return; diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 17b148178f..5d0d0a48c3 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -1513,9 +1513,9 @@ static int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, /* Copy nexthops; recursive info is included too */ copy_nexthops(&(ctx->u.rinfo.zd_ng.nexthop), - re->nhe->nhg->nexthop, NULL); + re->nhe->nhg.nexthop, NULL); - /* Ensure that the dplane's nexthops flags are clear. */ + /* Ensure that the dplane nexthops' flags are clear. */ for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); @@ -1596,9 +1596,9 @@ static int dplane_ctx_nexthop_init(struct zebra_dplane_ctx *ctx, ctx->u.rinfo.nhe.vrf_id = nhe->vrf_id; ctx->u.rinfo.nhe.type = nhe->type; - nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), nhe->nhg); + nexthop_group_copy(&(ctx->u.rinfo.nhe.ng), &(nhe->nhg)); - /* If its a group, convert it to a grp array of ids */ + /* If this is a group, convert it to a grp array of ids */ if (!zebra_nhg_depends_is_empty(nhe) && !CHECK_FLAG(nhe->flags, NEXTHOP_GROUP_RECURSIVE)) ctx->u.rinfo.nhe.nh_grp_count = zebra_nhg_nhe2grp( @@ -1753,7 +1753,7 @@ static int dplane_ctx_pw_init(struct zebra_dplane_ctx *ctx, if (re) copy_nexthops(&(ctx->u.pw.nhg.nexthop), - re->nhe->nhg->nexthop, NULL); + re->nhe->nhg.nexthop, NULL); route_unlock_node(rn); } @@ -1849,7 +1849,7 @@ dplane_route_update_internal(struct route_node *rn, * We'll need these to do per-nexthop deletes. */ copy_nexthops(&(ctx->u.rinfo.zd_old_ng.nexthop), - old_re->nhe->nhg->nexthop, NULL); + old_re->nhe->nhg.nexthop, NULL); #endif /* !HAVE_NETLINK */ } diff --git a/zebra/zebra_fpm_dt.c b/zebra/zebra_fpm_dt.c index 389781d4f7..81437e72f5 100644 --- a/zebra/zebra_fpm_dt.c +++ b/zebra/zebra_fpm_dt.c @@ -90,7 +90,7 @@ static int zfpm_dt_find_route(rib_dest_t **dest_p, struct route_entry **re_p) if (!re) continue; - if (nexthop_group_active_nexthop_num(re->nhe->nhg) == 0) + if (nexthop_group_active_nexthop_num(&(re->nhe->nhg)) == 0) continue; *dest_p = dest; diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index be29b75aea..929e675351 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -309,7 +309,7 @@ static int netlink_route_info_fill(netlink_route_info_t *ri, int cmd, ri->rtm_type = RTN_UNICAST; ri->metric = &re->metric; - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { if (ri->num_nhs >= zrouter.multipath_num) break; diff --git a/zebra/zebra_fpm_protobuf.c b/zebra/zebra_fpm_protobuf.c index d50981debf..ade4b636d6 100644 --- a/zebra/zebra_fpm_protobuf.c +++ b/zebra/zebra_fpm_protobuf.c @@ -173,7 +173,7 @@ static Fpm__AddRoute *create_add_route_message(qpb_allocator_t *allocator, * Figure out the set of nexthops to be added to the message. */ num_nhs = 0; - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { if (num_nhs >= zrouter.multipath_num) break; diff --git a/zebra/zebra_gr.c b/zebra/zebra_gr.c index e8c7304f44..956fe9c2c8 100644 --- a/zebra/zebra_gr.c +++ b/zebra/zebra_gr.c @@ -468,9 +468,7 @@ static int32_t zebra_gr_route_stale_delete_timer_expiry(struct thread *thread) LOG_GR("%s: Client %s all starle routes processed", __func__, zebra_route_string(client->proto)); - if (info->current_prefix != NULL) - XFREE(MTYPE_TMP, info->current_prefix); - info->current_prefix = NULL; + XFREE(MTYPE_TMP, info->current_prefix); info->current_afi = 0; zebra_gr_delete_stale_client(info); } @@ -516,7 +514,6 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, struct route_entry *next; struct route_table *table; int32_t n = 0; - struct prefix *p; afi_t afi, curr_afi; uint8_t proto; uint16_t instance; @@ -541,25 +538,21 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, /* Process routes for all AFI */ for (afi = curr_afi; afi < AFI_MAX; afi++) { table = zvrf->table[afi][SAFI_UNICAST]; - p = info->current_prefix; if (table) { /* * If the current prefix is NULL then get the first * route entry in the table */ - if (p == NULL) { + if (info->current_prefix == NULL) { rn = route_top(table); if (rn == NULL) continue; - p = XCALLOC(MTYPE_TMP, sizeof(struct prefix)); - if (p == NULL) - return -1; curr = rn; - prefix_copy(p, &rn->p); } else /* Get the next route entry */ - curr = route_table_get_next(table, p); + curr = route_table_get_next( + table, info->current_prefix); for (rn = curr; rn; rn = srcdest_route_next(rn)) { RNODE_FOREACH_RE_SAFE (rn, re, next) { @@ -583,9 +576,13 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, */ if ((n >= ZEBRA_MAX_STALE_ROUTE_COUNT) && (info->delete == false)) { - prefix_copy(p, &rn->p); info->current_afi = afi; - info->current_prefix = p; + info->current_prefix = XCALLOC( + MTYPE_TMP, + sizeof(struct prefix)); + prefix_copy( + info->current_prefix, + &rn->p); return n; } } @@ -595,11 +592,7 @@ static int32_t zebra_gr_delete_stale_route(struct client_gr_info *info, * Reset the current prefix to indicate processing completion * of the current AFI */ - if (info->current_prefix) { - XFREE(MTYPE_TMP, info->current_prefix); - info->current_prefix = NULL; - } - continue; + XFREE(MTYPE_TMP, info->current_prefix); } return 0; } diff --git a/zebra/zebra_mpls.c b/zebra/zebra_mpls.c index c167e6a8ad..fa6b952244 100644 --- a/zebra/zebra_mpls.c +++ b/zebra/zebra_mpls.c @@ -186,7 +186,7 @@ static int lsp_install(struct zebra_vrf *zvrf, mpls_label_t label, * the label advertised by the recursive nexthop (plus we don't have the * logic yet to push multiple labels). */ - for (nexthop = re->nhe->nhg->nexthop; + for (nexthop = re->nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) { /* Skip inactive and recursive entries. */ if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) @@ -638,7 +638,7 @@ static int nhlfe_nexthop_active_ipv4(zebra_nhlfe_t *nhlfe, || !CHECK_FLAG(match->flags, ZEBRA_FLAG_SELECTED)) continue; - for (match_nh = match->nhe->nhg->nexthop; match_nh; + for (match_nh = match->nhe->nhg.nexthop; match_nh; match_nh = match_nh->next) { if (match->type == ZEBRA_ROUTE_CONNECT || nexthop->ifindex == match_nh->ifindex) { @@ -689,10 +689,10 @@ static int nhlfe_nexthop_active_ipv6(zebra_nhlfe_t *nhlfe, break; } - if (!match || !match->nhe->nhg->nexthop) + if (!match || !match->nhe->nhg.nexthop) return 0; - nexthop->ifindex = match->nhe->nhg->nexthop->ifindex; + nexthop->ifindex = match->nhe->nhg.nexthop->ifindex; return 1; } @@ -2631,7 +2631,7 @@ int mpls_ftn_update(int add, struct zebra_vrf *zvrf, enum lsp_types_t type, * We can't just change the values here since we are hashing * on labels. We need to create a whole new group */ - nexthop_group_copy(&new_grp, re->nhe->nhg); + nexthop_group_copy(&new_grp, &(re->nhe->nhg)); found = false; for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { @@ -2712,7 +2712,7 @@ int mpls_ftn_uninstall(struct zebra_vrf *zvrf, enum lsp_types_t type, if (re == NULL) return -1; - nexthop_group_copy(&new_grp, re->nhe->nhg); + nexthop_group_copy(&new_grp, &(re->nhe->nhg)); for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) nexthop_del_labels(nexthop); @@ -2949,7 +2949,7 @@ static void mpls_ftn_uninstall_all(struct zebra_vrf *zvrf, RNODE_FOREACH_RE (rn, re) { struct nexthop_group new_grp = {}; - nexthop_group_copy(&new_grp, re->nhe->nhg); + nexthop_group_copy(&new_grp, &(re->nhe->nhg)); for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index bb95e72382..7f81e530fb 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -315,20 +315,20 @@ zebra_nhg_connect_depends(struct nhg_hash_entry *nhe, } /* Add the ifp now if its not a group or recursive and has ifindex */ - if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg->nexthop - && nhe->nhg->nexthop->ifindex) { + if (zebra_nhg_depends_is_empty(nhe) && nhe->nhg.nexthop + && nhe->nhg.nexthop->ifindex) { struct interface *ifp = NULL; - ifp = if_lookup_by_index(nhe->nhg->nexthop->ifindex, - nhe->nhg->nexthop->vrf_id); + ifp = if_lookup_by_index(nhe->nhg.nexthop->ifindex, + nhe->nhg.nexthop->vrf_id); if (ifp) zebra_nhg_set_if(nhe, ifp); else flog_err( EC_ZEBRA_IF_LOOKUP_FAILED, "Zebra failed to lookup an interface with ifindex=%d in vrf=%u for NHE id=%u", - nhe->nhg->nexthop->ifindex, - nhe->nhg->nexthop->vrf_id, nhe->id); + nhe->nhg.nexthop->ifindex, + nhe->nhg.nexthop->vrf_id, nhe->id); } } @@ -350,8 +350,7 @@ static struct nhg_hash_entry *zebra_nhg_copy(const struct nhg_hash_entry *copy, nhe->id = id; - nhe->nhg = nexthop_group_new(); - nexthop_group_copy(nhe->nhg, copy->nhg); + nexthop_group_copy(&(nhe->nhg), &(copy->nhg)); nhe->vrf_id = copy->vrf_id; nhe->afi = copy->afi; @@ -371,7 +370,7 @@ static void *zebra_nhg_hash_alloc(void *arg) nhe = zebra_nhg_copy(copy, copy->id); /* Mark duplicate nexthops in a group at creation time. */ - nexthop_group_mark_duplicates(nhe->nhg); + nexthop_group_mark_duplicates(&(nhe->nhg)); zebra_nhg_connect_depends(nhe, copy->nhg_depends); zebra_nhg_insert_id(nhe); @@ -385,7 +384,8 @@ uint32_t zebra_nhg_hash_key(const void *arg) uint32_t key = 0x5a351234; - key = jhash_3words(nhe->vrf_id, nhe->afi, nexthop_group_hash(nhe->nhg), + key = jhash_3words(nhe->vrf_id, nhe->afi, + nexthop_group_hash(&(nhe->nhg)), key); return key; @@ -416,7 +416,7 @@ bool zebra_nhg_hash_equal(const void *arg1, const void *arg2) return false; /* Nexthops should be sorted */ - for (nexthop1 = nhe1->nhg->nexthop, nexthop2 = nhe2->nhg->nexthop; + for (nexthop1 = nhe1->nhg.nexthop, nexthop2 = nhe2->nhg.nexthop; nexthop1 || nexthop2; nexthop1 = nexthop1->next, nexthop2 = nexthop2->next) { if (nexthop1 && !nexthop2) @@ -498,7 +498,7 @@ static int zebra_nhg_process_grp(struct nexthop_group *nhg, * in the kernel. */ - copy_nexthops(&nhg->nexthop, depend->nhg->nexthop, NULL); + copy_nexthops(&nhg->nexthop, depend->nhg.nexthop, NULL); } return 0; @@ -536,14 +536,14 @@ static bool zebra_nhg_find(struct nhg_hash_entry **nhe, uint32_t id, lookup.id = id ? id : ++id_counter; lookup.type = type ? type : ZEBRA_ROUTE_NHG; - lookup.nhg = nhg; + lookup.nhg = *nhg; lookup.vrf_id = vrf_id; - if (lookup.nhg->nexthop->next) { + if (lookup.nhg.nexthop->next) { /* Groups can have all vrfs and AF's in them */ lookup.afi = AFI_UNSPEC; } else { - switch (lookup.nhg->nexthop->type) { + switch (lookup.nhg.nexthop->type) { case (NEXTHOP_TYPE_IFINDEX): case (NEXTHOP_TYPE_BLACKHOLE): /* @@ -1206,7 +1206,8 @@ zebra_nhg_rib_find(uint32_t id, struct nexthop_group *nhg, afi_t rt_afi) static void zebra_nhg_free_members(struct nhg_hash_entry *nhe) { - nexthop_group_delete(&nhe->nhg); + nexthops_free(nhe->nhg.nexthop); + /* Decrement to remove connection ref */ nhg_connected_tree_decrement_ref(&nhe->nhg_depends); nhg_connected_tree_free(&nhe->nhg_depends); @@ -1533,7 +1534,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, if (match->type == ZEBRA_ROUTE_CONNECT) { /* Directly point connected route. */ - newhop = match->nhe->nhg->nexthop; + newhop = match->nhe->nhg.nexthop; if (newhop) { if (nexthop->type == NEXTHOP_TYPE_IPV4 || nexthop->type == NEXTHOP_TYPE_IPV6) @@ -1542,7 +1543,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return 1; } else if (CHECK_FLAG(re->flags, ZEBRA_FLAG_ALLOW_RECURSION)) { resolved = 0; - for (ALL_NEXTHOPS_PTR(match->nhe->nhg, newhop)) { + for (ALL_NEXTHOPS(match->nhe->nhg, newhop)) { if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; @@ -1563,7 +1564,7 @@ static int nexthop_active(afi_t afi, struct route_entry *re, return resolved; } else if (re->type == ZEBRA_ROUTE_STATIC) { resolved = 0; - for (ALL_NEXTHOPS_PTR(match->nhe->nhg, newhop)) { + for (ALL_NEXTHOPS(match->nhe->nhg, newhop)) { if (!CHECK_FLAG(match->status, ROUTE_ENTRY_INSTALLED)) continue; @@ -1754,7 +1755,7 @@ int nexthop_active_update(struct route_node *rn, struct route_entry *re) UNSET_FLAG(re->status, ROUTE_ENTRY_CHANGED); /* Copy over the nexthops in current state */ - nexthop_group_copy(&new_grp, re->nhe->nhg); + nexthop_group_copy(&new_grp, &(re->nhe->nhg)); for (nexthop = new_grp.nexthop; nexthop; nexthop = nexthop->next) { @@ -1866,7 +1867,7 @@ uint8_t zebra_nhg_nhe2grp(struct nh_grp *grp, struct nhg_hash_entry *nhe, if (!duplicate) { grp[i].id = depend->id; /* We aren't using weights for anything right now */ - grp[i].weight = depend->nhg->nexthop->weight; + grp[i].weight = depend->nhg.nexthop->weight; i++; } diff --git a/zebra/zebra_nhg.h b/zebra/zebra_nhg.h index 4d001944b7..dc3a47c020 100644 --- a/zebra/zebra_nhg.h +++ b/zebra/zebra_nhg.h @@ -40,16 +40,15 @@ struct nh_grp { PREDECL_RBTREE_UNIQ(nhg_connected_tree); /* - * Hashtables contiaining entries found in `zebra_router`. + * Hashtables containing nhg entries is in `zebra_router`. */ - struct nhg_hash_entry { uint32_t id; afi_t afi; vrf_id_t vrf_id; int type; - struct nexthop_group *nhg; + struct nexthop_group nhg; /* If this is not a group, it * will be a single nexthop diff --git a/zebra/zebra_ptm.c b/zebra/zebra_ptm.c index 681b4d1ab8..b80c9026a7 100644 --- a/zebra/zebra_ptm.c +++ b/zebra/zebra_ptm.c @@ -441,15 +441,17 @@ static void if_bfd_session_update(struct interface *ifp, struct prefix *dp, dp->prefixlen, ifp->name, bfd_get_status_str(status)); } else { + struct vrf *vrf = vrf_lookup_by_id(vrf_id); + zlog_debug( "MESSAGE: ZEBRA_INTERFACE_BFD_DEST_UPDATE %s/%d " - "with src %s/%d and vrf %u %s event", + "with src %s/%d and vrf %s(%u) %s event", inet_ntop(dp->family, &dp->u.prefix, buf[0], INET6_ADDRSTRLEN), dp->prefixlen, inet_ntop(sp->family, &sp->u.prefix, buf[1], INET6_ADDRSTRLEN), - sp->prefixlen, vrf_id, + sp->prefixlen, VRF_LOGNAME(vrf), vrf_id, bfd_get_status_str(status)); } } diff --git a/zebra/zebra_pw.c b/zebra/zebra_pw.c index 618a232408..610a052c31 100644 --- a/zebra/zebra_pw.c +++ b/zebra/zebra_pw.c @@ -259,7 +259,7 @@ static int zebra_pw_check_reachability(struct zebra_pw *pw) * Need to ensure that there's a label binding for all nexthops. * Otherwise, ECMP for this route could render the pseudowire unusable. */ - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { if (!nexthop->nh_label) { if (IS_ZEBRA_DEBUG_PW) zlog_debug("%s: unlabeled route for %s", diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 57bd986872..9185c7ad16 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -198,8 +198,8 @@ int zebra_check_addr(const struct prefix *p) */ void route_entry_copy_nexthops(struct route_entry *re, struct nexthop *nh) { - assert(!re->nhe->nhg->nexthop); - copy_nexthops(&re->nhe->nhg->nexthop, nh, NULL); + assert(!re->nhe->nhg.nexthop); + copy_nexthops(&re->nhe->nhg.nexthop, nh, NULL); } static void route_entry_attach_ref(struct route_entry *re, @@ -217,12 +217,14 @@ int route_entry_update_nhe(struct route_entry *re, struct nhg_hash_entry *new) int ret = 0; if (new == NULL) { - re->nhe->nhg = NULL; + if (re->nhe) + zebra_nhg_decrement_ref(re->nhe); + re->nhe = NULL; goto done; } if (re->nhe_id != new->id) { - old = zebra_nhg_lookup_id(re->nhe_id); + old = re->nhe; route_entry_attach_ref(re, new); @@ -404,7 +406,7 @@ int zebra_rib_labeled_unicast(struct route_entry *re) if (re->type != ZEBRA_ROUTE_BGP) return 0; - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) if (!nexthop->nh_label || !nexthop->nh_label->num_labels) return 0; @@ -428,7 +430,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, srcdest_rnode_prefixes(rn, &p, &src_p); if (info->safi != SAFI_UNICAST) { - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } @@ -437,7 +439,7 @@ void rib_install_kernel(struct route_node *rn, struct route_entry *re, /* * Install the resolved nexthop object first. */ - zebra_nhg_install_kernel(zebra_nhg_lookup_id(re->nhe_id)); + zebra_nhg_install_kernel(re->nhe); /* * If this is a replace to a new RE let the originator of the RE @@ -506,7 +508,7 @@ void rib_uninstall_kernel(struct route_node *rn, struct route_entry *re) if (info->safi != SAFI_UNICAST) { UNSET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); return; } @@ -566,7 +568,7 @@ static void rib_uninstall(struct route_node *rn, struct route_entry *re) re->fib_ng.nexthop = NULL; } - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); } @@ -742,7 +744,7 @@ static void rib_process_add_fib(struct zebra_vrf *zvrf, struct route_node *rn, /* Update real nexthop. This may actually determine if nexthop is active * or not. */ - if (!nexthop_group_active_nexthop_num(new->nhe->nhg)) { + if (!nexthop_group_active_nexthop_num(&(new->nhe->nhg))) { UNSET_FLAG(new->status, ROUTE_ENTRY_CHANGED); return; } @@ -811,7 +813,7 @@ static void rib_process_update_fib(struct zebra_vrf *zvrf, /* Update the nexthop; we could determine here that nexthop is * inactive. */ - if (nexthop_group_active_nexthop_num(new->nhe->nhg)) + if (nexthop_group_active_nexthop_num(&(new->nhe->nhg))) nh_active = 1; /* If nexthop is active, install the selected route, if @@ -929,7 +931,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, /* both are connected. are either loop or vrf? */ struct nexthop *nexthop = NULL; - for (ALL_NEXTHOPS_PTR(alternate->nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(alternate->nhe->nhg, nexthop)) { struct interface *ifp = if_lookup_by_index( nexthop->ifindex, alternate->vrf_id); @@ -937,7 +939,7 @@ static struct route_entry *rib_choose_best(struct route_entry *current, return alternate; } - for (ALL_NEXTHOPS_PTR(current->nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(current->nhe->nhg, nexthop)) { struct interface *ifp = if_lookup_by_index( nexthop->ifindex, current->vrf_id); @@ -1269,7 +1271,7 @@ static void zebra_rib_fixup_system(struct route_node *rn) SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); UNSET_FLAG(re->status, ROUTE_ENTRY_QUEUED); - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nhop)) { + for (ALL_NEXTHOPS(re->nhe->nhg, nhop)) { if (CHECK_FLAG(nhop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -1386,7 +1388,7 @@ static bool rib_update_re_from_ctx(struct route_entry *re, || !CHECK_FLAG(ctx_nexthop->flags, NEXTHOP_FLAG_ACTIVE)) ctx_nexthop = nexthop_next_active_resolved(ctx_nexthop); - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) continue; @@ -2354,8 +2356,8 @@ void rib_unlink(struct route_node *rn, struct route_entry *re) nhe = zebra_nhg_lookup_id(re->nhe_id); if (nhe) zebra_nhg_decrement_ref(nhe); - } else if (re->nhe->nhg) - nexthop_group_delete(&re->nhe->nhg); + } else if (re->nhe->nhg.nexthop) + nexthops_free(re->nhe->nhg.nexthop); nexthops_free(re->fib_ng.nexthop); @@ -2408,13 +2410,14 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, char srcaddr[PREFIX_STRLEN]; char nhname[PREFIX_STRLEN]; struct nexthop *nexthop; + struct vrf *vrf = vrf_lookup_by_id(re->vrf_id); - zlog_debug("%s: dumping RE entry %p for %s%s%s vrf %u", func, + zlog_debug("%s: dumping RE entry %p for %s%s%s vrf %s(%u)", func, (const void *)re, prefix2str(pp, straddr, sizeof(straddr)), is_srcdst ? " from " : "", is_srcdst ? prefix2str(src_pp, srcaddr, sizeof(srcaddr)) : "", - re->vrf_id); + VRF_LOGNAME(vrf), re->vrf_id); zlog_debug("%s: uptime == %lu, type == %u, instance == %d, table == %d", straddr, (unsigned long)re->uptime, re->type, re->instance, re->table); @@ -2422,10 +2425,10 @@ void _route_entry_dump(const char *func, union prefixconstptr pp, "%s: metric == %u, mtu == %u, distance == %u, flags == %u, status == %u", straddr, re->metric, re->mtu, re->distance, re->flags, re->status); zlog_debug("%s: nexthop_num == %u, nexthop_active_num == %u", straddr, - nexthop_group_nexthop_num(re->nhe->nhg), - nexthop_group_active_nexthop_num(re->nhe->nhg)); + nexthop_group_nexthop_num(&(re->nhe->nhg)), + nexthop_group_active_nexthop_num(&(re->nhe->nhg))); - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { struct interface *ifp; struct vrf *vrf = vrf_lookup_by_id(nexthop->vrf_id); @@ -2783,7 +2786,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (re->type == ZEBRA_ROUTE_KERNEL && re->metric != metric) continue; if (re->type == ZEBRA_ROUTE_CONNECT && - (rtnh = re->nhe->nhg->nexthop) + (rtnh = re->nhe->nhg.nexthop) && rtnh->type == NEXTHOP_TYPE_IFINDEX && nh) { if (rtnh->ifindex != nh->ifindex) continue; @@ -2801,7 +2804,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, same = re; break; } - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, rtnh)) { + for (ALL_NEXTHOPS(re->nhe->nhg, rtnh)) { /* * No guarantee all kernel send nh with labels * on delete. @@ -2843,7 +2846,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (allow_delete) { UNSET_FLAG(fib->status, ROUTE_ENTRY_INSTALLED); /* Unset flags. */ - for (rtnh = fib->nhe->nhg->nexthop; rtnh; + for (rtnh = fib->nhe->nhg.nexthop; rtnh; rtnh = rtnh->next) UNSET_FLAG(rtnh->flags, NEXTHOP_FLAG_FIB); @@ -2899,7 +2902,7 @@ void rib_delete(afi_t afi, safi_t safi, vrf_id_t vrf_id, int type, if (CHECK_FLAG(flags, ZEBRA_FLAG_EVPN_ROUTE)) { struct nexthop *tmp_nh; - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, tmp_nh)) { + for (ALL_NEXTHOPS(re->nhe->nhg, tmp_nh)) { struct ipaddr vtep_ip; memset(&vtep_ip, 0, sizeof(struct ipaddr)); @@ -3223,7 +3226,7 @@ void rib_sweep_table(struct route_table *table) * this decision needs to be revisited */ SET_FLAG(re->status, ROUTE_ENTRY_INSTALLED); - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); rib_uninstall_kernel(rn, re); diff --git a/zebra/zebra_rnh.c b/zebra/zebra_rnh.c index 2d9c83becb..74c3ac3712 100644 --- a/zebra/zebra_rnh.c +++ b/zebra/zebra_rnh.c @@ -54,7 +54,7 @@ DEFINE_MTYPE_STATIC(ZEBRA, RNH, "Nexthop tracking object") static void free_state(vrf_id_t vrf_id, struct route_entry *re, struct route_node *rn); -static void copy_state(struct rnh *rnh, struct route_entry *re, +static void copy_state(struct rnh *rnh, const struct route_entry *re, struct route_node *rn); static int compare_state(struct route_entry *r1, struct route_entry *r2); static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, @@ -384,7 +384,7 @@ static void zebra_rnh_clear_nexthop_rnh_filters(struct route_entry *re) struct nexthop *nexthop; if (re) { - for (nexthop = re->nhe->nhg->nexthop; nexthop; + for (nexthop = re->nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_RNH_FILTERED); } @@ -403,7 +403,7 @@ static int zebra_rnh_apply_nht_rmap(afi_t afi, struct zebra_vrf *zvrf, route_map_result_t ret; if (prn && re) { - for (nexthop = re->nhe->nhg->nexthop; nexthop; + for (nexthop = re->nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) { ret = zebra_nht_route_map_check( afi, proto, &prn->p, zvrf, re, nexthop); @@ -688,7 +688,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, /* Just being SELECTED isn't quite enough - must * have an installed nexthop to be useful. */ - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { if (rnh_nexthop_valid(re, nexthop)) break; } @@ -707,7 +707,7 @@ zebra_rnh_resolve_nexthop_entry(struct zebra_vrf *zvrf, afi_t afi, break; if (re->type == ZEBRA_ROUTE_NHRP) { - for (nexthop = re->nhe->nhg->nexthop; + for (nexthop = re->nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) if (nexthop->type @@ -945,7 +945,7 @@ static void free_state(vrf_id_t vrf_id, struct route_entry *re, XFREE(MTYPE_RE, re); } -static void copy_state(struct rnh *rnh, struct route_entry *re, +static void copy_state(struct rnh *rnh, const struct route_entry *re, struct route_node *rn) { struct route_entry *state; @@ -966,9 +966,8 @@ static void copy_state(struct rnh *rnh, struct route_entry *re, state->status = re->status; state->nhe = zebra_nhg_alloc(); - state->nhe->nhg = nexthop_group_new(); - nexthop_group_copy(state->nhe->nhg, re->nhe->nhg); + nexthop_group_copy(&(state->nhe->nhg), &(re->nhe->nhg)); rnh->state = state; } @@ -986,12 +985,12 @@ static int compare_state(struct route_entry *r1, struct route_entry *r2) if (r1->metric != r2->metric) return 1; - if (nexthop_group_nexthop_num(r1->nhe->nhg) - != nexthop_group_nexthop_num(r2->nhe->nhg)) + if (nexthop_group_nexthop_num(&(r1->nhe->nhg)) + != nexthop_group_nexthop_num(&(r2->nhe->nhg))) return 1; - if (nexthop_group_hash(r1->nhe->nhg) != - nexthop_group_hash(r2->nhe->nhg)) + if (nexthop_group_hash(&(r1->nhe->nhg)) != + nexthop_group_hash(&(r2->nhe->nhg))) return 1; return 0; @@ -1043,7 +1042,7 @@ static int send_client(struct rnh *rnh, struct zserv *client, rnh_type_t type, num = 0; nump = stream_get_endp(s); stream_putc(s, 0); - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nh)) + for (ALL_NEXTHOPS(re->nhe->nhg, nh)) if (rnh_nexthop_valid(re, nh)) { zapi_nexthop_from_nexthop(&znh, nh); zapi_nexthop_encode(s, &znh, 0 /* flags */); @@ -1114,7 +1113,7 @@ static void print_rnh(struct route_node *rn, struct vty *vty) if (rnh->state) { vty_out(vty, " resolved via %s\n", zebra_route_string(rnh->state->type)); - for (nexthop = rnh->state->nhe->nhg->nexthop; nexthop; + for (nexthop = rnh->state->nhe->nhg.nexthop; nexthop; nexthop = nexthop->next) print_nh(nexthop, vty); } else diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c index 70bb6a14ca..5de45c0294 100644 --- a/zebra/zebra_snmp.c +++ b/zebra/zebra_snmp.c @@ -285,8 +285,8 @@ static void check_replace(struct route_node *np2, struct route_entry *re2, return; } - if (in_addr_cmp((uint8_t *)&(*re)->nhe->nhg->nexthop->gate.ipv4, - (uint8_t *)&re2->nhe->nhg->nexthop->gate.ipv4) + if (in_addr_cmp((uint8_t *)&(*re)->nhe->nhg.nexthop->gate.ipv4, + (uint8_t *)&re2->nhe->nhg.nexthop->gate.ipv4) <= 0) return; @@ -372,7 +372,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], (uint8_t *)&dest)) { RNODE_FOREACH_RE (*np, *re) { if (!in_addr_cmp((uint8_t *)&(*re)->nhe - ->nhg->nexthop + ->nhg.nexthop ->gate.ipv4, (uint8_t *)&nexthop)) if (proto @@ -407,7 +407,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], || ((policy == policy2) && (proto == proto2) && (in_addr_cmp( (uint8_t *)&re2->nhe - ->nhg->nexthop->gate.ipv4, + ->nhg.nexthop->gate.ipv4, (uint8_t *)&nexthop) >= 0))) check_replace(np2, re2, np, re); @@ -432,7 +432,7 @@ static void get_fwtable_route_node(struct variable *v, oid objid[], { struct nexthop *nexthop; - nexthop = (*re)->nhe->nhg->nexthop; + nexthop = (*re)->nhe->nhg.nexthop; if (nexthop) { pnt = (uint8_t *)&nexthop->gate.ipv4; for (i = 0; i < 4; i++) @@ -462,7 +462,7 @@ static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len, if (!np) return NULL; - nexthop = re->nhe->nhg->nexthop; + nexthop = re->nhe->nhg.nexthop; if (!nexthop) return NULL; diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c index 86ec2ffef3..8c719f4b6a 100644 --- a/zebra/zebra_vty.c +++ b/zebra/zebra_vty.c @@ -62,7 +62,7 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, - unsigned short ospf_instance_id); + unsigned short ospf_instance_id, uint32_t tableid); static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, int mcast, bool use_fib, bool show_ng); static void vty_show_ip_route_summary(struct vty *vty, @@ -131,7 +131,7 @@ DEFUN (show_ip_rpf, { bool uj = use_json(argc, argv); return do_show_ip_route(vty, VRF_DEFAULT_NAME, AFI_IP, SAFI_MULTICAST, - false, uj, 0, NULL, false, 0, 0); + false, uj, 0, NULL, false, 0, 0, 0); } DEFUN (show_ip_rpf_addr, @@ -264,7 +264,7 @@ static void vty_show_ip_route_detail(struct vty *vty, struct route_node *rn, if (show_ng) vty_out(vty, " Nexthop Group ID: %u\n", re->nhe_id); - for (ALL_NEXTHOPS_PTR(re->nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(re->nhe->nhg, nexthop)) { char addrstr[32]; vty_out(vty, " %c%s", @@ -417,7 +417,7 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, if (is_fib) nhg = rib_active_nhg(re); else - nhg = re->nhe->nhg; + nhg = &(re->nhe->nhg); if (json) { json_route = json_object_new_object(); @@ -470,10 +470,10 @@ static void vty_show_ip_route(struct vty *vty, struct route_node *rn, json_object_int_add(json_route, "internalFlags", re->flags); json_object_int_add(json_route, "internalNextHopNum", - nexthop_group_nexthop_num(re->nhe->nhg)); + nexthop_group_nexthop_num(&(re->nhe->nhg))); json_object_int_add(json_route, "internalNextHopActiveNum", nexthop_group_active_nexthop_num( - re->nhe->nhg)); + &(re->nhe->nhg))); if (uptime < ONE_DAY_SECOND) sprintf(buf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min, tm->tm_sec); @@ -915,12 +915,40 @@ static void do_show_route_helper(struct vty *vty, struct zebra_vrf *zvrf, } } +static void do_show_ip_route_all(struct vty *vty, struct zebra_vrf *zvrf, afi_t afi, + bool use_fib, bool use_json, + route_tag_t tag, + const struct prefix *longer_prefix_p, + bool supernets_only, int type, + unsigned short ospf_instance_id) +{ + struct zebra_router_table *zrt; + rib_table_info_t *info; + + RB_FOREACH (zrt, zebra_router_table_head, + &zrouter.tables) { + info = route_table_get_info(zrt->table); + + if (zvrf != info->zvrf) + continue; + if (zrt->afi != afi || + zrt->safi != SAFI_UNICAST) + continue; + if (zrt->table) + do_show_ip_route(vty, zvrf_name(zvrf), afi, + SAFI_UNICAST, use_fib, use_json, + tag, longer_prefix_p, + supernets_only, type, + ospf_instance_id, zrt->tableid); + } +} + static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, safi_t safi, bool use_fib, bool use_json, route_tag_t tag, const struct prefix *longer_prefix_p, bool supernets_only, int type, - unsigned short ospf_instance_id) + unsigned short ospf_instance_id, uint32_t tableid) { struct route_table *table; struct zebra_vrf *zvrf = NULL; @@ -941,7 +969,10 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, return CMD_SUCCESS; } - table = zebra_vrf_table(afi, safi, zvrf_id(zvrf)); + if (tableid) + table = zebra_router_find_table(zvrf, tableid, afi, SAFI_UNICAST); + else + table = zebra_vrf_table(afi, safi, zvrf_id(zvrf)); if (!table) { if (use_json) vty_out(vty, "{}\n"); @@ -950,95 +981,8 @@ static int do_show_ip_route(struct vty *vty, const char *vrf_name, afi_t afi, do_show_route_helper(vty, zvrf, table, afi, use_fib, tag, longer_prefix_p, supernets_only, type, - ospf_instance_id, use_json, 0); - - return CMD_SUCCESS; -} - -DEFPY (show_route_table, - show_route_table_cmd, - "show <ip$ipv4|ipv6$ipv6> route table (1-4294967295)$table [json$json]", - SHOW_STR - IP_STR - IP6_STR - "IP routing table\n" - "Table to display\n" - "The table number to display, if available\n" - JSON_STR) -{ - afi_t afi = ipv4 ? AFI_IP : AFI_IP6; - struct zebra_vrf *zvrf = zebra_vrf_lookup_by_id(VRF_DEFAULT); - struct route_table *t; - - t = zebra_router_find_table(zvrf, table, afi, SAFI_UNICAST); - if (t) - do_show_route_helper(vty, zvrf, t, afi, false, 0, false, false, - 0, 0, !!json, table); - - return CMD_SUCCESS; -} - -DEFPY (show_route_table_vrf, - show_route_table_vrf_cmd, - "show <ip$ipv4|ipv6$ipv6> route table (1-4294967295)$table vrf NAME$vrf_name [json$json]", - SHOW_STR - IP_STR - IP6_STR - "IP routing table\n" - "Table to display\n" - "The table number to display, if available\n" - VRF_CMD_HELP_STR - JSON_STR) -{ - afi_t afi = ipv4 ? AFI_IP : AFI_IP6; - struct zebra_vrf *zvrf; - struct route_table *t; - vrf_id_t vrf_id = VRF_DEFAULT; - - if (vrf_name) - VRF_GET_ID(vrf_id, vrf_name, !!json); - zvrf = zebra_vrf_lookup_by_id(vrf_id); + ospf_instance_id, use_json, tableid); - t = zebra_router_find_table(zvrf, table, afi, SAFI_UNICAST); - if (t) - do_show_route_helper(vty, zvrf, t, afi, false, 0, false, false, - 0, 0, !!json, table); - - return CMD_SUCCESS; -} - -DEFPY (show_route_all_table_vrf, - show_route_all_table_vrf_cmd, - "show <ip$ipv4|ipv6$ipv6> route [vrf <NAME$vrf_name|all$vrf_all>] tables [json$json]", - SHOW_STR - IP_STR - IP6_STR - "IP routing table\n" - "Display all tables\n" - VRF_FULL_CMD_HELP_STR - JSON_STR) -{ - afi_t afi = ipv4 ? AFI_IP : AFI_IP6; - struct zebra_vrf *zvrf = NULL; - vrf_id_t vrf_id = VRF_UNKNOWN; - struct zebra_router_table *zrt; - - if (vrf_name) { - VRF_GET_ID(vrf_id, vrf_name, !!json); - zvrf = zebra_vrf_lookup_by_id(vrf_id); - } - - RB_FOREACH (zrt, zebra_router_table_head, &zrouter.tables) { - rib_table_info_t *info = route_table_get_info(zrt->table); - - if (zvrf && zvrf != info->zvrf) - continue; - if (zrt->afi != afi || zrt->safi != SAFI_UNICAST) - continue; - - do_show_route_helper(vty, info->zvrf, zrt->table, afi, false, 0, - false, false, 0, 0, !!json, zrt->tableid); - } return CMD_SUCCESS; } @@ -1149,7 +1093,7 @@ static void show_nexthop_group_out(struct vty *vty, struct nhg_hash_entry *nhe) vty_out(vty, "\n"); } - for (ALL_NEXTHOPS_PTR(nhe->nhg, nexthop)) { + for (ALL_NEXTHOPS(nhe->nhg, nexthop)) { if (!CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) vty_out(vty, " "); else @@ -1512,7 +1456,8 @@ DEFPY (show_route, show_route_cmd, "show\ <\ - ip$ipv4 <fib$fib|route> [vrf <NAME$vrf_name|all$vrf_all>]\ + ip$ipv4 <fib$fib|route> [table <(1-4294967295)$table|all$table_all>]\ + [vrf <NAME$vrf_name|all$vrf_all>]\ [{\ tag (1-4294967295)\ |A.B.C.D/M$prefix longer-prefixes\ @@ -1522,7 +1467,8 @@ DEFPY (show_route, " FRR_IP_REDIST_STR_ZEBRA "$type_str\ |ospf$type_str (1-65535)$ospf_instance_id\ >]\ - |ipv6$ipv6 <fib$fib|route> [vrf <NAME$vrf_name|all$vrf_all>]\ + |ipv6$ipv6 <fib$fib|route> [table <(1-4294967295)$table|all$table_all>]\ + [vrf <NAME$vrf_name|all$vrf_all>]\ [{\ tag (1-4294967295)\ |X:X::X:X/M$prefix longer-prefixes\ @@ -1534,6 +1480,9 @@ DEFPY (show_route, IP_STR "IP forwarding table\n" "IP routing table\n" + "Table to display\n" + "The table number to display\n" + "All tables\n" VRF_FULL_CMD_HELP_STR "Show only routes with tag\n" "Tag value\n" @@ -1546,6 +1495,9 @@ DEFPY (show_route, IPV6_STR "IP forwarding table\n" "IP routing table\n" + "Table to display\n" + "The table number to display\n" + "All tables\n" VRF_FULL_CMD_HELP_STR "Show only routes with tag\n" "Tag value\n" @@ -1557,7 +1509,19 @@ DEFPY (show_route, afi_t afi = ipv4 ? AFI_IP : AFI_IP6; struct vrf *vrf; int type = 0; + struct zebra_vrf *zvrf; + if (!vrf_is_backend_netns()) { + if ((vrf_all || vrf_name) && (table || table_all)) { + if (!!json) + vty_out(vty, "{}\n"); + else { + vty_out(vty, "Linux vrf backend already points to table id\n"); + vty_out(vty, "Either remove table parameter or vrf parameter\n"); + } + return CMD_SUCCESS; + } + } if (type_str) { type = proto_redistnum(afi, type_str); if (type < 0) { @@ -1568,17 +1532,22 @@ DEFPY (show_route, if (vrf_all) { RB_FOREACH (vrf, vrf_name_head, &vrfs_by_name) { - struct zebra_vrf *zvrf; - struct route_table *table; - if ((zvrf = vrf->info) == NULL - || (table = zvrf->table[afi][SAFI_UNICAST]) == NULL) + || (zvrf->table[afi][SAFI_UNICAST] == NULL)) continue; - do_show_ip_route( - vty, zvrf_name(zvrf), afi, SAFI_UNICAST, !!fib, - !!json, tag, prefix_str ? prefix : NULL, - !!supernets_only, type, ospf_instance_id); + if (table_all) + do_show_ip_route_all(vty, zvrf, afi, + !!fib, !!json, + tag, prefix_str ? prefix : NULL, + !!supernets_only, type, + ospf_instance_id); + else + do_show_ip_route(vty, zvrf_name(zvrf), afi, + SAFI_UNICAST, !!fib, !!json, tag, + prefix_str ? prefix : NULL, + !!supernets_only, type, + ospf_instance_id, table); } } else { vrf_id_t vrf_id = VRF_DEFAULT; @@ -1586,9 +1555,21 @@ DEFPY (show_route, if (vrf_name) VRF_GET_ID(vrf_id, vrf_name, !!json); vrf = vrf_lookup_by_id(vrf_id); - do_show_ip_route(vty, vrf->name, afi, SAFI_UNICAST, !!fib, - !!json, tag, prefix_str ? prefix : NULL, - !!supernets_only, type, ospf_instance_id); + if (vrf) + zvrf = vrf->info; + if (!vrf || !zvrf) + return CMD_SUCCESS; + + if (table_all) + do_show_ip_route_all(vty, zvrf, afi, + !!fib, !!json, + tag, prefix_str ? prefix : NULL, + !!supernets_only, type, + ospf_instance_id); + else + do_show_ip_route(vty, vrf->name, afi, SAFI_UNICAST, !!fib, + !!json, tag, prefix_str ? prefix : NULL, + !!supernets_only, type, ospf_instance_id, table); } return CMD_SUCCESS; @@ -1970,7 +1951,7 @@ static void vty_show_ip_route_summary_prefix(struct vty *vty, fib_cnt[ZEBRA_ROUTE_TOTAL]++; fib_cnt[re->type]++; } - for (nexthop = re->nhe->nhg->nexthop; (!cnt && nexthop); + for (nexthop = re->nhe->nhg.nexthop; (!cnt && nexthop); nexthop = nexthop->next) { cnt++; rib_cnt[ZEBRA_ROUTE_TOTAL]++; @@ -3539,10 +3520,6 @@ void zebra_vty_init(void) install_element(VIEW_NODE, &show_vrf_cmd); install_element(VIEW_NODE, &show_vrf_vni_cmd); install_element(VIEW_NODE, &show_route_cmd); - install_element(VIEW_NODE, &show_route_table_cmd); - if (vrf_is_backend_netns()) - install_element(VIEW_NODE, &show_route_table_vrf_cmd); - install_element(VIEW_NODE, &show_route_all_table_vrf_cmd); install_element(VIEW_NODE, &show_route_detail_cmd); install_element(VIEW_NODE, &show_route_summary_cmd); install_element(VIEW_NODE, &show_ip_nht_cmd); |
