summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_addpath.c32
-rw-r--r--bgpd/bgp_addpath.h9
-rw-r--r--bgpd/bgp_bfd.c4
-rw-r--r--bgpd/bgp_fsm.c3
-rw-r--r--bgpd/bgp_nht.c19
-rw-r--r--bgpd/bgp_packet.c186
-rw-r--r--bgpd/bgp_route.c38
-rw-r--r--bgpd/bgp_updgrp.c7
-rw-r--r--bgpd/bgp_vty.c105
-rw-r--r--bgpd/bgp_zebra.c51
-rw-r--r--bgpd/bgpd.c96
-rw-r--r--bgpd/bgpd.h9
-rw-r--r--isisd/isis_tlvs.h6
-rw-r--r--lib/zclient.c165
-rw-r--r--lib/zclient.h24
-rw-r--r--redhat/frr.spec.in3
-rw-r--r--tests/topotests/bgp_aggregate_address_topo1/r1/bgp_192_168_0_1.json41
-rw-r--r--tests/topotests/bgp_aggregate_address_topo1/test_bgp_aggregate_address_topo1.py19
-rw-r--r--tests/topotests/bgp_bfd_session/r1/frr.conf12
-rw-r--r--tests/topotests/bgp_bfd_session/test_bgp_bfd_session.py24
-rw-r--r--tests/topotests/bgp_bmp/test_bgp_bmp_1.py2
-rw-r--r--tests/topotests/bgp_dynamic_capability/r2/frr.conf4
-rw-r--r--tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_path_limit.py (renamed from tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py)121
-rw-r--r--tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes.json8
-rw-r--r--tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes_all.json8
-rw-r--r--tests/topotests/bgp_evpn_rt5/r1/frr.conf (renamed from tests/topotests/bgp_evpn_rt5/r1/bgpd.conf)31
-rw-r--r--tests/topotests/bgp_evpn_rt5/r1/zebra.conf23
-rw-r--r--tests/topotests/bgp_evpn_rt5/r2/bgp_l2vpn_evpn_routes.json8
-rw-r--r--tests/topotests/bgp_evpn_rt5/r2/frr.conf (renamed from tests/topotests/bgp_evpn_rt5/r2/bgpd.conf)16
-rw-r--r--tests/topotests/bgp_evpn_rt5/r2/zebra.conf19
-rw-r--r--tests/topotests/bgp_evpn_rt5/r3/frr.conf46
-rw-r--r--tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py59
-rw-r--r--tests/topotests/bgp_peer_solo/r1/frr.conf10
-rw-r--r--tests/topotests/bgp_peer_solo/r2/frr.conf14
-rw-r--r--tests/topotests/bgp_peer_solo/test_bgp_peer_solo.py131
-rw-r--r--tests/topotests/bgp_table_direct_topo1/__init__.py0
-rw-r--r--tests/topotests/bgp_table_direct_topo1/r1/frr.conf31
-rw-r--r--tests/topotests/bgp_table_direct_topo1/r2/frr.conf10
-rw-r--r--tests/topotests/bgp_table_direct_topo1/r3/frr.conf10
-rw-r--r--tests/topotests/bgp_table_direct_topo1/test_bgp_table_direct_topo1.py201
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes_advertised_10_125_0_2.json105
-rw-r--r--tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py38
-rw-r--r--zebra/redistribute.c115
-rw-r--r--zebra/zapi_msg.c10
-rw-r--r--zebra/zapi_msg.h6
-rw-r--r--zebra/zebra_vty.c15
46 files changed, 1273 insertions, 621 deletions
diff --git a/bgpd/bgp_addpath.c b/bgpd/bgp_addpath.c
index aada6e555f..030db4b28e 100644
--- a/bgpd/bgp_addpath.c
+++ b/bgpd/bgp_addpath.c
@@ -10,8 +10,6 @@
#include "bgp_addpath.h"
#include "bgp_route.h"
-#include "bgp_open.h"
-#include "bgp_packet.h"
static const struct bgp_addpath_strategy_names strat_names[BGP_ADDPATH_MAX] = {
{
@@ -361,30 +359,6 @@ void bgp_addpath_type_changed(struct bgp *bgp)
}
}
-int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths)
-{
- int action = CAPABILITY_ACTION_UNSET;
-
- switch (addpath_type) {
- case BGP_ADDPATH_ALL:
- case BGP_ADDPATH_BEST_PER_AS:
- action = CAPABILITY_ACTION_SET;
- break;
- case BGP_ADDPATH_BEST_SELECTED:
- if (paths)
- action = CAPABILITY_ACTION_SET;
- else
- action = CAPABILITY_ACTION_UNSET;
- break;
- case BGP_ADDPATH_NONE:
- case BGP_ADDPATH_MAX:
- action = CAPABILITY_ACTION_UNSET;
- break;
- }
-
- return action;
-}
-
/*
* Change the addpath type assigned to a peer, or peer group. In addition to
* adjusting the counts, peer sessions will be reset as needed to make the
@@ -398,7 +372,6 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
struct listnode *node, *nnode;
struct peer *tmp_peer;
struct peer_group *group;
- int action = bgp_addpath_capability_action(addpath_type, paths);
if (safi == SAFI_LABELED_UNICAST)
safi = SAFI_UNICAST;
@@ -456,12 +429,9 @@ void bgp_addpath_set_peer_type(struct peer *peer, afi_t afi, safi_t safi,
}
}
} else {
- if (!CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_RCV) &&
- !CHECK_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV))
- peer_change_action(peer, afi, safi, peer_change_reset);
+ peer_change_action(peer, afi, safi, peer_change_reset);
}
- bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action);
}
/*
diff --git a/bgpd/bgp_addpath.h b/bgpd/bgp_addpath.h
index f1ff98ea7a..c136671ea4 100644
--- a/bgpd/bgp_addpath.h
+++ b/bgpd/bgp_addpath.h
@@ -15,11 +15,7 @@
#include "bgpd/bgp_table.h"
#include "lib/json.h"
-struct bgp_addpath_capability {
- uint16_t afi;
- uint8_t safi;
- uint8_t flags;
-};
+#define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1
struct bgp_paths_limit_capability {
uint16_t afi;
@@ -27,8 +23,6 @@ struct bgp_paths_limit_capability {
uint16_t paths_limit;
} __attribute__((packed));
-#define BGP_ADDPATH_TX_ID_FOR_DEFAULT_ORIGINATE 1
-
void bgp_addpath_init_bgp_data(struct bgp_addpath_bgp_data *d);
bool bgp_addpath_is_addpath_used(struct bgp_addpath_bgp_data *d, afi_t afi,
@@ -68,5 +62,4 @@ void bgp_addpath_update_ids(struct bgp *bgp, struct bgp_dest *dest, afi_t afi,
safi_t safi);
void bgp_addpath_type_changed(struct bgp *bgp);
-extern int bgp_addpath_capability_action(enum bgp_addpath_strat addpath_type, uint16_t paths);
#endif
diff --git a/bgpd/bgp_bfd.c b/bgpd/bgp_bfd.c
index 78759ae2b6..5437b67f34 100644
--- a/bgpd/bgp_bfd.c
+++ b/bgpd/bgp_bfd.c
@@ -114,6 +114,10 @@ void bgp_peer_config_apply(struct peer *p, struct peer_group *pg)
*/
gconfig = pg->conf;
+ if (CHECK_FLAG(gconfig->flags, PEER_FLAG_UPDATE_SOURCE) ||
+ CHECK_FLAG(p->flags_override, PEER_FLAG_UPDATE_SOURCE))
+ bgp_peer_bfd_update_source(p);
+
/*
* If using default control plane independent configuration,
* then prefer group's (e.g. it means it wasn't manually configured).
diff --git a/bgpd/bgp_fsm.c b/bgpd/bgp_fsm.c
index 0e3ed9f0d1..1a30cb37f4 100644
--- a/bgpd/bgp_fsm.c
+++ b/bgpd/bgp_fsm.c
@@ -2163,6 +2163,9 @@ bgp_establish(struct peer_connection *connection)
peer->established++;
bgp_fsm_change_status(connection, Established);
+ if (peer->last_reset == PEER_DOWN_WAITING_OPEN)
+ peer->last_reset = 0;
+
/* bgp log-neighbor-changes of neighbor Up */
if (CHECK_FLAG(peer->bgp->flags, BGP_FLAG_LOG_NEIGHBOR_CHANGES)) {
struct vrf *vrf = vrf_lookup_by_id(peer->bgp->vrf_id);
diff --git a/bgpd/bgp_nht.c b/bgpd/bgp_nht.c
index 164e2300c0..2ef7ec97e3 100644
--- a/bgpd/bgp_nht.c
+++ b/bgpd/bgp_nht.c
@@ -1278,6 +1278,25 @@ void evaluate_paths(struct bgp_nexthop_cache *bnc)
}
LIST_FOREACH (path, &(bnc->paths), nh_thread) {
+ /*
+ * Currently when a peer goes down, bgp immediately
+ * sees this via the interface events( if it is directly
+ * connected). And in this case it takes and puts on
+ * a special peer queue all path info's associated with
+ * but these items are not yet processed typically when
+ * the nexthop is being handled here. Thus we end
+ * up in a situation where the process Queue for BGP
+ * is being asked to look at the same path info multiple
+ * times. Let's just cut to the chase here and if
+ * the bnc has a peer associated with it and the path info
+ * being looked at uses that peer and the peer is no
+ * longer established we know the path_info is being
+ * handled elsewhere and we do not need to process
+ * it here at all since the pathinfo is going away
+ */
+ if (peer && path->peer == peer && !peer_established(peer->connection))
+ continue;
+
if (path->type == ZEBRA_ROUTE_BGP &&
(path->sub_type == BGP_ROUTE_NORMAL ||
path->sub_type == BGP_ROUTE_STATIC ||
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index ca2e8de041..f8726ffff9 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -1218,7 +1218,6 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
uint16_t len;
uint32_t gr_restart_time;
uint8_t addpath_afi_safi_count = 0;
- bool adv_addpath_tx = false;
unsigned long number_of_orfs_p;
uint8_t number_of_orfs = 0;
const char *capability = lookup_msg(capcode_str, capability_code,
@@ -1226,6 +1225,9 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
const char *hostname = cmd_hostname_get();
const char *domainname = cmd_domainname_get();
+ if (!peer)
+ return;
+
if (!peer_established(peer->connection))
return;
@@ -1383,87 +1385,6 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
COND_FLAG(peer->cap, PEER_CAP_LLGR_ADV,
action == CAPABILITY_ACTION_SET);
break;
- case CAPABILITY_CODE_ADDPATH:
- FOREACH_AFI_SAFI (afi, safi) {
- if (peer->afc[afi][safi]) {
- addpath_afi_safi_count++;
-
- /* Only advertise addpath TX if a feature that
- * will use it is
- * configured */
- if (peer->addpath_type[afi][safi] !=
- BGP_ADDPATH_NONE)
- adv_addpath_tx = true;
-
- /* If we have enabled labeled unicast, we MUST check
- * against unicast SAFI because addpath IDs are
- * allocated under unicast SAFI, the same as the RIB
- * is managed in unicast SAFI.
- */
- if (safi == SAFI_LABELED_UNICAST)
- if (peer->addpath_type[afi][SAFI_UNICAST] !=
- BGP_ADDPATH_NONE)
- adv_addpath_tx = true;
- }
- }
-
- stream_putc(s, action);
- stream_putc(s, CAPABILITY_CODE_ADDPATH);
- stream_putc(s, CAPABILITY_CODE_ADDPATH_LEN *
- addpath_afi_safi_count);
-
- FOREACH_AFI_SAFI (afi, safi) {
- if (peer->afc[afi][safi]) {
- bool adv_addpath_rx =
- !CHECK_FLAG(peer->af_flags[afi][safi],
- PEER_FLAG_DISABLE_ADDPATH_RX);
- uint8_t flags = 0;
-
- /* Convert AFI, SAFI to values for packet. */
- bgp_map_afi_safi_int2iana(afi, safi, &pkt_afi,
- &pkt_safi);
-
- stream_putw(s, pkt_afi);
- stream_putc(s, pkt_safi);
-
- if (adv_addpath_rx) {
- SET_FLAG(flags, BGP_ADDPATH_RX);
- SET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_RX_ADV);
- } else {
- UNSET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_RX_ADV);
- }
-
- if (adv_addpath_tx) {
- SET_FLAG(flags, BGP_ADDPATH_TX);
- SET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_TX_ADV);
- if (safi == SAFI_LABELED_UNICAST)
- SET_FLAG(peer->af_cap[afi]
- [SAFI_UNICAST],
- PEER_CAP_ADDPATH_AF_TX_ADV);
- } else {
- UNSET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_TX_ADV);
- }
-
- stream_putc(s, flags);
- }
- }
-
- if (bgp_debug_neighbor_events(peer))
- zlog_debug("%pBP sending CAPABILITY has %s %s for afi/safi: %s/%s",
- peer,
- action == CAPABILITY_ACTION_SET
- ? "Advertising"
- : "Removing",
- capability, iana_afi2str(pkt_afi),
- iana_safi2str(pkt_safi));
-
- COND_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV,
- action == CAPABILITY_ACTION_SET);
- break;
case CAPABILITY_CODE_PATHS_LIMIT:
FOREACH_AFI_SAFI (afi, safi) {
if (!peer->afc[afi][safi])
@@ -1619,6 +1540,7 @@ void bgp_capability_send(struct peer *peer, afi_t afi, safi_t safi,
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC:
+ case CAPABILITY_CODE_ADDPATH:
case CAPABILITY_CODE_ENHANCED_RR:
case CAPABILITY_CODE_EXT_MESSAGE:
break;
@@ -3174,102 +3096,6 @@ static int bgp_route_refresh_receive(struct peer_connection *connection,
return BGP_PACKET_NOOP;
}
-static void bgp_dynamic_capability_addpath(uint8_t *pnt, int action,
- struct capability_header *hdr,
- struct peer *peer)
-{
- uint8_t *data = pnt + 3;
- uint8_t *end = data + hdr->length;
- size_t len = end - data;
- afi_t afi;
- safi_t safi;
-
- if (action == CAPABILITY_ACTION_SET) {
- if (len % CAPABILITY_CODE_ADDPATH_LEN) {
- flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
- "Add Path: Received invalid length %zu, non-multiple of 4",
- len);
- return;
- }
-
- SET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV);
-
- while (data + CAPABILITY_CODE_ADDPATH_LEN <= end) {
- afi_t afi;
- safi_t safi;
- iana_afi_t pkt_afi;
- iana_safi_t pkt_safi;
- struct bgp_addpath_capability bac;
-
- memcpy(&bac, data, sizeof(bac));
- pkt_afi = ntohs(bac.afi);
- pkt_safi = safi_int2iana(bac.safi);
-
- /* If any other value (other than 1-3) is received,
- * then the capability SHOULD be treated as not
- * understood and ignored.
- */
- if (!bac.flags || bac.flags > 3) {
- flog_warn(EC_BGP_CAPABILITY_INVALID_LENGTH,
- "Add Path: Received invalid send/receive value %u in Add Path capability",
- bac.flags);
- goto ignore;
- }
-
- if (bgp_debug_neighbor_events(peer))
- zlog_debug("%s OPEN has %s capability for afi/safi: %s/%s%s%s",
- peer->host, lookup_msg(capcode_str, hdr->code, NULL),
- iana_afi2str(pkt_afi), iana_safi2str(pkt_safi),
- CHECK_FLAG(bac.flags, BGP_ADDPATH_RX) ? ", receive" : "",
- CHECK_FLAG(bac.flags, BGP_ADDPATH_TX) ? ", transmit"
- : "");
-
- if (bgp_map_afi_safi_iana2int(pkt_afi, pkt_safi, &afi,
- &safi)) {
- if (bgp_debug_neighbor_events(peer))
- zlog_debug("%s Addr-family %s/%s(afi/safi) not supported. Ignore the Addpath Attribute for this AFI/SAFI",
- peer->host,
- iana_afi2str(pkt_afi),
- iana_safi2str(pkt_safi));
- goto ignore;
- } else if (!peer->afc[afi][safi]) {
- if (bgp_debug_neighbor_events(peer))
- zlog_debug("%s Addr-family %s/%s(afi/safi) not enabled. Ignore the AddPath capability for this AFI/SAFI",
- peer->host,
- iana_afi2str(pkt_afi),
- iana_safi2str(pkt_safi));
- goto ignore;
- }
-
- if (CHECK_FLAG(bac.flags, BGP_ADDPATH_RX))
- SET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_RX_RCV);
- else
- UNSET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_RX_RCV);
-
- if (CHECK_FLAG(bac.flags, BGP_ADDPATH_TX))
- SET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_TX_RCV);
- else
- UNSET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_TX_RCV);
-
-ignore:
- data += CAPABILITY_CODE_ADDPATH_LEN;
- }
- } else {
- FOREACH_AFI_SAFI (afi, safi) {
- UNSET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_RX_RCV);
- UNSET_FLAG(peer->af_cap[afi][safi],
- PEER_CAP_ADDPATH_AF_TX_RCV);
- }
-
- UNSET_FLAG(peer->cap, PEER_CAP_ADDPATH_RCV);
- }
-}
-
static void bgp_dynamic_capability_paths_limit(uint8_t *pnt, int action,
struct capability_header *hdr,
struct peer *peer)
@@ -4030,9 +3856,6 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
case CAPABILITY_CODE_LLGR:
bgp_dynamic_capability_llgr(pnt, action, hdr, peer);
break;
- case CAPABILITY_CODE_ADDPATH:
- bgp_dynamic_capability_addpath(pnt, action, hdr, peer);
- break;
case CAPABILITY_CODE_PATHS_LIMIT:
bgp_dynamic_capability_paths_limit(pnt, action, hdr,
peer);
@@ -4046,6 +3869,7 @@ static int bgp_capability_msg_parse(struct peer *peer, uint8_t *pnt,
case CAPABILITY_CODE_REFRESH:
case CAPABILITY_CODE_AS4:
case CAPABILITY_CODE_DYNAMIC:
+ case CAPABILITY_CODE_ADDPATH:
case CAPABILITY_CODE_ENHANCED_RR:
case CAPABILITY_CODE_EXT_MESSAGE:
break;
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 8b94892b39..f2e61e1e7f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -4923,6 +4923,7 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bool force_evpn_import = false;
safi_t orig_safi = safi;
struct bgp_labels bgp_labels = {};
+ struct bgp_route_evpn *p_evpn = evpn;
uint8_t i;
if (frrtrace_enabled(frr_bgp, process_update)) {
@@ -4964,11 +4965,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
* will not be interned. In which case, it is ok to update the
* attr->evpn_overlay, so that, this can be stored in adj_in.
*/
- if (evpn) {
- if (afi == AFI_L2VPN)
- bgp_attr_set_evpn_overlay(attr, evpn);
- else
- evpn_overlay_free(evpn);
+ if (evpn && afi == AFI_L2VPN) {
+ bgp_attr_set_evpn_overlay(attr, evpn);
+ p_evpn = NULL;
}
bgp_adj_in_set(dest, peer, attr, addpath_id, &bgp_labels);
}
@@ -5141,11 +5140,9 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
* attr->evpn_overlay with evpn directly. Instead memcpy
* evpn to new_atr.evpn_overlay before it is interned.
*/
- if (soft_reconfig && evpn) {
- if (afi == AFI_L2VPN)
- bgp_attr_set_evpn_overlay(&new_attr, evpn);
- else
- evpn_overlay_free(evpn);
+ if (soft_reconfig && evpn && afi == AFI_L2VPN) {
+ bgp_attr_set_evpn_overlay(&new_attr, evpn);
+ p_evpn = NULL;
}
/* Apply incoming route-map.
@@ -5314,7 +5311,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
bgp_dest_unlock_node(dest);
bgp_attr_unintern(&attr_new);
-
+ if (p_evpn)
+ evpn_overlay_free(p_evpn);
return;
}
@@ -5479,6 +5477,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
ret = bgp_damp_update(pi, dest, afi, safi);
if (ret == BGP_DAMP_SUPPRESSED) {
bgp_dest_unlock_node(dest);
+ if (p_evpn)
+ evpn_overlay_free(p_evpn);
return;
}
}
@@ -5565,6 +5565,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
type, sub_type, NULL);
}
#endif
+ if (p_evpn)
+ evpn_overlay_free(p_evpn);
return;
} // End of implicit withdraw
@@ -5659,6 +5661,8 @@ void bgp_update(struct peer *peer, const struct prefix *p, uint32_t addpath_id,
}
#endif
+ if (p_evpn)
+ evpn_overlay_free(p_evpn);
return;
/* This BGP update is filtered. Log the reason then update BGP
@@ -5722,6 +5726,8 @@ filtered:
}
#endif
+ if (p_evpn)
+ evpn_overlay_free(p_evpn);
return;
}
@@ -10945,6 +10951,12 @@ void route_vty_out_detail(struct vty *vty, struct bgp *bgp, struct bgp_dest *bn,
else
vty_out(vty, ", (stale)");
}
+ if (bgp_path_suppressed(path)) {
+ if (json_paths)
+ json_object_boolean_true_add(json_path, "suppressed");
+ else
+ vty_out(vty, ", (suppressed)");
+ }
if (CHECK_FLAG(attr->flag, ATTR_FLAG_BIT(BGP_ATTR_AGGREGATOR))) {
if (json_paths) {
@@ -15233,7 +15245,7 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
if (type == bgp_show_adj_route_advertised ||
type == bgp_show_adj_route_received) {
if (first) {
- vty_out(vty, "\"%s\":", rd_str);
+ vty_out(vty, "{\"%s\":", rd_str);
first = false;
} else {
vty_out(vty, ",\"%s\":", rd_str);
@@ -15247,6 +15259,8 @@ static int peer_adj_routes(struct vty *vty, struct peer *peer, afi_t afi,
output_count += output_count_per_rd;
filtered_count += filtered_count_per_rd;
}
+ if (first == false && json_routes)
+ vty_out(vty, "}");
} else {
show_adj_route(vty, peer, table, afi, safi, type, rmap_name,
json, json_ar, show_flags, &header1, &header2,
diff --git a/bgpd/bgp_updgrp.c b/bgpd/bgp_updgrp.c
index 35ddfc34ff..c6b1ff1d2f 100644
--- a/bgpd/bgp_updgrp.c
+++ b/bgpd/bgp_updgrp.c
@@ -2037,13 +2037,16 @@ int update_group_adjust_soloness(struct peer *peer, int set)
struct peer_group *group;
struct listnode *node, *nnode;
- peer_flag_set(peer, PEER_FLAG_LONESOUL);
-
if (!CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP)) {
peer_lonesoul_or_not(peer, set);
if (peer_established(peer->connection))
bgp_announce_route_all(peer);
} else {
+ if (set)
+ peer_flag_set(peer, PEER_FLAG_LONESOUL);
+ else
+ peer_flag_unset(peer, PEER_FLAG_LONESOUL);
+
group = peer->group;
for (ALL_LIST_ELEMENTS(group->peer, node, nnode, peer)) {
peer_lonesoul_or_not(peer, set);
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index 33b220d3ec..046b18f224 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -1499,13 +1499,12 @@ DEFUN_NOSH (router_bgp,
int idx_asn = 2;
int idx_view_vrf = 3;
int idx_vrf = 4;
- int is_new_bgp = 0;
int idx_asnotation = 3;
int idx_asnotation_kind = 4;
enum asnotation_mode asnotation = ASNOTATION_UNDEFINED;
int ret;
as_t as;
- struct bgp *bgp;
+ struct bgp *bgp = NULL;
const char *name = NULL;
enum bgp_instance_type inst_type;
@@ -1567,35 +1566,40 @@ DEFUN_NOSH (router_bgp,
asnotation = ASNOTATION_PLAIN;
}
- if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
- is_new_bgp = (bgp_lookup(as, name) == NULL);
-
- ret = bgp_get_vty(&bgp, &as, name, inst_type,
- argv[idx_asn]->arg, asnotation);
+ ret = bgp_lookup_by_as_name_type(&bgp, &as, argv[idx_asn]->arg, asnotation, name,
+ inst_type, true);
+ if (bgp && ret == BGP_INSTANCE_EXISTS)
+ ret = CMD_SUCCESS;
+ else if (bgp == NULL && ret == CMD_SUCCESS)
+ /* SUCCESS and bgp is NULL */
+ ret = bgp_get_vty(&bgp, &as, name, inst_type, argv[idx_asn]->arg,
+ asnotation);
switch (ret) {
case BGP_ERR_AS_MISMATCH:
vty_out(vty, "BGP is already running; AS is %s\n",
- bgp->as_pretty);
+ bgp ? bgp->as_pretty : "unknown");
return CMD_WARNING_CONFIG_FAILED;
case BGP_ERR_INSTANCE_MISMATCH:
vty_out(vty,
"BGP instance name and AS number mismatch\n");
- vty_out(vty,
- "BGP instance is already running; AS is %s\n",
- bgp->as_pretty);
+ vty_out(vty, "BGP instance is already running; AS is %s\n",
+ bgp ? bgp->as_pretty : "unknown");
return CMD_WARNING_CONFIG_FAILED;
}
+ if (!bgp) {
+ vty_out(vty, "BGP instance not found\n");
+ return CMD_WARNING_CONFIG_FAILED;
+ }
/*
* If we just instantiated the default instance, complete
* any pending VRF-VPN leaking that was configured via
* earlier "router bgp X vrf FOO" blocks.
*/
- if (is_new_bgp && inst_type == BGP_INSTANCE_TYPE_DEFAULT)
+ if (inst_type == BGP_INSTANCE_TYPE_DEFAULT)
vpn_leak_postchange_all();
- if (inst_type == BGP_INSTANCE_TYPE_VRF ||
- IS_BGP_INSTANCE_HIDDEN(bgp)) {
+ if (inst_type == BGP_INSTANCE_TYPE_VRF || IS_BGP_INSTANCE_HIDDEN(bgp)) {
bgp_vpn_leak_export(bgp);
UNSET_FLAG(bgp->flags, BGP_FLAG_INSTANCE_HIDDEN);
UNSET_FLAG(bgp->flags, BGP_FLAG_DELETE_IN_PROGRESS);
@@ -9202,21 +9206,12 @@ DEFUN(neighbor_disable_addpath_rx,
struct peer *peer;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
- int ret;
- int action;
peer = peer_and_group_lookup_vty(vty, peer_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- action = bgp_addpath_capability_action(peer->addpath_type[afi][safi], 0);
-
- ret = peer_af_flag_set_vty(vty, peer_str, afi, safi,
- PEER_FLAG_DISABLE_ADDPATH_RX);
-
- bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action);
-
- return ret;
+ return peer_af_flag_set_vty(vty, peer_str, afi, safi, PEER_FLAG_DISABLE_ADDPATH_RX);
}
DEFUN(no_neighbor_disable_addpath_rx,
@@ -9231,21 +9226,12 @@ DEFUN(no_neighbor_disable_addpath_rx,
struct peer *peer;
afi_t afi = bgp_node_afi(vty);
safi_t safi = bgp_node_safi(vty);
- int ret;
- int action;
peer = peer_and_group_lookup_vty(vty, peer_str);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- action = bgp_addpath_capability_action(peer->addpath_type[afi][safi], 0);
-
- ret = peer_af_flag_unset_vty(vty, peer_str, afi, safi,
- PEER_FLAG_DISABLE_ADDPATH_RX);
-
- bgp_capability_send(peer, afi, safi, CAPABILITY_CODE_ADDPATH, action);
-
- return ret;
+ return peer_af_flag_unset_vty(vty, peer_str, afi, safi, PEER_FLAG_DISABLE_ADDPATH_RX);
}
DEFUN (neighbor_addpath_tx_all_paths,
@@ -9257,15 +9243,12 @@ DEFUN (neighbor_addpath_tx_all_paths,
{
int idx_peer = 1;
struct peer *peer;
- afi_t afi = bgp_node_afi(vty);
- safi_t safi = bgp_node_safi(vty);
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_ALL, 0);
-
+ bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), BGP_ADDPATH_ALL, 0);
return CMD_SUCCESS;
}
@@ -9285,20 +9268,18 @@ DEFUN (no_neighbor_addpath_tx_all_paths,
{
int idx_peer = 2;
struct peer *peer;
- afi_t afi = bgp_node_afi(vty);
- safi_t safi = bgp_node_safi(vty);
peer = peer_and_group_lookup_vty(vty, argv[idx_peer]->arg);
if (!peer)
return CMD_WARNING_CONFIG_FAILED;
- if (peer->addpath_type[afi][safi] != BGP_ADDPATH_ALL) {
+ if (peer->addpath_type[bgp_node_afi(vty)][bgp_node_safi(vty)] != BGP_ADDPATH_ALL) {
vty_out(vty,
"%% Peer not currently configured to transmit all paths.");
return CMD_WARNING_CONFIG_FAILED;
}
- bgp_addpath_set_peer_type(peer, afi, safi, BGP_ADDPATH_NONE, 0);
+ bgp_addpath_set_peer_type(peer, bgp_node_afi(vty), bgp_node_safi(vty), BGP_ADDPATH_NONE, 0);
return CMD_SUCCESS;
}
@@ -10559,7 +10540,7 @@ DEFPY(bgp_imexport_vrf, bgp_imexport_vrf_cmd,
SET_FLAG(bgp_default->flags, BGP_FLAG_INSTANCE_HIDDEN);
}
- vrf_bgp = bgp_lookup_by_name(import_name);
+ vrf_bgp = bgp_lookup_by_name_filter(import_name, false);
if (!vrf_bgp) {
if (strcmp(import_name, VRF_DEFAULT_NAME) == 0) {
vrf_bgp = bgp_default;
@@ -17594,12 +17575,6 @@ DEFUN (bgp_redistribute_ipv4_ospf,
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
else {
- if (bgp->vrf_id != VRF_DEFAULT) {
- vty_out(vty,
- "%% Only default BGP instance can use '%s'\n",
- argv[idx_ospf_table]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
strlen("table-direct")) == 0) {
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
@@ -17653,12 +17628,6 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap,
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
else {
- if (bgp->vrf_id != VRF_DEFAULT) {
- vty_out(vty,
- "%% Only default BGP instance can use '%s'\n",
- argv[idx_ospf_table]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
strlen("table-direct")) == 0) {
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
@@ -17716,12 +17685,6 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric,
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
else {
- if (bgp->vrf_id != VRF_DEFAULT) {
- vty_out(vty,
- "%% Only default BGP instance can use '%s'\n",
- argv[idx_ospf_table]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
strlen("table-direct")) == 0) {
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
@@ -17786,12 +17749,6 @@ DEFUN (bgp_redistribute_ipv4_ospf_rmap_metric,
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
else {
- if (bgp->vrf_id != VRF_DEFAULT) {
- vty_out(vty,
- "%% Only default BGP instance can use '%s'\n",
- argv[idx_ospf_table]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
strlen("table-direct")) == 0) {
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
@@ -17861,13 +17818,7 @@ DEFUN (bgp_redistribute_ipv4_ospf_metric_rmap,
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
else {
- if (bgp->vrf_id != VRF_DEFAULT) {
- vty_out(vty,
- "%% Only default BGP instance can use '%s'\n",
- argv[idx_ospf_table]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- } else if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
- strlen("table-direct")) == 0) {
+ if (strncmp(argv[idx_ospf_table]->arg, "table-direct", strlen("table-direct")) == 0) {
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
if (instance == RT_TABLE_MAIN ||
instance == RT_TABLE_LOCAL) {
@@ -17930,12 +17881,6 @@ DEFUN (no_bgp_redistribute_ipv4_ospf,
if (strncmp(argv[idx_ospf_table]->arg, "o", 1) == 0)
protocol = ZEBRA_ROUTE_OSPF;
else {
- if (bgp->vrf_id != VRF_DEFAULT) {
- vty_out(vty,
- "%% Only default BGP instance can use '%s'\n",
- argv[idx_ospf_table]->arg);
- return CMD_WARNING_CONFIG_FAILED;
- }
if (strncmp(argv[idx_ospf_table]->arg, "table-direct",
strlen("table-direct")) == 0) {
protocol = ZEBRA_ROUTE_TABLE_DIRECT;
diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c
index 8e8616c155..179404a2ce 100644
--- a/bgpd/bgp_zebra.c
+++ b/bgpd/bgp_zebra.c
@@ -2042,11 +2042,34 @@ int bgp_redistribute_set(struct bgp *bgp, afi_t afi, int type,
/* Return if already redistribute flag is set. */
if (instance) {
- if (redist_check_instance(&zclient->mi_redist[afi][type],
- instance))
- return CMD_WARNING;
+ if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
+ /*
+ * When redistribution type is `table-direct` the
+ * instance means `table identification`.
+ *
+ * `table_id` support 32bit integers, however since
+ * `instance` is being overloaded to `table_id` it
+ * will only be possible to use the first 65535
+ * entries.
+ *
+ * Also the ZAPI must also support `int`
+ * (see `zebra_redistribute_add`).
+ */
+ struct redist_table_direct table = {
+ .table_id = instance,
+ .vrf_id = bgp->vrf_id,
+ };
+ if (redist_lookup_table_direct(&zclient->mi_redist[afi][type], &table) !=
+ NULL)
+ return CMD_WARNING;
+
+ redist_add_table_direct(&zclient->mi_redist[afi][type], &table);
+ } else {
+ if (redist_check_instance(&zclient->mi_redist[afi][type], instance))
+ return CMD_WARNING;
- redist_add_instance(&zclient->mi_redist[afi][type], instance);
+ redist_add_instance(&zclient->mi_redist[afi][type], instance);
+ }
} else {
if (vrf_bitmap_check(&zclient->redist[afi][type], bgp->vrf_id))
return CMD_WARNING;
@@ -2174,10 +2197,22 @@ int bgp_redistribute_unreg(struct bgp *bgp, afi_t afi, int type,
/* Return if zebra connection is disabled. */
if (instance) {
- if (!redist_check_instance(&zclient->mi_redist[afi][type],
- instance))
- return CMD_WARNING;
- redist_del_instance(&zclient->mi_redist[afi][type], instance);
+ if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
+ struct redist_table_direct table = {
+ .table_id = instance,
+ .vrf_id = bgp->vrf_id,
+ };
+ if (redist_lookup_table_direct(&zclient->mi_redist[afi][type], &table) ==
+ NULL)
+ return CMD_WARNING;
+
+ redist_del_table_direct(&zclient->mi_redist[afi][type], &table);
+ } else {
+ if (!redist_check_instance(&zclient->mi_redist[afi][type], instance))
+ return CMD_WARNING;
+
+ redist_del_instance(&zclient->mi_redist[afi][type], instance);
+ }
} else {
if (!vrf_bitmap_check(&zclient->redist[afi][type], bgp->vrf_id))
return CMD_WARNING;
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index c2254ae791..edf90d3dd8 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -2026,8 +2026,11 @@ struct peer *peer_create(union sockunion *su, const char *conf_if,
if (bgp->autoshutdown)
peer_flag_set(peer, PEER_FLAG_SHUTDOWN);
/* Set up peer's events and timers. */
- else if (!active && peer_active(peer->connection))
+ else if (!active && peer_active(peer->connection)) {
+ if (peer->last_reset == PEER_DOWN_NOAFI_ACTIVATED)
+ peer->last_reset = 0;
bgp_timer_set(peer->connection);
+ }
bgp_peer_gr_flags_update(peer);
BGP_GR_ROUTER_DETECT_AND_SEND_CAPABILITY_TO_ZEBRA(bgp, bgp->peer);
@@ -3634,13 +3637,13 @@ struct bgp *bgp_lookup(as_t as, const char *name)
}
/* Lookup BGP structure by view name. */
-struct bgp *bgp_lookup_by_name(const char *name)
+struct bgp *bgp_lookup_by_name_filter(const char *name, bool filter_auto)
{
struct bgp *bgp;
struct listnode *node, *nnode;
for (ALL_LIST_ELEMENTS(bm->bgp, node, nnode, bgp)) {
- if (CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
+ if (filter_auto && CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO))
continue;
if ((bgp->name == NULL && name == NULL)
|| (bgp->name && name && strcmp(bgp->name, name) == 0))
@@ -3649,6 +3652,11 @@ struct bgp *bgp_lookup_by_name(const char *name)
return NULL;
}
+struct bgp *bgp_lookup_by_name(const char *name)
+{
+ return bgp_lookup_by_name_filter(name, true);
+}
+
/* Lookup BGP instance based on VRF id. */
/* Note: Only to be used for incoming messages from Zebra. */
struct bgp *bgp_lookup_by_vrf_id(vrf_id_t vrf_id)
@@ -3734,10 +3742,9 @@ int bgp_handle_socket(struct bgp *bgp, struct vrf *vrf, vrf_id_t old_vrf_id,
return bgp_check_main_socket(create, bgp);
}
-int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
- const char *as_pretty,
+int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *as_pretty,
enum asnotation_mode asnotation, const char *name,
- enum bgp_instance_type inst_type)
+ enum bgp_instance_type inst_type, bool force_config)
{
struct bgp *bgp;
struct peer *peer = NULL;
@@ -3746,7 +3753,7 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
/* Multiple instance check. */
if (name)
- bgp = bgp_lookup_by_name(name);
+ bgp = bgp_lookup_by_name_filter(name, !force_config);
else
bgp = bgp_get_default();
@@ -3756,7 +3763,7 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
/* Handle AS number change */
if (bgp->as != *as) {
if (hidden || CHECK_FLAG(bgp->vrf_flags, BGP_VRF_AUTO)) {
- if (hidden) {
+ if (force_config == false && hidden) {
bgp_create(as, name, inst_type,
as_pretty, asnotation, bgp,
hidden);
@@ -3764,7 +3771,8 @@ int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
BGP_FLAG_INSTANCE_HIDDEN);
} else {
bgp->as = *as;
- UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO);
+ if (force_config == false)
+ UNSET_FLAG(bgp->vrf_flags, BGP_VRF_AUTO);
}
/* Set all peer's local AS with this ASN */
@@ -3801,8 +3809,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
struct vrf *vrf = NULL;
int ret = 0;
- ret = bgp_lookup_by_as_name_type(bgp_val, as, as_pretty, asnotation,
- name, inst_type);
+ ret = bgp_lookup_by_as_name_type(bgp_val, as, as_pretty, asnotation, name, inst_type, false);
if (ret || *bgp_val)
return ret;
@@ -4816,39 +4823,40 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{0, 0, 0}};
static const struct peer_flag_action peer_af_flag_action_list[] = {
- {PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out},
- {PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out},
- {PEER_FLAG_SEND_LARGE_COMMUNITY, 1, peer_change_reset_out},
- {PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out},
- {PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset},
- {PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset},
- {PEER_FLAG_SOFT_RECONFIG, 0, peer_change_reset_in},
- {PEER_FLAG_AS_PATH_UNCHANGED, 1, peer_change_reset_out},
- {PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out},
- {PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out},
- {PEER_FLAG_DEFAULT_ORIGINATE, 0, peer_change_none},
- {PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out},
- {PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in},
- {PEER_FLAG_ALLOWAS_IN_ORIGIN, 0, peer_change_reset_in},
- {PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset},
- {PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset},
- {PEER_FLAG_MAX_PREFIX, 0, peer_change_none},
- {PEER_FLAG_MAX_PREFIX_WARNING, 0, peer_change_none},
- {PEER_FLAG_MAX_PREFIX_FORCE, 0, peer_change_none},
- {PEER_FLAG_MAX_PREFIX_OUT, 0, peer_change_none},
- {PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out},
- {PEER_FLAG_FORCE_NEXTHOP_SELF, 1, peer_change_reset_out},
- {PEER_FLAG_REMOVE_PRIVATE_AS_ALL, 1, peer_change_reset_out},
- {PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE, 1, peer_change_reset_out},
- {PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out},
- {PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, 1, peer_change_reset_out},
- {PEER_FLAG_WEIGHT, 0, peer_change_reset_in},
- {PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_none},
- {PEER_FLAG_SOO, 0, peer_change_reset},
- {PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset},
- {PEER_FLAG_SEND_EXT_COMMUNITY_RPKI, 1, peer_change_reset_out},
- {PEER_FLAG_ADDPATH_RX_PATHS_LIMIT, 0, peer_change_none},
- {0, 0, 0}};
+ { PEER_FLAG_SEND_COMMUNITY, 1, peer_change_reset_out },
+ { PEER_FLAG_SEND_EXT_COMMUNITY, 1, peer_change_reset_out },
+ { PEER_FLAG_SEND_LARGE_COMMUNITY, 1, peer_change_reset_out },
+ { PEER_FLAG_NEXTHOP_SELF, 1, peer_change_reset_out },
+ { PEER_FLAG_REFLECTOR_CLIENT, 1, peer_change_reset },
+ { PEER_FLAG_RSERVER_CLIENT, 1, peer_change_reset },
+ { PEER_FLAG_SOFT_RECONFIG, 0, peer_change_reset_in },
+ { PEER_FLAG_AS_PATH_UNCHANGED, 1, peer_change_reset_out },
+ { PEER_FLAG_NEXTHOP_UNCHANGED, 1, peer_change_reset_out },
+ { PEER_FLAG_MED_UNCHANGED, 1, peer_change_reset_out },
+ { PEER_FLAG_DEFAULT_ORIGINATE, 0, peer_change_none },
+ { PEER_FLAG_REMOVE_PRIVATE_AS, 1, peer_change_reset_out },
+ { PEER_FLAG_ALLOWAS_IN, 0, peer_change_reset_in },
+ { PEER_FLAG_ALLOWAS_IN_ORIGIN, 0, peer_change_reset_in },
+ { PEER_FLAG_ORF_PREFIX_SM, 1, peer_change_reset },
+ { PEER_FLAG_ORF_PREFIX_RM, 1, peer_change_reset },
+ { PEER_FLAG_MAX_PREFIX, 0, peer_change_none },
+ { PEER_FLAG_MAX_PREFIX_WARNING, 0, peer_change_none },
+ { PEER_FLAG_MAX_PREFIX_FORCE, 0, peer_change_none },
+ { PEER_FLAG_MAX_PREFIX_OUT, 0, peer_change_none },
+ { PEER_FLAG_NEXTHOP_LOCAL_UNCHANGED, 0, peer_change_reset_out },
+ { PEER_FLAG_FORCE_NEXTHOP_SELF, 1, peer_change_reset_out },
+ { PEER_FLAG_REMOVE_PRIVATE_AS_ALL, 1, peer_change_reset_out },
+ { PEER_FLAG_REMOVE_PRIVATE_AS_REPLACE, 1, peer_change_reset_out },
+ { PEER_FLAG_AS_OVERRIDE, 1, peer_change_reset_out },
+ { PEER_FLAG_REMOVE_PRIVATE_AS_ALL_REPLACE, 1, peer_change_reset_out },
+ { PEER_FLAG_WEIGHT, 0, peer_change_reset_in },
+ { PEER_FLAG_DISABLE_ADDPATH_RX, 0, peer_change_reset },
+ { PEER_FLAG_SOO, 0, peer_change_reset },
+ { PEER_FLAG_ACCEPT_OWN, 0, peer_change_reset },
+ { PEER_FLAG_SEND_EXT_COMMUNITY_RPKI, 1, peer_change_reset_out },
+ { PEER_FLAG_ADDPATH_RX_PATHS_LIMIT, 0, peer_change_none },
+ { 0, 0, 0 }
+};
/* Proper action set. */
static int peer_flag_action_set(const struct peer_flag_action *action_list,
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index c72072852d..96a78e6662 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -2285,6 +2285,7 @@ extern void bgp_zclient_reset(void);
extern struct bgp *bgp_get_default(void);
extern struct bgp *bgp_lookup(as_t, const char *);
extern struct bgp *bgp_lookup_by_name(const char *);
+extern struct bgp *bgp_lookup_by_name_filter(const char *name, bool filter_auto);
extern struct bgp *bgp_lookup_by_vrf_id(vrf_id_t);
extern struct bgp *bgp_get_evpn(void);
extern void bgp_set_evpn(struct bgp *bgp);
@@ -2859,11 +2860,9 @@ extern struct peer *peer_new(struct bgp *bgp);
extern struct peer *peer_lookup_in_view(struct vty *vty, struct bgp *bgp,
const char *ip_str, bool use_json);
-extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as,
- const char *as_pretty,
- enum asnotation_mode asnotation,
- const char *name,
- enum bgp_instance_type inst_type);
+extern int bgp_lookup_by_as_name_type(struct bgp **bgp_val, as_t *as, const char *as_pretty,
+ enum asnotation_mode asnotation, const char *name,
+ enum bgp_instance_type inst_type, bool force_config);
/* Hooks */
DECLARE_HOOK(bgp_vrf_status_changed, (struct bgp *bgp, struct interface *ifp),
diff --git a/isisd/isis_tlvs.h b/isisd/isis_tlvs.h
index c64bbf7f69..5798d318f2 100644
--- a/isisd/isis_tlvs.h
+++ b/isisd/isis_tlvs.h
@@ -777,12 +777,6 @@ struct list *isis_fragment_tlvs(struct isis_tlvs *tlvs, size_t size);
#define ISIS_MT_AT_MASK 0x4000
#endif
-/* RFC 8919 */
-#define ISIS_SABM_FLAG_R 0x80 /* RSVP-TE */
-#define ISIS_SABM_FLAG_S 0x40 /* Segment Routing Policy */
-#define ISIS_SABM_FLAG_L 0x20 /* Loop-Free Alternate */
-#define ISIS_SABM_FLAG_X 0x10 /* Flex-Algorithm - RFC9350 */
-
void isis_tlvs_add_auth(struct isis_tlvs *tlvs, struct isis_passwd *passwd);
void isis_tlvs_add_area_addresses(struct isis_tlvs *tlvs,
struct list *addresses);
diff --git a/lib/zclient.c b/lib/zclient.c
index 063944fd3b..9f6542eb31 100644
--- a/lib/zclient.c
+++ b/lib/zclient.c
@@ -31,6 +31,7 @@
DEFINE_MTYPE_STATIC(LIB, ZCLIENT, "Zclient");
DEFINE_MTYPE_STATIC(LIB, REDIST_INST, "Redistribution instance IDs");
+DEFINE_MTYPE_STATIC(LIB, REDIST_TABLE_DIRECT, "Redistribution table direct");
/* Zebra client events. */
enum zclient_event { ZCLIENT_SCHEDULE, ZCLIENT_READ, ZCLIENT_CONNECT };
@@ -104,6 +105,11 @@ void zclient_free(struct zclient *zclient)
XFREE(MTYPE_ZCLIENT, zclient);
}
+static void redist_free_instance(void *data)
+{
+ XFREE(MTYPE_REDIST_INST, data);
+}
+
unsigned short *redist_check_instance(struct redist_proto *red,
unsigned short instance)
{
@@ -126,8 +132,10 @@ void redist_add_instance(struct redist_proto *red, unsigned short instance)
red->enabled = 1;
- if (!red->instances)
+ if (!red->instances) {
red->instances = list_new();
+ red->instances->del = redist_free_instance;
+ }
in = XMALLOC(MTYPE_REDIST_INST, sizeof(unsigned short));
*in = instance;
@@ -143,23 +151,100 @@ void redist_del_instance(struct redist_proto *red, unsigned short instance)
return;
listnode_delete(red->instances, id);
- XFREE(MTYPE_REDIST_INST, id);
+ red->instances->del(id);
if (!red->instances->count) {
red->enabled = 0;
list_delete(&red->instances);
}
}
-void redist_del_all_instances(struct redist_proto *red)
+static void redist_free_table_direct(void *data)
{
- struct listnode *ln, *nn;
- unsigned short *id;
+ XFREE(MTYPE_REDIST_TABLE_DIRECT, data);
+}
+
+struct redist_table_direct *redist_lookup_table_direct(const struct redist_proto *red,
+ const struct redist_table_direct *table)
+{
+ struct redist_table_direct *ntable;
+ struct listnode *node;
+
+ if (red->instances == NULL)
+ return NULL;
+
+ for (ALL_LIST_ELEMENTS_RO(red->instances, node, ntable)) {
+ if (table->vrf_id != ntable->vrf_id)
+ continue;
+ if (table->table_id != ntable->table_id)
+ continue;
+
+ return ntable;
+ }
+
+ return NULL;
+}
+
+bool redist_table_direct_has_id(const struct redist_proto *red, int table_id)
+{
+ struct redist_table_direct *table;
+ struct listnode *node;
+
+ if (red->instances == NULL)
+ return false;
+
+ for (ALL_LIST_ELEMENTS_RO(red->instances, node, table)) {
+ if (table->table_id != table_id)
+ continue;
+
+ return true;
+ }
+
+ return false;
+}
+
+void redist_add_table_direct(struct redist_proto *red, const struct redist_table_direct *table)
+{
+ struct redist_table_direct *ntable;
+
+ ntable = redist_lookup_table_direct(red, table);
+ if (ntable != NULL)
+ return;
+
+ if (red->instances == NULL) {
+ red->instances = list_new();
+ red->instances->del = redist_free_table_direct;
+ }
+
+ red->enabled = 1;
+
+ ntable = XCALLOC(MTYPE_REDIST_TABLE_DIRECT, sizeof(*ntable));
+ ntable->vrf_id = table->vrf_id;
+ ntable->table_id = table->table_id;
+ listnode_add(red->instances, ntable);
+}
+void redist_del_table_direct(struct redist_proto *red, const struct redist_table_direct *table)
+{
+ struct redist_table_direct *ntable;
+
+ ntable = redist_lookup_table_direct(red, table);
+ if (ntable == NULL)
+ return;
+
+ listnode_delete(red->instances, ntable);
+ red->instances->del(ntable);
+ if (red->instances->count == 0) {
+ red->enabled = 0;
+ list_delete(&red->instances);
+ }
+}
+
+void redist_del_all_instances(struct redist_proto *red)
+{
if (!red->instances)
return;
- for (ALL_LIST_ELEMENTS(red->instances, ln, nn, id))
- redist_del_instance(red, *id);
+ list_delete(&red->instances);
}
/* Stop zebra client services. */
@@ -480,6 +565,17 @@ enum zclient_send_status zclient_send_localsid(struct zclient *zclient,
return zclient_route_send(ZEBRA_ROUTE_ADD, zclient, &api);
}
+static void zclient_send_table_direct(struct zclient *zclient, afi_t afi, int type)
+{
+ struct redist_table_direct *table;
+ struct redist_proto *red = &zclient->mi_redist[afi][ZEBRA_ROUTE_TABLE_DIRECT];
+ struct listnode *node;
+
+ for (ALL_LIST_ELEMENTS_RO(red->instances, node, table))
+ zebra_redistribute_send(type, zclient, afi, ZEBRA_ROUTE_TABLE_DIRECT,
+ table->table_id, table->vrf_id);
+}
+
/* Send register requests to zebra daemon for the information in a VRF. */
void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
{
@@ -513,6 +609,12 @@ void zclient_send_reg_requests(struct zclient *zclient, vrf_id_t vrf_id)
if (!zclient->mi_redist[afi][i].enabled)
continue;
+ if (i == ZEBRA_ROUTE_TABLE_DIRECT) {
+ zclient_send_table_direct(zclient, afi,
+ ZEBRA_REDISTRIBUTE_ADD);
+ continue;
+ }
+
struct listnode *node;
unsigned short *id;
@@ -580,6 +682,12 @@ void zclient_send_dereg_requests(struct zclient *zclient, vrf_id_t vrf_id)
if (!zclient->mi_redist[afi][i].enabled)
continue;
+ if (i == ZEBRA_ROUTE_TABLE_DIRECT) {
+ zclient_send_table_direct(zclient, afi,
+ ZEBRA_REDISTRIBUTE_DELETE);
+ continue;
+ }
+
struct listnode *node;
unsigned short *id;
@@ -4634,9 +4742,52 @@ static void zclient_read(struct event *thread)
zclient_event(ZCLIENT_READ, zclient);
}
+static void zclient_redistribute_table_direct(struct zclient *zclient, vrf_id_t vrf_id, afi_t afi,
+ int instance, int command)
+{
+ struct redist_proto *red = &zclient->mi_redist[afi][ZEBRA_ROUTE_TABLE_DIRECT];
+ bool has_table;
+ struct redist_table_direct table = {
+ .vrf_id = vrf_id,
+ .table_id = instance,
+ };
+
+ has_table = redist_lookup_table_direct(red, &table);
+
+ if (command == ZEBRA_REDISTRIBUTE_ADD) {
+ if (has_table)
+ return;
+
+ redist_add_table_direct(red, &table);
+ } else {
+ if (!has_table)
+ return;
+
+ redist_del_table_direct(red, &table);
+ }
+
+ if (zclient->sock > 0)
+ zebra_redistribute_send(command, zclient, afi, ZEBRA_ROUTE_TABLE_DIRECT, instance,
+ vrf_id);
+}
+
void zclient_redistribute(int command, struct zclient *zclient, afi_t afi,
int type, unsigned short instance, vrf_id_t vrf_id)
{
+ /*
+ * When asking for table-direct redistribution the parameter
+ * `instance` has a different meaning: it means table
+ * identification.
+ *
+ * The table identification information is stored in
+ * `zclient->mi_redist` along with the VRF identification
+ * information in a pair (different from the usual single protocol
+ * instance value).
+ */
+ if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
+ zclient_redistribute_table_direct(zclient, vrf_id, afi, instance, command);
+ return;
+ }
if (instance) {
if (command == ZEBRA_REDISTRIBUTE_ADD) {
diff --git a/lib/zclient.h b/lib/zclient.h
index 2385a8a219..f3657822b8 100644
--- a/lib/zclient.h
+++ b/lib/zclient.h
@@ -268,6 +268,21 @@ struct redist_proto {
struct list *instances;
};
+/**
+ * Redistribute table direct instance data structure: keeps the VRF
+ * that subscribed to the table ID.
+ *
+ * **NOTE**
+ * `table_id` is an integer because that is what the netlink interface
+ * uses for route attribute RTA_TABLE (32bit int), however the whole
+ * zclient API uses `unsigned short` (and CLI commands) so it will be
+ * limited to the range 1 to 65535.
+ */
+struct redist_table_direct {
+ vrf_id_t vrf_id;
+ int table_id;
+};
+
struct zclient_capabilities {
uint32_t ecmp;
bool mpls_enabled;
@@ -924,6 +939,15 @@ extern void redist_add_instance(struct redist_proto *, unsigned short);
extern void redist_del_instance(struct redist_proto *, unsigned short);
extern void redist_del_all_instances(struct redist_proto *red);
+extern struct redist_table_direct *
+redist_lookup_table_direct(const struct redist_proto *red, const struct redist_table_direct *table);
+extern bool redist_table_direct_has_id(const struct redist_proto *red, int table_id);
+extern void redist_add_table_direct(struct redist_proto *red,
+ const struct redist_table_direct *table);
+extern void redist_del_table_direct(struct redist_proto *red,
+ const struct redist_table_direct *table);
+
+
/*
* Send to zebra that the specified vrf is using label to resolve
* itself for L3VPN's. Repeated calls of this function with
diff --git a/redhat/frr.spec.in b/redhat/frr.spec.in
index 4c0a654c8e..4e0196d24a 100644
--- a/redhat/frr.spec.in
+++ b/redhat/frr.spec.in
@@ -191,6 +191,9 @@ BuildRequires: ncurses-devel
BuildRequires: readline-devel
BuildRequires: texinfo
BuildRequires: libyang-devel >= 2.1.128
+# Version requirement don't get reflected down from a BuildRequire
+# to Require, so need to require libyang version as both ways
+Requires: libyang >= 2.1.128
BuildRequires: pcre2-devel
%if 0%{?rhel} && 0%{?rhel} < 7
#python27-devel is available from ius community repo for RedHat/CentOS 6
diff --git a/tests/topotests/bgp_aggregate_address_topo1/r1/bgp_192_168_0_1.json b/tests/topotests/bgp_aggregate_address_topo1/r1/bgp_192_168_0_1.json
new file mode 100644
index 0000000000..8c0da8dc92
--- /dev/null
+++ b/tests/topotests/bgp_aggregate_address_topo1/r1/bgp_192_168_0_1.json
@@ -0,0 +1,41 @@
+{
+ "prefix":"192.168.0.1/32",
+ "paths":[
+ {
+ "aspath":{
+ "string":"65001",
+ "segments":[
+ {
+ "type":"as-sequence",
+ "list":[
+ 65001
+ ]
+ }
+ ],
+ "length":1
+ },
+ "suppressed":true,
+ "origin":"IGP",
+ "metric":10,
+ "valid":true,
+ "bestpath":{
+ "overall":true,
+ "selectionReason":"First path received"
+ },
+ "nexthops":[
+ {
+ "ip":"10.0.0.2",
+ "afi":"ipv4",
+ "metric":0,
+ "accessible":true,
+ "used":true
+ }
+ ],
+ "peer":{
+ "peerId":"10.0.0.2",
+ "routerId":"10.254.254.3",
+ "type":"external"
+ }
+ }
+ ]
+}
diff --git a/tests/topotests/bgp_aggregate_address_topo1/test_bgp_aggregate_address_topo1.py b/tests/topotests/bgp_aggregate_address_topo1/test_bgp_aggregate_address_topo1.py
index 370d01e525..a0a1027c98 100644
--- a/tests/topotests/bgp_aggregate_address_topo1/test_bgp_aggregate_address_topo1.py
+++ b/tests/topotests/bgp_aggregate_address_topo1/test_bgp_aggregate_address_topo1.py
@@ -13,6 +13,7 @@
Test BGP aggregate address features.
"""
+import json
import os
import sys
import pytest
@@ -265,6 +266,24 @@ match ip address acl-sup-three
)
+def test_check_bgp_attribute():
+ "Dump the suppressed attribute of the 192.168.0.1/32 prefix in r1."
+ tgen = get_topogen()
+
+ logger.info("Test that the BGP path to 192.168.0.1 is as expected.")
+ expected = json.loads(open("{}/r1/bgp_192_168_0_1.json".format(CWD)).read())
+
+ test_func = functools.partial(
+ topotest.router_json_cmp,
+ tgen.gears["r1"],
+ "show bgp ipv4 192.168.0.1/32 json",
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assertmsg = '"r1" BGP 192.168.0.1 route output failed'
+ assert result is None, assertmsg
+
+
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
diff --git a/tests/topotests/bgp_bfd_session/r1/frr.conf b/tests/topotests/bgp_bfd_session/r1/frr.conf
index a1560b09fa..cea1ff8147 100644
--- a/tests/topotests/bgp_bfd_session/r1/frr.conf
+++ b/tests/topotests/bgp_bfd_session/r1/frr.conf
@@ -11,4 +11,16 @@ router bgp 65000
neighbor 192.168.1.3 bfd
neighbor 192.168.1.3 ebgp-multihop 20
neighbor 192.168.1.3 update-source r1-eth0
+ neighbor PG peer-group
+ neighbor PG remote-as auto
+ neighbor PG bfd
+ neighbor PG ebgp-multihop 15
+ neighbor PG update-source 10.0.0.1
+ neighbor 192.168.1.4 peer-group PG
+ neighbor PG2 peer-group
+ neighbor PG2 remote-as auto
+ neighbor PG2 bfd
+ neighbor PG2 ebgp-multihop 25
+ neighbor 192.168.1.5 peer-group PG2
+ neighbor 192.168.1.5 update-source 10.0.0.1
exit
diff --git a/tests/topotests/bgp_bfd_session/test_bgp_bfd_session.py b/tests/topotests/bgp_bfd_session/test_bgp_bfd_session.py
index adf557af7b..0dbb2f089b 100644
--- a/tests/topotests/bgp_bfd_session/test_bgp_bfd_session.py
+++ b/tests/topotests/bgp_bfd_session/test_bgp_bfd_session.py
@@ -85,7 +85,29 @@ def test_bgp_bfd_session():
"diagnostic": "ok",
"remote-diagnostic": "ok",
"type": "dynamic",
- }
+ },
+ {
+ "multihop": True,
+ "peer": "192.168.1.4",
+ "local": "10.0.0.1",
+ "vrf": "default",
+ "minimum-ttl": 241,
+ "status": "down",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok",
+ "type": "dynamic",
+ },
+ {
+ "multihop": True,
+ "peer": "192.168.1.5",
+ "local": "10.0.0.1",
+ "vrf": "default",
+ "minimum-ttl": 231,
+ "status": "down",
+ "diagnostic": "ok",
+ "remote-diagnostic": "ok",
+ "type": "dynamic",
+ },
]
return topotest.json_cmp(output, expected)
diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py
index be3e07929a..1d7aa97473 100644
--- a/tests/topotests/bgp_bmp/test_bgp_bmp_1.py
+++ b/tests/topotests/bgp_bmp/test_bgp_bmp_1.py
@@ -78,7 +78,7 @@ def setup_module(mod):
"tcpdump -nni r1-eth0 -s 0 -w {} &".format(pcap_file), stdout=None
)
- for rname, router in tgen.routers().items():
+ for _, (rname, router) in enumerate(tgen.routers().items(), 1):
logger.info("Loading router %s" % rname)
router.load_frr_config(
os.path.join(CWD, "{}/frr.conf".format(rname)),
diff --git a/tests/topotests/bgp_dynamic_capability/r2/frr.conf b/tests/topotests/bgp_dynamic_capability/r2/frr.conf
index 621e9381e3..cca07078ea 100644
--- a/tests/topotests/bgp_dynamic_capability/r2/frr.conf
+++ b/tests/topotests/bgp_dynamic_capability/r2/frr.conf
@@ -18,7 +18,6 @@ router bgp 65002
neighbor 192.168.1.1 timers connect 1
neighbor 192.168.1.1 capability dynamic
neighbor 192.168.1.1 capability extended-nexthop
- neighbor 192.168.1.1 addpath-rx-paths-limit 20
neighbor 2001:db8::1 remote-as external
neighbor 2001:db8::1 timers 1 3
neighbor 2001:db8::1 timers connect 1
@@ -27,6 +26,9 @@ router bgp 65002
!
address-family ipv4 unicast
redistribute connected
+ neighbor 192.168.1.1 addpath-tx-all-paths
+ neighbor 192.168.1.1 disable-addpath-rx
+ neighbor 192.168.1.1 addpath-rx-paths-limit 20
exit-address-family
!
address-family ipv6 unicast
diff --git a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_path_limit.py
index 91df89b1b5..22e4fe687b 100644
--- a/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_addpath.py
+++ b/tests/topotests/bgp_dynamic_capability/test_bgp_dynamic_capability_path_limit.py
@@ -9,8 +9,6 @@
Test if Addpath/Paths-Limit capabilities are adjusted dynamically.
T1: Enable Addpath/Paths-Limit capabilities and check if they are exchanged dynamically
T2: Disable paths limit and check if it's exchanged dynamically
-T3: Disable Addpath capability RX and check if it's exchanged dynamically
-T4: Disable Addpath capability and check if it's exchanged dynamically
"""
import os
@@ -65,12 +63,12 @@ def test_bgp_addpath_paths_limit():
"dynamic": "advertisedAndReceived",
"addPath": {
"ipv4Unicast": {
- "txAdvertisedAndReceived": False,
+ "txAdvertisedAndReceived": True,
"txAdvertised": True,
- "txReceived": False,
- "rxAdvertisedAndReceived": True,
+ "txReceived": True,
+ "rxAdvertisedAndReceived": False,
"rxAdvertised": True,
- "rxReceived": True,
+ "rxReceived": False,
}
},
"pathsLimit": {
@@ -105,7 +103,6 @@ def test_bgp_addpath_paths_limit():
configure terminal
router bgp
address-family ipv4 unicast
- neighbor 192.168.1.1 addpath-tx-all-paths
neighbor 192.168.1.1 addpath-rx-paths-limit 21
"""
)
@@ -122,9 +119,9 @@ def test_bgp_addpath_paths_limit():
"txAdvertisedAndReceived": True,
"txAdvertised": True,
"txReceived": True,
- "rxAdvertisedAndReceived": True,
+ "rxAdvertisedAndReceived": False,
"rxAdvertised": True,
- "rxReceived": True,
+ "rxReceived": False,
}
},
"pathsLimit": {
@@ -143,7 +140,7 @@ def test_bgp_addpath_paths_limit():
"messageStats": {
"notificationsRecv": 0,
"notificationsSent": 0,
- "capabilityRecv": 2,
+ "capabilityRecv": 1,
},
}
}
@@ -181,58 +178,6 @@ def test_bgp_addpath_paths_limit():
"txAdvertisedAndReceived": True,
"txAdvertised": True,
"txReceived": True,
- "rxAdvertisedAndReceived": True,
- "rxAdvertised": True,
- "rxReceived": True,
- }
- },
- "pathsLimit": {
- "ipv4Unicast": {
- "advertisedAndReceived": True,
- "advertisedPathsLimit": 10,
- "receivedPathsLimit": 0,
- }
- },
- },
- "messageStats": {
- "notificationsRecv": 0,
- "notificationsSent": 0,
- "capabilityRecv": 3,
- },
- }
- }
- return topotest.json_cmp(output, expected)
-
- test_func = functools.partial(
- _disable_paths_limit,
- )
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
- assert result is None, "Something went wrong after disabling paths limit"
-
- ###
- # T3: Disable Addpath capability RX and check if it's exchanged dynamically
- ###
- r2.vtysh_cmd(
- """
- configure terminal
- router bgp
- address-family ipv4 unicast
- neighbor 192.168.1.1 disable-addpath-rx
- """
- )
-
- def _disable_addpath_rx():
- output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
- expected = {
- "192.168.1.2": {
- "bgpState": "Established",
- "neighborCapabilities": {
- "dynamic": "advertisedAndReceived",
- "addPath": {
- "ipv4Unicast": {
- "txAdvertisedAndReceived": True,
- "txAdvertised": True,
- "txReceived": True,
"rxAdvertisedAndReceived": False,
"rxAdvertised": True,
"rxReceived": False,
@@ -249,63 +194,17 @@ def test_bgp_addpath_paths_limit():
"messageStats": {
"notificationsRecv": 0,
"notificationsSent": 0,
- "capabilityRecv": 4,
- },
- }
- }
- return topotest.json_cmp(output, expected)
-
- test_func = functools.partial(
- _disable_addpath_rx,
- )
- _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
- assert result is None, "Something went wrong after disabling Addpath RX flags"
-
- ###
- # T4: Disable Addpath capability and check if it's exchanged dynamically
- ###
- r1.vtysh_cmd(
- """
- configure terminal
- router bgp
- address-family ipv4 unicast
- no neighbor 192.168.1.2 addpath-tx-all-paths
- """
- )
-
- def _disable_addpath():
- output = json.loads(r1.vtysh_cmd("show bgp neighbor json"))
- expected = {
- "192.168.1.2": {
- "bgpState": "Established",
- "neighborCapabilities": {
- "dynamic": "advertisedAndReceived",
- "addPath": {
- "ipv4Unicast": {
- "txAdvertisedAndReceived": False,
- "txAdvertised": False,
- "txReceived": True,
- "rxAdvertisedAndReceived": False,
- "rxAdvertised": True,
- "rxReceived": False,
- }
- },
- },
- "messageStats": {
- "notificationsRecv": 0,
- "notificationsSent": 0,
- "capabilitySent": 1,
- "capabilityRecv": 4,
+ "capabilityRecv": 2,
},
}
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(
- _disable_addpath,
+ _disable_paths_limit,
)
_, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
- assert result is None, "Something went wrong when disabling Addpath capability"
+ assert result is None, "Something went wrong after disabling paths limit"
if __name__ == "__main__":
diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes.json b/tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes.json
index 7532ce9331..cfab5726ed 100644
--- a/tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes.json
+++ b/tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes.json
@@ -2,8 +2,8 @@
"bgpLocalRouterId":"192.168.100.21",
"defaultLocPrf":100,
"localAS":65000,
- "192.168.101.41:2":{
- "rd":"192.168.101.41:2",
+ "65000:201":{
+ "rd":"65000:201",
"[5]:[0]:[32]:[192.168.101.41]":{
"prefix":"[5]:[0]:[32]:[192.168.101.41]",
"prefixLen":352,
@@ -65,8 +65,8 @@
]
}
},
- "192.168.102.21:2":{
- "rd":"192.168.102.21:2",
+ "65000:101":{
+ "rd":"65000:101",
"[5]:[0]:[32]:[192.168.102.21]":{
"prefix":"[5]:[0]:[32]:[192.168.102.21]",
"prefixLen":352,
diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes_all.json b/tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes_all.json
index a14ba1291e..444c67e442 100644
--- a/tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes_all.json
+++ b/tests/topotests/bgp_evpn_rt5/r1/bgp_l2vpn_evpn_routes_all.json
@@ -2,8 +2,8 @@
"bgpLocalRouterId":"192.168.100.21",
"defaultLocPrf":100,
"localAS":65000,
- "192.168.101.41:2":{
- "rd":"192.168.101.41:2",
+ "65000:201":{
+ "rd":"65000:201",
"[5]:[0]:[32]:[192.168.101.41]":{
"prefix":"[5]:[0]:[32]:[192.168.101.41]",
"prefixLen":352,
@@ -125,8 +125,8 @@
]
}
},
- "192.168.102.21:2":{
- "rd":"192.168.102.21:2",
+ "65000:101":{
+ "rd":"65000:101",
"[5]:[0]:[32]:[192.168.102.21]":{
"prefix":"[5]:[0]:[32]:[192.168.102.21]",
"prefixLen":352,
diff --git a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r1/frr.conf
index c8c4faf222..e4a8059988 100644
--- a/tests/topotests/bgp_evpn_rt5/r1/bgpd.conf
+++ b/tests/topotests/bgp_evpn_rt5/r1/frr.conf
@@ -1,15 +1,36 @@
+! debug zebra vxlan
+! debug zebra kernel
+! debug zebra dplane
+! debug zebra rib
! debug bgp neighbor-events
! debug bgp updates
! debug bgp zebra
+vrf r1-vrf-101
+ vni 101
+ exit-vrf
+!
+interface r1-eth0
+ ip address 192.168.100.21/24
+!
+interface loop101 vrf r1-vrf-101
+ ip address 192.168.102.21/32
+ ipv6 address fd00::1/128
+!
router bgp 65000
bgp router-id 192.168.100.21
bgp log-neighbor-changes
no bgp default ipv4-unicast
+ no bgp ebgp-requires-policy
neighbor 192.168.100.41 remote-as 65000
neighbor 192.168.100.41 capability extended-nexthop
+ neighbor 192.168.100.61 remote-as 65500
+ neighbor 192.168.100.61 capability extended-nexthop
!
address-family l2vpn evpn
neighbor 192.168.100.41 activate
+ neighbor 192.168.100.41 route-map rmap_r1 in
+ neighbor 192.168.100.61 activate
+ neighbor 192.168.100.61 route-map rmap_r3 in
advertise-all-vni
exit-address-family
!
@@ -24,7 +45,17 @@ router bgp 65000 vrf r1-vrf-101
network fd00::1/128
exit-address-family
address-family l2vpn evpn
+ rd 65000:101
+ route-target both 65:101
advertise ipv4 unicast
advertise ipv6 unicast
exit-address-family
!
+route-map rmap_r3 deny 1
+ match evpn vni 102
+exit
+route-map rmap_r1 permit 1
+ match evpn vni 101
+exit
+
+
diff --git a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf b/tests/topotests/bgp_evpn_rt5/r1/zebra.conf
deleted file mode 100644
index c3d508c2b6..0000000000
--- a/tests/topotests/bgp_evpn_rt5/r1/zebra.conf
+++ /dev/null
@@ -1,23 +0,0 @@
-log stdout
-
-hostname r1
-password zebra
-
-! debug zebra vxlan
-! debug zebra kernel
-! debug zebra dplane
-! debug zebra rib
-log stdout
-vrf r1-vrf-101
- vni 101
- exit-vrf
-!
-interface r1-eth0
- ip address 192.168.100.21/24
-!
-interface loop101 vrf r1-vrf-101
- ip address 192.168.102.21/32
- ipv6 address fd00::1/128
-!
-
-
diff --git a/tests/topotests/bgp_evpn_rt5/r2/bgp_l2vpn_evpn_routes.json b/tests/topotests/bgp_evpn_rt5/r2/bgp_l2vpn_evpn_routes.json
index 597bca5fd3..3a55a7a38d 100644
--- a/tests/topotests/bgp_evpn_rt5/r2/bgp_l2vpn_evpn_routes.json
+++ b/tests/topotests/bgp_evpn_rt5/r2/bgp_l2vpn_evpn_routes.json
@@ -2,8 +2,8 @@
"bgpLocalRouterId":"192.168.100.41",
"defaultLocPrf":100,
"localAS":65000,
- "192.168.101.41:2":{
- "rd":"192.168.101.41:2",
+ "65000:201":{
+ "rd":"65000:201",
"[5]:[0]:[32]:[192.168.101.41]":{
"prefix":"[5]:[0]:[32]:[192.168.101.41]",
"prefixLen":352,
@@ -63,8 +63,8 @@
]
}
},
- "192.168.102.21:2":{
- "rd":"192.168.102.21:2",
+ "65000:101":{
+ "rd":"65000:101",
"[5]:[0]:[32]:[192.168.102.21]":{
"prefix":"[5]:[0]:[32]:[192.168.102.21]",
"prefixLen":352,
diff --git a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf b/tests/topotests/bgp_evpn_rt5/r2/frr.conf
index 4f1d8e4a37..0bb4b7cab5 100644
--- a/tests/topotests/bgp_evpn_rt5/r2/bgpd.conf
+++ b/tests/topotests/bgp_evpn_rt5/r2/frr.conf
@@ -1,6 +1,19 @@
+! debug zebra vxlan
! debug bgp neighbor-events
! debug bgp updates
! debug bgp zebra
+
+vrf r2-vrf-101
+ vni 101
+ exit-vrf
+!
+interface loop101 vrf r2-vrf-101
+ ip address 192.168.101.41/32
+ ipv6 address fd00::2/128
+!
+interface r2-eth0
+ ip address 192.168.100.41/24
+!
router bgp 65000
bgp router-id 192.168.100.41
bgp log-neighbor-changes
@@ -27,6 +40,8 @@ router bgp 65000 vrf r2-vrf-101
network fd00::3/128
exit-address-family
address-family l2vpn evpn
+ rd 65000:201
+ route-target both 65:101
advertise ipv4 unicast route-map rmap4
advertise ipv6 unicast route-map rmap6
exit-address-family
@@ -47,3 +62,4 @@ exit
route-map rmap6 deny 2
match ipv6 address acl6_2
exit
+
diff --git a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf b/tests/topotests/bgp_evpn_rt5/r2/zebra.conf
deleted file mode 100644
index 7db40cb59c..0000000000
--- a/tests/topotests/bgp_evpn_rt5/r2/zebra.conf
+++ /dev/null
@@ -1,19 +0,0 @@
-log stdout
-
-hostname r2
-password zebra
-
-! debug zebra vxlan
-
-vrf r2-vrf-101
- vni 101
- exit-vrf
-!
-interface loop101 vrf r2-vrf-101
- ip address 192.168.101.41/32
- ipv6 address fd00::2/128
-!
-interface r2-eth0
- ip address 192.168.100.41/24
-!
-
diff --git a/tests/topotests/bgp_evpn_rt5/r3/frr.conf b/tests/topotests/bgp_evpn_rt5/r3/frr.conf
new file mode 100644
index 0000000000..3f3851bd8c
--- /dev/null
+++ b/tests/topotests/bgp_evpn_rt5/r3/frr.conf
@@ -0,0 +1,46 @@
+! debug bgp neighbor-events
+! debug bgp updates
+! debug bgp zebra
+vrf r3-vrf-102
+ vni 102
+ exit-vrf
+!
+interface r3-eth0
+ ip address 192.168.100.61/24
+!
+interface loop102 vrf r3-vrf-102
+ ip address 192.168.102.61/32
+ ipv6 address fd00:6::1/128
+!
+router bgp 65500
+ bgp router-id 192.168.100.61
+ bgp log-neighbor-changes
+ no bgp default ipv4-unicast
+ no bgp ebgp-requires-policy
+ neighbor 192.168.100.21 remote-as 65000
+ neighbor 192.168.100.21 capability extended-nexthop
+ !
+ address-family l2vpn evpn
+ neighbor 192.168.100.21 activate
+ advertise-all-vni
+ exit-address-family
+!
+router bgp 65000 vrf r3-vrf-102
+ bgp router-id 192.168.100.61
+ bgp log-neighbor-changes
+ no bgp network import-check
+ address-family ipv4 unicast
+ network 192.168.102.102/32
+ exit-address-family
+ address-family ipv6 unicast
+ network fd00:102::1/128
+ exit-address-family
+ address-family l2vpn evpn
+ rd 65000:302
+ route-target both 65:101
+ advertise ipv4 unicast
+ advertise ipv6 unicast
+ exit-address-family
+ !
+
+
diff --git a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
index c874cbed66..2b8355af09 100644
--- a/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
+++ b/tests/topotests/bgp_evpn_rt5/test_bgp_evpn.py
@@ -42,10 +42,12 @@ def build_topo(tgen):
tgen.add_router("r1")
tgen.add_router("r2")
+ tgen.add_router("r3")
switch = tgen.add_switch("s1")
switch.add_link(tgen.gears["r1"])
switch.add_link(tgen.gears["r2"])
+ switch.add_link(tgen.gears["r3"])
switch = tgen.add_switch("s2")
switch.add_link(tgen.gears["r1"])
@@ -53,6 +55,9 @@ def build_topo(tgen):
switch = tgen.add_switch("s3")
switch.add_link(tgen.gears["r2"])
+ switch = tgen.add_switch("s4")
+ switch.add_link(tgen.gears["r3"])
+
def setup_module(mod):
"Sets up the pytest environment"
@@ -71,16 +76,16 @@ def setup_module(mod):
)
return pytest.skip("Skipping BGP EVPN RT5 NETNS Test. Kernel not supported")
- # create VRF vrf-101 on R1 and R2
+ # create VRF vrf-101 on R1, R2, R3
# create loop101
cmds_vrflite = [
- "ip link add {}-vrf-101 type vrf table 101",
- "ip ru add oif {}-vrf-101 table 101",
- "ip ru add iif {}-vrf-101 table 101",
- "ip link set dev {}-vrf-101 up",
- "ip link add loop101 type dummy",
- "ip link set dev loop101 master {}-vrf-101",
- "ip link set dev loop101 up",
+ "ip link add {0}-vrf-{1} type vrf table {1}",
+ "ip ru add oif {0}-vrf-{1} table {1}",
+ "ip ru add iif {0}-vrf-{1} table {1}",
+ "ip link set dev {0}-vrf-{1} up",
+ "ip link add loop{1} type dummy",
+ "ip link set dev loop{1} master {0}-vrf-{1}",
+ "ip link set dev loop{1} up",
]
cmds_r2 = [ # config routing 101
@@ -92,6 +97,15 @@ def setup_module(mod):
"ip link set vxlan-101 up type bridge_slave learning off flood off mcast_flood off",
]
+ cmds_r3 = [ # config routing 102
+ "ip link add name bridge-102 up type bridge stp_state 0",
+ "ip link set bridge-102 master {}-vrf-102",
+ "ip link set dev bridge-102 up",
+ "ip link add name vxlan-102 type vxlan id 102 dstport 4789 dev r3-eth0 local 192.168.100.61",
+ "ip link set dev vxlan-102 master bridge-102",
+ "ip link set vxlan-102 up type bridge_slave learning off flood off mcast_flood off",
+ ]
+
# cmds_r1_netns_method3 = [
# "ip link add name vxlan-{1} type vxlan id {1} dstport 4789 dev {0}-eth0 local 192.168.100.21",
# "ip link set dev vxlan-{1} netns {0}-vrf-{1}",
@@ -111,8 +125,8 @@ def setup_module(mod):
router = tgen.gears["r2"]
for cmd in cmds_vrflite:
- logger.info("cmd to r2: " + cmd.format("r2"))
- output = router.cmd_raises(cmd.format("r2"))
+ logger.info("cmd to r2: " + cmd.format("r2", 101))
+ output = router.cmd_raises(cmd.format("r2", 101))
logger.info("result: " + output)
for cmd in cmds_r2:
@@ -120,6 +134,17 @@ def setup_module(mod):
output = router.cmd_raises(cmd.format("r2"))
logger.info("result: " + output)
+ router = tgen.gears["r3"]
+ for cmd in cmds_vrflite:
+ logger.info("cmd to r3: " + cmd.format("r3", 102))
+ output = router.cmd_raises(cmd.format("r3", 102))
+ logger.info("result: " + output)
+
+ for cmd in cmds_r3:
+ logger.info("cmd to r3: " + cmd.format("r3"))
+ output = router.cmd_raises(cmd.format("r3"))
+ logger.info("result: " + output)
+
tgen.net["r1"].cmd_raises(
"ip link add name vxlan-101 type vxlan id 101 dstport 4789 dev r1-eth0 local 192.168.100.21"
)
@@ -134,19 +159,13 @@ def setup_module(mod):
tgen.net["r1"].cmd_raises("ip -n r1-vrf-101 link set bridge-101 up")
tgen.net["r1"].cmd_raises("ip -n r1-vrf-101 link set vxlan-101 up")
- for rname, router in router_list.items():
+ for rname, router in tgen.routers().items():
+ logger.info("Loading router %s" % rname)
if rname == "r1":
router.use_netns_vrf()
- router.load_config(
- TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
- )
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
else:
- 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_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
# Initialize all routers.
tgen.start_router()
diff --git a/tests/topotests/bgp_peer_solo/r1/frr.conf b/tests/topotests/bgp_peer_solo/r1/frr.conf
new file mode 100644
index 0000000000..6ef3688b83
--- /dev/null
+++ b/tests/topotests/bgp_peer_solo/r1/frr.conf
@@ -0,0 +1,10 @@
+!
+int r1-eth0
+ ip address 10.255.0.1/24
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 10.255.0.2 timers 1 3
+ neighbor 10.255.0.2 timers connect 1
+ neighbor 10.255.0.2 remote-as external
+!
diff --git a/tests/topotests/bgp_peer_solo/r2/frr.conf b/tests/topotests/bgp_peer_solo/r2/frr.conf
new file mode 100644
index 0000000000..c58e327418
--- /dev/null
+++ b/tests/topotests/bgp_peer_solo/r2/frr.conf
@@ -0,0 +1,14 @@
+!
+int r2-eth0
+ ip address 10.255.0.2/24
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 10.255.0.1 remote-as external
+ neighbor 10.255.0.1 timers 1 3
+ neighbor 10.255.0.1 timers connect 1
+ address-family ipv4 unicast
+ network 10.0.0.1/32
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_peer_solo/test_bgp_peer_solo.py b/tests/topotests/bgp_peer_solo/test_bgp_peer_solo.py
new file mode 100644
index 0000000000..6bd2430aea
--- /dev/null
+++ b/tests/topotests/bgp_peer_solo/test_bgp_peer_solo.py
@@ -0,0 +1,131 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+import os
+import re
+import sys
+import json
+import pytest
+import functools
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+from lib import topotest
+from lib.topogen import Topogen, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for _, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_frr_config(os.path.join(CWD, "{}/frr.conf".format(rname)))
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_peer_solo():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ r1 = tgen.gears["r1"]
+
+ def _bgp_converge():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 unicast summary json"))
+ print("output=", output)
+ expected = {
+ "peers": {
+ "10.255.0.2": {
+ "remoteAs": 65002,
+ "state": "Established",
+ "peerState": "OK",
+ },
+ },
+ "totalPeers": 1,
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_converge,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=30, wait=1)
+ assert result is None, "Can't converge initial state"
+
+ def _bgp_advertised():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 neighbors 10.255.0.2 advertised-routes json"))
+ print("output adv=", output)
+ expected = {
+ "advertisedRoutes": {
+ "10.0.0.1/32": {},
+ },
+ "totalPrefixCounter": 1,
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_advertised,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assert result is None, "Should contain an advertised route"
+
+ #
+ # Apply solo option
+ #
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65001
+ neighbor 10.255.0.2 solo
+ """
+ )
+
+ def _bgp_no_advertised():
+ output = json.loads(r1.vtysh_cmd("show bgp ipv4 neighbors 10.255.0.2 advertised-routes json"))
+ expected = {
+ "totalPrefixCounter": 0,
+ }
+
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(
+ _bgp_no_advertised,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assert result is None, "Shouldn't contain advertised routes"
+
+ #
+ # Unset solo option
+ #
+ r1.vtysh_cmd(
+ """
+ configure terminal
+ router bgp 65001
+ no neighbor 10.255.0.2 solo
+ """
+ )
+
+ test_func = functools.partial(
+ _bgp_advertised,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assert result is None, "Should contain an advertised route"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_table_direct_topo1/__init__.py b/tests/topotests/bgp_table_direct_topo1/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_table_direct_topo1/__init__.py
diff --git a/tests/topotests/bgp_table_direct_topo1/r1/frr.conf b/tests/topotests/bgp_table_direct_topo1/r1/frr.conf
new file mode 100644
index 0000000000..c45e3456a4
--- /dev/null
+++ b/tests/topotests/bgp_table_direct_topo1/r1/frr.conf
@@ -0,0 +1,31 @@
+log commands
+!
+debug bgp zebra
+debug zebra events
+!
+ip route 10.254.254.1/32 lo table 2000
+ip route 10.254.254.2/32 lo table 2000
+ip route 10.254.254.3/32 lo table 2000
+!
+interface r1-eth0
+ ip address 192.168.10.1/24
+!
+interface r1-eth1 vrf blue
+ ip address 192.168.20.1/24
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.10.2 remote-as external
+ address-family ipv4 unicast
+ redistribute table-direct 2000
+ exit-address-family
+!
+router bgp 65001 vrf blue
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.20.2 remote-as external
+ address-family ipv4 unicast
+ redistribute table-direct 2000
+ exit-address-family
+! \ No newline at end of file
diff --git a/tests/topotests/bgp_table_direct_topo1/r2/frr.conf b/tests/topotests/bgp_table_direct_topo1/r2/frr.conf
new file mode 100644
index 0000000000..04787be0b3
--- /dev/null
+++ b/tests/topotests/bgp_table_direct_topo1/r2/frr.conf
@@ -0,0 +1,10 @@
+log commands
+!
+interface r2-eth0
+ ip address 192.168.10.2/24
+!
+router bgp 65002
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.10.1 remote-as external
+! \ No newline at end of file
diff --git a/tests/topotests/bgp_table_direct_topo1/r3/frr.conf b/tests/topotests/bgp_table_direct_topo1/r3/frr.conf
new file mode 100644
index 0000000000..2530b28bfd
--- /dev/null
+++ b/tests/topotests/bgp_table_direct_topo1/r3/frr.conf
@@ -0,0 +1,10 @@
+log commands
+!
+interface r3-eth0
+ ip address 192.168.20.2/24
+!
+router bgp 65003
+ no bgp ebgp-requires-policy
+ no bgp network import-check
+ neighbor 192.168.20.1 remote-as external
+! \ No newline at end of file
diff --git a/tests/topotests/bgp_table_direct_topo1/test_bgp_table_direct_topo1.py b/tests/topotests/bgp_table_direct_topo1/test_bgp_table_direct_topo1.py
new file mode 100644
index 0000000000..70257be3e7
--- /dev/null
+++ b/tests/topotests/bgp_table_direct_topo1/test_bgp_table_direct_topo1.py
@@ -0,0 +1,201 @@
+#!/usr/bin/env python
+# SPDX-License-Identifier: ISC
+
+#
+# test_bgp_table_direct_topo1.py
+# Part of NetDEF Topology Tests
+#
+# Copyright (c) 2025 by
+# Network Device Education Foundation, Inc. ("NetDEF")
+#
+
+"""
+test_bgp_table_direct_topo1.py: Test the FRR PIM MSDP peer.
+"""
+
+import os
+import sys
+import json
+from functools import partial
+import re
+import pytest
+
+# Save the Current Working Directory to find configuration files.
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+# Import topogen and topotest helpers
+from lib import topotest
+
+# Required to instantiate the topology builder class.
+from lib.topogen import Topogen, TopoRouter, get_topogen
+from lib.topolog import logger
+
+from lib.pim import McastTesterHelper
+
+pytestmark = [pytest.mark.bgpd, pytest.mark.pimd]
+
+app_helper = McastTesterHelper()
+
+
+def build_topo(tgen):
+ """
+ +----+ +----+
+ | r1 | <-> | r2 |
+ +----+ +----+
+ |
+ | +----+
+ --------| r3 |
+ +----+
+ """
+
+ # Create 3 routers
+ for routern in range(1, 4):
+ tgen.add_router(f"r{routern}")
+
+ switch = tgen.add_switch("s1")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r2"])
+
+ switch = tgen.add_switch("s2")
+ switch.add_link(tgen.gears["r1"])
+ switch.add_link(tgen.gears["r3"])
+
+
+def setup_module(mod):
+ "Sets up the pytest environment"
+ tgen = Topogen(build_topo, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+ for _, router in router_list.items():
+ router.load_frr_config(os.path.join(CWD, f"{router.name}/frr.conf"))
+
+ tgen.gears["r1"].run("ip link add blue type vrf table 10")
+ tgen.gears["r1"].run("ip link set blue up")
+ tgen.gears["r1"].run("ip link set r1-eth1 master blue")
+
+ # Initialize all routers.
+ tgen.start_router()
+
+ app_helper.init(tgen)
+
+
+def teardown_module():
+ "Teardown the pytest environment"
+ tgen = get_topogen()
+ app_helper.cleanup()
+ tgen.stop_topology()
+
+
+def expect_bgp_route(router, iptype, route, missing=False):
+ "Wait until route is present on RIB for protocol."
+ if missing:
+ logger.info("waiting route {} go missing in {}".format(route, router))
+ else:
+ logger.info("waiting route {} in {}".format(route, router))
+
+ tgen = get_topogen()
+ expected_output = {route: [{"protocol": "bgp"}]}
+ wait_time = 130
+ if missing:
+ expected_output = {route: None}
+ wait_time = 5
+
+ test_func = partial(
+ topotest.router_json_cmp,
+ tgen.gears[router],
+ "show {} route json".format(iptype),
+ expected_output
+ )
+
+ _, result = topotest.run_and_expect(test_func, None, count=130, wait=1)
+ assertmsg = f'"{router}" convergence failure'
+ assert result is None, assertmsg
+
+
+def test_bgp_convergence():
+ "Wait for BGP protocol convergence"
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ logger.info("waiting for protocols to converge")
+
+ # Wait for R2
+ expect_bgp_route("r2", "ip", "10.254.254.1/32")
+ expect_bgp_route("r2", "ip", "10.254.254.2/32")
+ expect_bgp_route("r2", "ip", "10.254.254.3/32")
+
+ # Wait for R3
+ expect_bgp_route("r3", "ip", "10.254.254.1/32")
+ expect_bgp_route("r3", "ip", "10.254.254.2/32")
+ expect_bgp_route("r3", "ip", "10.254.254.3/32")
+
+
+def test_route_change_convergence():
+ "Change routes in table 2000 to test zebra redistribution."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.gears["r1"].vtysh_cmd("""
+ configure terminal
+ no ip route 10.254.254.2/32 lo table 2000
+ ip route 10.254.254.10/32 lo table 2000
+ """)
+
+ # Check R2
+ expect_bgp_route("r2", "ip", "10.254.254.2/32", missing=True)
+ expect_bgp_route("r2", "ip", "10.254.254.10/32")
+
+ # Check R3
+ expect_bgp_route("r3", "ip", "10.254.254.2/32", missing=True)
+ expect_bgp_route("r3", "ip", "10.254.254.10/32")
+
+
+def test_configuration_removal_convergence():
+ "Remove table direct configuration and check if routes went missing."
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ tgen.gears["r1"].vtysh_cmd("""
+ configure terminal
+ router bgp 65001
+ address-family ipv4 unicast
+ no redistribute table-direct 2000
+ exit-address-family
+ exit
+
+ router bgp 65001 vrf blue
+ address-family ipv4 unicast
+ no redistribute table-direct 2000
+ exit-address-family
+ exit
+ """)
+
+ # Check R2
+ expect_bgp_route("r2", "ip", "10.254.254.1/32", missing=True)
+ expect_bgp_route("r2", "ip", "10.254.254.3/32", missing=True)
+ expect_bgp_route("r2", "ip", "10.254.254.10/32", missing=True)
+
+ # Check R3
+ expect_bgp_route("r3", "ip", "10.254.254.1/32", missing=True)
+ expect_bgp_route("r3", "ip", "10.254.254.3/32", missing=True)
+ expect_bgp_route("r3", "ip", "10.254.254.10/32", missing=True)
+
+
+def test_memory_leak():
+ "Run the memory leak test and report results."
+ tgen = get_topogen()
+ if not tgen.is_memleak_enabled():
+ pytest.skip("Memory leak test/report is disabled")
+
+ tgen.report_memory_leaks()
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))
diff --git a/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes_advertised_10_125_0_2.json b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes_advertised_10_125_0_2.json
new file mode 100644
index 0000000000..7891982653
--- /dev/null
+++ b/tests/topotests/bgp_vpnv4_noretain/r1/ipv4_vpn_routes_advertised_10_125_0_2.json
@@ -0,0 +1,105 @@
+{
+ "bgpLocalRouterId":"192.0.2.1",
+ "defaultLocPrf":100,
+ "localAS":65500,
+ "advertisedRoutes":{
+ "192.0.2.1:1":{
+ "rd":"192.0.2.1:1",
+ "10.101.0.0/24":{
+ "prefix":"10.101.0.0/24",
+ "advertisedTo":{
+ "10.125.0.2":{
+ "hostname":"r2"
+ }
+ },
+ "paths":[{
+ "aspath":{
+ "string":"Local",
+ "segments":[],
+ "length":0
+ },
+ "nhVrfName":"vrf1",
+ "announceNexthopSelf":true,
+ "origin":"incomplete",
+ "metric":0,
+ "locPrf":100,
+ "weight":32768,
+ "valid":true,
+ "sourced":true,
+ "local":true,
+ "bestpath":{
+ "overall":true,
+ "selectionReason":"First path received"
+ },
+ "extendedCommunity":{
+ "string":"RT:192.0.2.1:100"
+ },
+ "originatorId":"192.0.2.1",
+ "remoteLabel":101,
+ "nexthops":[{
+ "ip":"0.0.0.0",
+ "hostname":"r1",
+ "afi":"ipv4",
+ "metric":0,
+ "accessible":true,
+ "used":true
+ }],
+ "peer":{
+ "peerId":"0.0.0.0",
+ "routerId":"192.0.2.1"
+ }
+ }]
+ }
+ },
+ "192.0.2.1:3":{
+ "rd":"192.0.2.1:3",
+ "10.103.0.0/24":{
+ "prefix":"10.103.0.0/24",
+ "advertisedTo":{
+ "10.125.0.2":{
+ "hostname":"r2"
+ }
+ },
+ "paths":[{
+ "aspath":{
+ "string":"Local",
+ "segments":[],
+ "length":0
+ },
+ "nhVrfName":"vrf3",
+ "announceNexthopSelf":true,
+ "origin":"incomplete",
+ "metric":0,
+ "locPrf":100,
+ "weight":32768,
+ "valid":true,
+ "sourced":true,
+ "local":true,
+ "bestpath":{
+ "overall":true,
+ "selectionReason":"First path received"
+ },
+ "extendedCommunity":{
+ "string":"RT:192.0.2.1:300"
+ },
+ "originatorId":"192.0.2.1",
+ "remoteLabel":103,
+ "nexthops":[{
+ "ip":"0.0.0.0",
+ "hostname":"r1",
+ "afi":"ipv4",
+ "metric":0,
+ "accessible":true,
+ "used":true
+ }],
+ "peer":{
+ "peerId":"0.0.0.0",
+ "routerId":"192.0.2.1"
+ }
+ }]
+ }
+ }
+ },
+ "totalPrefixCounter":2,
+ "filteredPrefixCounter":0
+}
diff --git a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py
index ee84e375fb..ada37c28c1 100644
--- a/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py
+++ b/tests/topotests/bgp_vpnv4_noretain/test_bgp_vpnv4_noretain.py
@@ -218,6 +218,29 @@ def check_show_bgp_ipv4_vpn(rname, json_file):
assert result is None, assertmsg
+def check_show_bgp_ipv4_vpn_peer_advertised_routes(rname, peer, json_file):
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+ router = tgen.gears[rname]
+
+ logger.info(
+ "Checking VPNv4 advertised routes for on {} for peer {}".format(rname, peer)
+ )
+
+ json_file = "{}/{}/{}".format(CWD, router.name, json_file)
+ expected = json.loads(open(json_file).read())
+ test_func = partial(
+ topotest.router_json_cmp,
+ router,
+ "show bgp ipv4 vpn neighbors {} advertised-routes detail json".format(peer),
+ expected,
+ )
+ _, result = topotest.run_and_expect(test_func, None, count=20, wait=1)
+ assertmsg = '"{}" JSON output mismatches'.format(router.name)
+ assert result is None, assertmsg
+
+
def check_show_bgp_vrf_ipv4(rname, json_file):
tgen = get_topogen()
if tgen.routers_have_failure():
@@ -563,6 +586,21 @@ router bgp 65500
check_show_bgp_vrf_ipv4(rname, "ipv4_vrf_all_routes_init.json")
+def test_bgp_advertised_routes_step13():
+ """
+ Dump advertised routes from r1 to r2
+ Check that the localpref attribute is set on the show command
+ """
+
+ tgen = get_topogen()
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ check_show_bgp_ipv4_vpn_peer_advertised_routes(
+ "r1", "10.125.0.2", "ipv4_vpn_routes_advertised_10_125_0_2.json"
+ )
+
+
def test_memory_leak():
"Run the memory leak test and report results."
tgen = get_topogen()
diff --git a/zebra/redistribute.c b/zebra/redistribute.c
index 66dc5b4b5f..9bf7e2cbb5 100644
--- a/zebra/redistribute.c
+++ b/zebra/redistribute.c
@@ -82,8 +82,8 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id)
RNODE_FOREACH_RE (rn, newre) {
if (CHECK_FLAG(newre->flags, ZEBRA_FLAG_SELECTED))
- zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
- client, rn, newre, false);
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, rn,
+ newre, NULL);
}
route_unlock_node(rn);
@@ -91,6 +91,24 @@ static void zebra_redistribute_default(struct zserv *client, vrf_id_t vrf_id)
}
/* Redistribute routes. */
+static void redistribute_table_direct(struct zserv *client, int type, const struct route_node *rn,
+ const struct route_entry *re)
+{
+ struct redist_table_direct *table;
+ struct redist_proto *red;
+ struct listnode *node;
+ afi_t afi = family2afi(rn->p.family);
+
+ red = &client->mi_redist[afi][ZEBRA_ROUTE_TABLE_DIRECT];
+
+ for (ALL_LIST_ELEMENTS_RO(red->instances, node, table)) {
+ if (table->table_id != (int)re->table)
+ continue;
+
+ zsend_redistribute_route(type, client, rn, re, &table->vrf_id);
+ }
+}
+
static void zebra_redistribute(struct zserv *client, int type,
unsigned short instance, struct zebra_vrf *zvrf,
int afi)
@@ -102,13 +120,9 @@ static void zebra_redistribute(struct zserv *client, int type,
vrf_id_t vrf_id = zvrf_id(zvrf);
if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
- if (vrf_id == VRF_DEFAULT) {
- table = zebra_router_find_table(zvrf, instance, afi,
- SAFI_UNICAST);
- type = ZEBRA_ROUTE_ALL;
- is_table_direct = true;
- } else
- return;
+ table = zebra_router_find_table(zvrf, instance, afi, SAFI_UNICAST);
+ type = ZEBRA_ROUTE_ALL;
+ is_table_direct = true;
} else
table = zebra_vrf_table(afi, SAFI_UNICAST, vrf_id);
@@ -140,15 +154,20 @@ static void zebra_redistribute(struct zserv *client, int type,
if (!zebra_check_addr(&rn->p))
continue;
- zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
- client, rn, newre, is_table_direct);
+ if (is_table_direct)
+ redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_ADD, rn,
+ newre);
+ else
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, rn,
+ newre, NULL);
}
}
/*
- * Function to return a valid table id value if table-direct is used
- * return 0 otherwise
- * This function can be called only if zebra_redistribute_check returns TRUE
+ * Checks if the route entry can be used as table-direct or not.
+ * `table-direct` routes always belong to `VRF_DEFAULT` and has an table
+ * ID different than the VRF it belongs (example main VRF table is 254,
+ * so in order to be `table-direct` the route's table ID must be != 254).
*/
static bool zebra_redistribute_is_table_direct(const struct route_entry *re)
{
@@ -177,15 +196,14 @@ static bool zebra_redistribute_check(const struct route_node *rn,
afi = family2afi(rn->p.family);
zvrf = zebra_vrf_lookup_by_id(re->vrf_id);
- if (re->vrf_id == VRF_DEFAULT && zvrf->table_id != re->table) {
+ if (zvrf->table_id != re->table) {
+ /*
+ * Routes with table ID different from VRFs can be used as
+ * `table-direct` if enabled.
+ */
if (re->table &&
- redist_check_instance(&client->mi_redist
- [afi][ZEBRA_ROUTE_TABLE_DIRECT],
- re->table)) {
- /* table-direct redistribution only for route entries which
- * are on the default vrf, and that have table id different
- * from the default table.
- */
+ redist_table_direct_has_id(&client->mi_redist[afi][ZEBRA_ROUTE_TABLE_DIRECT],
+ re->table)) {
return true;
}
return false;
@@ -227,7 +245,6 @@ void redistribute_update(const struct route_node *rn,
{
struct listnode *node, *nnode;
struct zserv *client;
- bool is_table_direct;
if (IS_ZEBRA_DEBUG_RIB)
zlog_debug(
@@ -242,7 +259,6 @@ void redistribute_update(const struct route_node *rn,
return;
}
-
for (ALL_LIST_ELEMENTS(zrouter.client_list, node, nnode, client)) {
if (zebra_redistribute_check(rn, re, client)) {
if (IS_ZEBRA_DEBUG_RIB) {
@@ -253,15 +269,19 @@ void redistribute_update(const struct route_node *rn,
re->vrf_id, re->table, re->type,
re->distance, re->metric);
}
- is_table_direct = zebra_redistribute_is_table_direct(re);
- zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD,
- client, rn, re,
- is_table_direct);
+ if (zebra_redistribute_is_table_direct(re))
+ redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_ADD, rn,
+ re);
+ else
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_ADD, client, rn,
+ re, NULL);
} else if (zebra_redistribute_check(rn, prev_re, client)) {
- is_table_direct = zebra_redistribute_is_table_direct(prev_re);
- zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
- client, rn, prev_re,
- is_table_direct);
+ if (zebra_redistribute_is_table_direct(prev_re))
+ redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_DEL, rn,
+ prev_re);
+ else
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, client, rn,
+ prev_re, NULL);
}
}
}
@@ -281,7 +301,6 @@ void redistribute_delete(const struct route_node *rn,
struct listnode *node, *nnode;
struct zserv *client;
vrf_id_t vrfid;
- bool is_table_direct;
if (old_re)
vrfid = old_re->vrf_id;
@@ -344,10 +363,12 @@ void redistribute_delete(const struct route_node *rn,
* happy.
*/
assert(old_re);
- is_table_direct = zebra_redistribute_is_table_direct(old_re);
- zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL,
- client, rn, old_re,
- is_table_direct);
+ if (zebra_redistribute_is_table_direct(old_re))
+ redistribute_table_direct(client, ZEBRA_REDISTRIBUTE_ROUTE_DEL, rn,
+ old_re);
+ else
+ zsend_redistribute_route(ZEBRA_REDISTRIBUTE_ROUTE_DEL, client, rn,
+ old_re, NULL);
}
}
}
@@ -383,8 +404,16 @@ void zebra_redistribute_add(ZAPI_HANDLER_ARGS)
}
if (instance) {
- if (!redist_check_instance(&client->mi_redist[afi][type],
- instance)) {
+ if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
+ struct redist_table_direct table = {
+ .vrf_id = zvrf->vrf->vrf_id,
+ .table_id = instance,
+ };
+ if (!redist_lookup_table_direct(&client->mi_redist[afi][type], &table)) {
+ redist_add_table_direct(&client->mi_redist[afi][type], &table);
+ zebra_redistribute(client, type, instance, zvrf, afi);
+ }
+ } else if (!redist_check_instance(&client->mi_redist[afi][type], instance)) {
redist_add_instance(&client->mi_redist[afi][type],
instance);
zebra_redistribute(client, type, instance, zvrf, afi);
@@ -443,7 +472,13 @@ void zebra_redistribute_delete(ZAPI_HANDLER_ARGS)
* themselves should keep track of the received routes from zebra and
* withdraw them when necessary.
*/
- if (instance)
+ if (type == ZEBRA_ROUTE_TABLE_DIRECT) {
+ struct redist_table_direct table = {
+ .vrf_id = zvrf->vrf->vrf_id,
+ .table_id = instance,
+ };
+ redist_del_table_direct(&client->mi_redist[afi][type], &table);
+ } else if (instance)
redist_del_instance(&client->mi_redist[afi][type], instance);
else
vrf_bitmap_unset(&client->redist[afi][type], zvrf_id(zvrf));
diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c
index ab55998af0..f32d8ea6c6 100644
--- a/zebra/zapi_msg.c
+++ b/zebra/zapi_msg.c
@@ -509,9 +509,8 @@ int zsend_interface_update(int cmd, struct zserv *client, struct interface *ifp)
return zserv_send_message(client, s);
}
-int zsend_redistribute_route(int cmd, struct zserv *client,
- const struct route_node *rn,
- const struct route_entry *re, bool is_table_direct)
+int zsend_redistribute_route(int cmd, struct zserv *client, const struct route_node *rn,
+ const struct route_entry *re, vrf_id_t *to_vrf)
{
struct zapi_route api;
struct zapi_nexthop *api_nh;
@@ -527,9 +526,10 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
api.vrf_id = re->vrf_id;
api.type = re->type;
api.safi = SAFI_UNICAST;
- if (is_table_direct) {
+ if (to_vrf != NULL) {
api.instance = re->table;
api.type = ZEBRA_ROUTE_TABLE_DIRECT;
+ api.vrf_id = *to_vrf;
} else
api.instance = re->instance;
api.flags = re->flags;
@@ -598,7 +598,7 @@ int zsend_redistribute_route(int cmd, struct zserv *client,
/* Attributes. */
SET_FLAG(api.message, ZAPI_MESSAGE_DISTANCE);
- if (is_table_direct)
+ if (to_vrf != NULL)
api.distance = ZEBRA_TABLEDIRECT_DISTANCE_DEFAULT;
else
api.distance = re->distance;
diff --git a/zebra/zapi_msg.h b/zebra/zapi_msg.h
index a59ccc838b..29a5b69f18 100644
--- a/zebra/zapi_msg.h
+++ b/zebra/zapi_msg.h
@@ -51,10 +51,8 @@ extern void nbr_connected_delete_ipv6(struct interface *ifp,
struct in6_addr *address);
extern int zsend_interface_update(int cmd, struct zserv *client,
struct interface *ifp);
-extern int zsend_redistribute_route(int cmd, struct zserv *zclient,
- const struct route_node *rn,
- const struct route_entry *re,
- bool is_table_direct);
+extern int zsend_redistribute_route(int cmd, struct zserv *zclient, const struct route_node *rn,
+ const struct route_entry *re, vrf_id_t *to_vrf);
extern int zsend_router_id_update(struct zserv *zclient, afi_t afi,
struct prefix *p, vrf_id_t vrf_id);
diff --git a/zebra/zebra_vty.c b/zebra/zebra_vty.c
index 582d15627c..a1731712d3 100644
--- a/zebra/zebra_vty.c
+++ b/zebra/zebra_vty.c
@@ -1789,9 +1789,24 @@ DEFPY (show_route_detail,
rib_dest_t *dest;
bool network_found = false;
bool show_ng = !!ng;
+ int idx = 0;
+
+ /*
+ * Return error if V6 address/prefix is passed as an argument to
+ * "show ip route" cmd.
+ *
+ * When "show ip route <X:X::X:X|X:X::X:X/M>" is queried,
+ * argv[idx]->text will be set to "ipv6" but argv[idx]->arg will be set
+ * to "ip".
+ */
+ if (argv_find(argv, argc, "ipv6", &idx) && !strcmp(argv[idx]->arg, "ip")) {
+ vty_out(vty, "%% Cannot specify IPv6 address/prefix for IPv4 table\n");
+ return CMD_WARNING;
+ }
if (address_str)
prefix_str = address_str;
+
if (str2prefix(prefix_str, &p) < 0) {
vty_out(vty, "%% Malformed address\n");
return CMD_WARNING;