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_fsm.c3
-rw-r--r--bgpd/bgp_packet.c186
-rw-r--r--bgpd/bgp_route.c10
-rw-r--r--bgpd/bgp_vty.c71
-rw-r--r--bgpd/bgp_zebra.c51
-rw-r--r--bgpd/bgpd.c72
-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_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_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
26 files changed, 841 insertions, 502 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_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_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 672c43b37c..f2e61e1e7f 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -10951,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) {
@@ -15239,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);
@@ -15253,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_vty.c b/bgpd/bgp_vty.c
index 2b3e11929b..046b18f224 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -9206,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,
@@ -9235,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,
@@ -9261,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;
}
@@ -9289,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;
}
@@ -17598,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;
@@ -17657,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;
@@ -17720,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;
@@ -17790,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;
@@ -17865,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) {
@@ -17934,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 d5463f3d0c..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);
@@ -4820,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/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_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_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);