summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_routemap.c
diff options
context:
space:
mode:
authorFrancois Dumontet <francois.dumontet@6wind.com>2023-07-11 10:03:04 +0200
committerFrancois Dumontet <francois.dumontet@6wind.com>2023-08-07 12:30:34 +0200
commit958340e935350f840e31a0405b492e6ac7dfe13b (patch)
tree7b37d33110cacc7043d811916074d1e13953c5ff /bgpd/bgp_routemap.c
parentMerge pull request #14151 from opensourcerouting/fix/improve_addpath_selected... (diff)
downloadfrr-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.c130
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);