diff options
author | Francois Dumontet <francois.dumontet@6wind.com> | 2023-07-11 10:03:04 +0200 |
---|---|---|
committer | Francois Dumontet <francois.dumontet@6wind.com> | 2023-08-07 12:30:34 +0200 |
commit | 958340e935350f840e31a0405b492e6ac7dfe13b (patch) | |
tree | 7b37d33110cacc7043d811916074d1e13953c5ff /bgpd/bgp_routemap.c | |
parent | Merge pull request #14151 from opensourcerouting/fix/improve_addpath_selected... (diff) | |
download | frr-958340e935350f840e31a0405b492e6ac7dfe13b.tar.xz frr-958340e935350f840e31a0405b492e6ac7dfe13b.zip |
bgpd: add set as-path exclude acl-list command
A route-map applied on incoming BGP updates is not able
to replace an unwanted as segments by another one.
unwanted as segment are based on an AS path access-list.
The below configuration illustrates the case:
router bgp 65001
address-family ipv4 unicast
neighbor 192.168.1.2 route-map rule_2 in
exit-address-family
bgp as-path access-list RULE permit ^65
route-map rule_2 permit 10
set as-path replace as-path-access-list RULE 6000
```
BGP routing table entry for 10.10.10.10/32, version 13
Paths: (1 available, best #1, table default)
Advertised to non peer-group peers:
192.168.10.65
65000 1 2 3 123
192.168.10.65 from 192.168.10.65 (10.10.10.11)
Origin IGP, metric 0, valid, external, best (First path received)
```
After:
```
do show ip bgp 10.10.10.10/32
BGP routing table entry for 10.10.10.10/32, version 15
Paths: (1 available, best #1, table default)
Advertised to non peer-group peers:
192.168.10.65
6000 1 2 3 123
192.168.10.65 from 192.168.10.65 (10.10.10.11)
Origin IGP, metric 0, valid, external, best (First path
received)
```
Signed-off-by: Francois Dumontet <francois.dumontet@6wind.com>
Diffstat (limited to 'bgpd/bgp_routemap.c')
-rw-r--r-- | bgpd/bgp_routemap.c | 130 |
1 files changed, 123 insertions, 7 deletions
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index b7ac976e2..a8e631018 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -2410,11 +2410,16 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object) as_t configured_asn; char *buf; char src_asn[ASN_STRING_MAX_SIZE]; + char *acl_list_name = NULL; + uint32_t acl_list_name_len = 0; + char *buf_acl_name = NULL; + static const char asp_acl[] = "as-path-access-list"; + struct as_list *aspath_acl = NULL; if (path->peer->sort != BGP_PEER_EBGP) { zlog_warn( "`set as-path replace` is supported only for EBGP peers"); - return RMAP_NOOP; + goto end_ko; } buf = strchr(replace, ' '); @@ -2422,6 +2427,46 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object) configured_asn = path->peer->change_local_as ? path->peer->change_local_as : path->peer->local_as; + } else if (!strncmp(replace, asp_acl, strlen(asp_acl))) { + /* its as-path-acl-list command get the access list name */ + while (*buf == ' ') + buf++; + buf_acl_name = buf; + buf = strchr(buf_acl_name, ' '); + if (buf) + acl_list_name_len = buf - buf_acl_name; + else + acl_list_name_len = strlen(buf_acl_name); + + buf_acl_name[acl_list_name_len] = 0; + /* get the acl-list */ + aspath_acl = as_list_lookup(buf_acl_name); + if (!aspath_acl) { + zlog_warn("`set as-path replace`, invalid as-path-access-list name: %s", + buf_acl_name); + goto end_ko; + } + acl_list_name = XSTRDUP(MTYPE_TMP, buf_acl_name); + buf_acl_name[acl_list_name_len] = ' '; + + if (!buf) { + configured_asn = path->peer->change_local_as + ? path->peer->change_local_as + : path->peer->local_as; + } else { + while (*buf == ' ') + buf++; + /* get the configured asn */ + if (!asn_str2asn(buf, &configured_asn)) { + zlog_warn( + "`set as-path replace`, invalid configured AS %s", + buf); + goto end_ko; + } + } + + replace = buf; + } else { memcpy(src_asn, replace, (size_t)(buf - replace)); src_asn[(size_t)(buf - replace)] = '\0'; @@ -2431,13 +2476,14 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object) zlog_warn( "`set as-path replace`, invalid configured AS %s", buf); - return RMAP_NOOP; + goto end_ko; } } - if (!strmatch(replace, "any") && !asn_str2asn(replace, &replace_asn)) { + if (replace && !strmatch(replace, "any") && + !asn_str2asn(replace, &replace_asn)) { zlog_warn("`set as-path replace`, invalid AS %s", replace); - return RMAP_NOOP; + goto end_ko; } if (path->attr->aspath->refcnt) @@ -2445,16 +2491,29 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object) else aspath_new = path->attr->aspath; - if (strmatch(replace, "any")) { + if (aspath_acl) { + path->attr->aspath = aspath_replace_regex_asn(aspath_new, + aspath_acl, + configured_asn); + } else if (strmatch(replace, "any")) { path->attr->aspath = aspath_replace_all_asn(aspath_new, configured_asn); - } else + } else { path->attr->aspath = aspath_replace_specific_asn( aspath_new, replace_asn, configured_asn); - + } aspath_free(aspath_new); + + if (acl_list_name) + XFREE(MTYPE_TMP, acl_list_name); return RMAP_OKAY; + +end_ko: + if (acl_list_name) + XFREE(MTYPE_TMP, acl_list_name); + return RMAP_NOOP; + } static const struct route_map_rule_cmd route_set_aspath_replace_cmd = { @@ -6087,6 +6146,61 @@ DEFPY_YANG(no_set_aspath_replace_asn, no_set_aspath_replace_asn_cmd, return nb_cli_apply_changes(vty, NULL); } +DEFPY_YANG( + set_aspath_replace_access_list, set_aspath_replace_access_list_cmd, + "set as-path replace as-path-access-list AS_PATH_FILTER_NAME$aspath_filter_name [<ASNUM>$configured_asn]", + SET_STR + "Transform BGP AS-path attribute\n" + "Replace AS number to local or configured AS number\n" + "Specify an as path access list name\n" + "AS path access list name\n" + "Define the configured AS number\n") +{ + char *str; + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-replace']"; + char xpath_value[XPATH_MAXLEN]; + as_t as_configured_value; + char replace_value[ASN_STRING_MAX_SIZE * 2]; + + if (configured_asn_str && + !asn_str2asn(configured_asn_str, &as_configured_value)) { + vty_out(vty, "%% Invalid AS configured value %s\n", + configured_asn_str); + return CMD_WARNING_CONFIG_FAILED; + } + + str = argv_concat(argv, argc, 3); + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + snprintf(replace_value, sizeof(replace_value), "%s %s", aspath_filter_name, str); + + snprintf(xpath_value, sizeof(xpath_value), + "%s/rmap-set-action/frr-bgp-route-map:replace-as-path", xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, str); + + return nb_cli_apply_changes(vty, NULL); +} + +DEFPY_YANG( + no_set_aspath_replace_access_list, no_set_aspath_replace_access_list_cmd, + "no set as-path replace as-path-access-list [AS_PATH_FILTER_NAME] [<ASNUM>$configured_asn]", + NO_STR + SET_STR + "Transform BGP AS_PATH attribute\n" + "Replace AS number to local or configured AS number\n" + "Specify an as path access list name\n" + "AS path access list name\n" + "Define the configured AS number\n") +{ + const char *xpath = + "./set-action[action='frr-bgp-route-map:as-path-replace']"; + + nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL); + return nb_cli_apply_changes(vty, NULL); +} + DEFUN_YANG (no_set_aspath_prepend, no_set_aspath_prepend_cmd, "no set as-path prepend [ASNUM]", @@ -7792,12 +7906,14 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &set_aspath_exclude_all_cmd); install_element(RMAP_NODE, &set_aspath_exclude_access_list_cmd); install_element(RMAP_NODE, &set_aspath_replace_asn_cmd); + install_element(RMAP_NODE, &set_aspath_replace_access_list_cmd); install_element(RMAP_NODE, &no_set_aspath_prepend_cmd); install_element(RMAP_NODE, &no_set_aspath_prepend_lastas_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_all_cmd); install_element(RMAP_NODE, &no_set_aspath_exclude_access_list_cmd); install_element(RMAP_NODE, &no_set_aspath_replace_asn_cmd); + install_element(RMAP_NODE, &no_set_aspath_replace_access_list_cmd); install_element(RMAP_NODE, &set_origin_cmd); install_element(RMAP_NODE, &no_set_origin_cmd); install_element(RMAP_NODE, &set_atomic_aggregate_cmd); |