Skip to content

Commit

Permalink
bgpd: add set as-path exclude acl-list command
Browse files Browse the repository at this point in the history
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 sonic-net#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 sonic-net#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>
  • Loading branch information
fdumontet6WIND committed Aug 7, 2023
1 parent 5292039 commit 958340e
Show file tree
Hide file tree
Showing 3 changed files with 166 additions and 7 deletions.
40 changes: 40 additions & 0 deletions bgpd/bgp_aspath.c
Original file line number Diff line number Diff line change
Expand Up @@ -1231,6 +1231,46 @@ bool aspath_private_as_check(struct aspath *aspath)
return true;
}

/* Replace all ASN instances of the regex rule with our own ASN */
struct aspath *aspath_replace_regex_asn(struct aspath *aspath,
struct as_list *acl_list, as_t our_asn)
{
struct aspath *new;
struct assegment *cur_seg;
struct as_list *cur_as_list;
struct as_filter *cur_as_filter;
char str_buf[ASPATH_STR_DEFAULT_LEN];
uint32_t i;

new = aspath_dup(aspath);
cur_seg = new->segments;

while (cur_seg) {
cur_as_list = acl_list;
while (cur_as_list) {
cur_as_filter = cur_as_list->head;
while (cur_as_filter) {
for (i = 0; i < cur_seg->length; i++) {
snprintfrr(str_buf,
ASPATH_STR_DEFAULT_LEN,
ASN_FORMAT(new->asnotation),
&cur_seg->as[i]);
if (!regexec(cur_as_filter->reg,
str_buf, 0, NULL, 0))
cur_seg->as[i] = our_asn;
}
cur_as_filter = cur_as_filter->next;
}
cur_as_list = cur_as_list->next;
}
cur_seg = cur_seg->next;
}

aspath_str_update(new, false);
return new;
}


/* Replace all instances of the target ASN with our own ASN */
struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
as_t target_asn, as_t our_asn)
Expand Down
3 changes: 3 additions & 0 deletions bgpd/bgp_aspath.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ extern unsigned int aspath_get_last_as(struct aspath *aspath);
extern int aspath_loop_check(struct aspath *aspath, as_t asno);
extern int aspath_loop_check_confed(struct aspath *aspath, as_t asno);
extern bool aspath_private_as_check(struct aspath *aspath);
extern struct aspath *aspath_replace_regex_asn(struct aspath *aspath,
struct as_list *acl_list,
as_t our_asn);
extern struct aspath *aspath_replace_specific_asn(struct aspath *aspath,
as_t target_asn,
as_t our_asn);
Expand Down
130 changes: 123 additions & 7 deletions bgpd/bgp_routemap.c
Original file line number Diff line number Diff line change
Expand Up @@ -2410,18 +2410,63 @@ 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, ' ');
if (!buf) {
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';
Expand All @@ -2431,30 +2476,44 @@ 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)
aspath_new = aspath_dup(path->attr->aspath);
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 = {
Expand Down Expand Up @@ -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]",
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 958340e

Please sign in to comment.