diff options
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); |
