diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index a7cd3fee88..10e78cbc96 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -520,6 +520,7 @@ unsigned int attrhash_key_make(const void *p) key = jhash(attr->mp_nexthop_global.s6_addr, IPV6_MAX_BYTELEN, key); key = jhash(attr->mp_nexthop_local.s6_addr, IPV6_MAX_BYTELEN, key); MIX3(attr->nh_ifindex, attr->nh_lla_ifindex, attr->distance); + MIX(attr->rmap_table_id); return key; } @@ -546,6 +547,7 @@ bool attrhash_cmp(const void *p1, const void *p2) && attr1->lcommunity == attr2->lcommunity && attr1->cluster == attr2->cluster && attr1->transit == attr2->transit + && attr1->rmap_table_id == attr2->rmap_table_id && (attr1->encap_tunneltype == attr2->encap_tunneltype) && encap_same(attr1->encap_subtlvs, attr2->encap_subtlvs) #if ENABLE_BGP_VNC diff --git a/bgpd/bgp_attr.h b/bgpd/bgp_attr.h index cfa428a796..eacd37b652 100644 --- a/bgpd/bgp_attr.h +++ b/bgpd/bgp_attr.h @@ -209,6 +209,9 @@ struct attr { /* Distance as applied by Route map */ uint8_t distance; + + /* rmap set table */ + uint32_t rmap_table_id; }; /* rmap_change_flags definition */ diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c index f0629fca08..3f30441f7b 100644 --- a/bgpd/bgp_route.c +++ b/bgpd/bgp_route.c @@ -3165,6 +3165,13 @@ int bgp_update(struct peer *peer, struct prefix *p, uint32_t addpath_id, goto filtered; } + if (pi && pi->attr && + pi->attr->rmap_table_id != new_attr.rmap_table_id) { + if (CHECK_FLAG(pi->flags, BGP_PATH_SELECTED)) + /* remove from RIB previous entry */ + bgp_zebra_withdraw(p, pi, bgp, safi); + } + if (peer->sort == BGP_PEER_EBGP) { /* If we receive the graceful-shutdown community from an eBGP diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index a5286cea69..a038b0e7a9 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -114,6 +114,7 @@ o Cisco route-map origin : Done tag : Done weight : Done + table : Done o Local extensions @@ -1754,6 +1755,32 @@ struct route_map_rule_cmd route_set_metric_cmd = { "metric", route_set_metric, route_value_compile, route_value_free, }; +/* `set table (1-4294967295)' */ + +static enum route_map_cmd_result_t route_set_table_id(void *rule, + const struct prefix *prefix, + route_map_object_t type, + void *object) +{ + struct rmap_value *rv; + struct bgp_path_info *path; + + if (type == RMAP_BGP) { + /* Fetch routemap's rule information. */ + rv = rule; + path = object; + + path->attr->rmap_table_id = rv->value; + } + return RMAP_OKAY; +} + +/* Set table_id rule structure. */ +static struct route_map_rule_cmd route_set_table_id_cmd = { + "table", route_set_table_id, + route_value_compile, route_value_free +}; + /* `set as-path prepend ASPATH' */ /* For AS path prepend mechanism. */ @@ -4058,6 +4085,32 @@ DEFUN (no_match_origin, RMAP_EVENT_MATCH_DELETED); } +DEFUN (set_table_id, + set_table_id_cmd, + "set table (1-4294967295)", + SET_STR + "export route to non-main kernel table\n" + "Kernel routing table id\n") +{ + int idx_id = 2; + + VTY_DECLVAR_CONTEXT(route_map_index, index); + + return generic_set_add(vty, index, "table", argv[idx_id]->arg); +} + +DEFUN (no_set_table_id, + no_set_table_id_cmd, + "no set table", + NO_STR + SET_STR + "export route to non-main kernel table\n") +{ + VTY_DECLVAR_CONTEXT(route_map_index, index); + + return generic_set_delete(vty, index, "table", NULL); +} + DEFUN (set_ip_nexthop_peer, set_ip_nexthop_peer_cmd, "[no] set ip next-hop peer-address", @@ -5167,6 +5220,7 @@ void bgp_route_map_init(void) route_map_install_match(&route_match_evpn_default_route_cmd); route_map_install_match(&route_match_vrl_source_vrf_cmd); + route_map_install_set(&route_set_table_id_cmd); route_map_install_set(&route_set_ip_nexthop_cmd); route_map_install_set(&route_set_local_pref_cmd); route_map_install_set(&route_set_weight_cmd); @@ -5223,6 +5277,8 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &match_probability_cmd); install_element(RMAP_NODE, &no_match_probability_cmd); + install_element(RMAP_NODE, &no_set_table_id_cmd); + install_element(RMAP_NODE, &set_table_id_cmd); install_element(RMAP_NODE, &set_ip_nexthop_peer_cmd); install_element(RMAP_NODE, &set_ip_nexthop_unchanged_cmd); install_element(RMAP_NODE, &set_local_pref_cmd); diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 8970e9d1d1..7923f076c1 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -1228,6 +1228,11 @@ void bgp_zebra_announce(struct bgp_node *rn, struct prefix *p, SET_FLAG(api.flags, ZEBRA_FLAG_ALLOW_RECURSION); + if (info->attr->rmap_table_id) { + SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); + api.tableid = info->attr->rmap_table_id; + } + /* Metric is currently based on the best-path only */ metric = info->attr->med; for (mpinfo = info; mpinfo; mpinfo = bgp_path_info_mpath_next(mpinfo)) { @@ -1494,6 +1499,11 @@ void bgp_zebra_withdraw(struct prefix *p, struct bgp_path_info *info, api.safi = safi; api.prefix = *p; + if (info->attr->rmap_table_id) { + SET_FLAG(api.message, ZAPI_MESSAGE_TABLEID); + api.tableid = info->attr->rmap_table_id; + } + /* If the route's source is EVPN, flag as such. */ if (is_route_parent_evpn(info)) SET_FLAG(api.flags, ZEBRA_FLAG_EVPN_ROUTE); diff --git a/doc/user/routemap.rst b/doc/user/routemap.rst index e36783d176..5c2b41b63c 100644 --- a/doc/user/routemap.rst +++ b/doc/user/routemap.rst @@ -306,6 +306,11 @@ Route Map Set Command Set BGP route origin. +.. index:: set table (1-4294967295) +.. clicmd:: set table (1-4294967295) + + Set the BGP table to a given table identifier + .. _route-map-call-command: Route Map Call Command diff --git a/zebra/zapi_msg.c b/zebra/zapi_msg.c index ffdc4dc512..b0488b7559 100644 --- a/zebra/zapi_msg.c +++ b/zebra/zapi_msg.c @@ -1425,7 +1425,7 @@ static void zread_route_add(ZAPI_HANDLER_ARGS) re->flags = api.flags; re->uptime = monotime(NULL); re->vrf_id = vrf_id; - if (api.tableid && vrf_id == VRF_DEFAULT) + if (api.tableid) re->table = api.tableid; else re->table = zvrf->table_id; @@ -1624,7 +1624,7 @@ static void zread_route_del(ZAPI_HANDLER_ARGS) if (CHECK_FLAG(api.message, ZAPI_MESSAGE_SRCPFX)) src_p = &api.src_prefix; - if (api.vrf_id == VRF_DEFAULT && api.tableid != 0) + if (api.tableid) table_id = api.tableid; else table_id = zvrf->table_id;