mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-12 09:52:27 +00:00
bgpd: add 'set as-path replace' with a configured ASN
There is no route-map set action to replace any ASN, or a part of an ASN, with a configured ASN. The current commit adds a new command to use a configured ASN as replacement, instead of using the local as number. > set as-path replace any 65500 Update the 'bgp_set_aspath_replace' test. Signed-off-by: Philippe Guibert <philippe.guibert@6wind.com>
This commit is contained in:
parent
07a2b9d41e
commit
a3f0a1f5ed
@ -2385,8 +2385,10 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object)
|
||||
struct aspath *aspath_new;
|
||||
const char *replace = rule;
|
||||
struct bgp_path_info *path = object;
|
||||
as_t own_asn = path->peer->change_local_as ? path->peer->change_local_as
|
||||
: path->peer->local_as;
|
||||
as_t replace_asn = 0;
|
||||
as_t configured_asn;
|
||||
char *buf;
|
||||
char src_asn[ASN_STRING_MAX_SIZE];
|
||||
|
||||
if (path->peer->sort != BGP_PEER_EBGP) {
|
||||
zlog_warn(
|
||||
@ -2394,6 +2396,29 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object)
|
||||
return RMAP_NOOP;
|
||||
}
|
||||
|
||||
buf = strchr(replace, ' ');
|
||||
if (!buf) {
|
||||
configured_asn = path->peer->change_local_as
|
||||
? path->peer->change_local_as
|
||||
: path->peer->local_as;
|
||||
} else {
|
||||
memcpy(src_asn, replace, (size_t)(buf - replace));
|
||||
src_asn[(size_t)(buf - replace)] = '\0';
|
||||
replace = src_asn;
|
||||
buf++;
|
||||
if (!asn_str2asn(buf, &configured_asn)) {
|
||||
zlog_warn(
|
||||
"`set as-path replace`, invalid configured AS %s",
|
||||
buf);
|
||||
return RMAP_NOOP;
|
||||
}
|
||||
}
|
||||
|
||||
if (!strmatch(replace, "any") && !asn_str2asn(replace, &replace_asn)) {
|
||||
zlog_warn("`set as-path replace`, invalid AS %s", replace);
|
||||
return RMAP_NOOP;
|
||||
}
|
||||
|
||||
if (path->attr->aspath->refcnt)
|
||||
aspath_new = aspath_dup(path->attr->aspath);
|
||||
else
|
||||
@ -2401,13 +2426,10 @@ route_set_aspath_replace(void *rule, const struct prefix *dummy, void *object)
|
||||
|
||||
if (strmatch(replace, "any")) {
|
||||
path->attr->aspath =
|
||||
aspath_replace_all_asn(aspath_new, own_asn);
|
||||
} else {
|
||||
as_t replace_asn = strtoul(replace, NULL, 10);
|
||||
|
||||
aspath_replace_all_asn(aspath_new, configured_asn);
|
||||
} else
|
||||
path->attr->aspath = aspath_replace_specific_asn(
|
||||
aspath_new, replace_asn, own_asn);
|
||||
}
|
||||
aspath_new, replace_asn, configured_asn);
|
||||
|
||||
aspath_free(aspath_new);
|
||||
|
||||
@ -5875,41 +5897,49 @@ DEFUN_YANG (set_aspath_prepend_lastas,
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
DEFPY_YANG (set_aspath_replace_asn,
|
||||
set_aspath_replace_asn_cmd,
|
||||
"set as-path replace <any|ASNUM>$replace",
|
||||
SET_STR
|
||||
"Transform BGP AS_PATH attribute\n"
|
||||
"Replace AS number to local AS number\n"
|
||||
"Replace any AS number to local AS number\n"
|
||||
"Replace a specific AS number in plain or dotted format to local AS number\n")
|
||||
DEFPY_YANG(set_aspath_replace_asn, set_aspath_replace_asn_cmd,
|
||||
"set as-path replace <any|ASNUM>$replace [<ASNUM>$configured_asn]",
|
||||
SET_STR
|
||||
"Transform BGP AS_PATH attribute\n"
|
||||
"Replace AS number to local or configured AS number\n"
|
||||
"Replace any AS number to local or configured AS number\n"
|
||||
"Replace a specific AS number to local or configured AS number\n"
|
||||
"Define the configured AS number\n")
|
||||
{
|
||||
const char *xpath =
|
||||
"./set-action[action='frr-bgp-route-map:as-path-replace']";
|
||||
char xpath_value[XPATH_MAXLEN];
|
||||
as_t as_value;
|
||||
as_t as_value, as_configured_value;
|
||||
char replace_value[ASN_STRING_MAX_SIZE * 2];
|
||||
|
||||
if (!strmatch(replace, "any") && !asn_str2asn(replace, &as_value)) {
|
||||
vty_out(vty, "%% Invalid AS value %s\n", replace);
|
||||
return CMD_WARNING_CONFIG_FAILED;
|
||||
}
|
||||
|
||||
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
|
||||
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;
|
||||
}
|
||||
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, replace);
|
||||
snprintf(replace_value, sizeof(replace_value), "%s%s%s", replace,
|
||||
configured_asn_str ? " " : "",
|
||||
configured_asn_str ? configured_asn_str : "");
|
||||
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, replace_value);
|
||||
return nb_cli_apply_changes(vty, NULL);
|
||||
}
|
||||
|
||||
DEFPY_YANG (no_set_aspath_replace_asn,
|
||||
no_set_aspath_replace_asn_cmd,
|
||||
"no set as-path replace [<any|ASNUM>]",
|
||||
NO_STR
|
||||
SET_STR
|
||||
"Transform BGP AS_PATH attribute\n"
|
||||
"Replace AS number to local AS number\n"
|
||||
"Replace any AS number to local AS number\n"
|
||||
"Replace a specific AS number in plain or dotted format to local AS number\n")
|
||||
DEFPY_YANG(no_set_aspath_replace_asn, no_set_aspath_replace_asn_cmd,
|
||||
"no set as-path replace [<any|ASNUM>] [<ASNUM>$configured_asn]",
|
||||
NO_STR SET_STR
|
||||
"Transform BGP AS_PATH attribute\n"
|
||||
"Replace AS number to local or configured AS number\n"
|
||||
"Replace any AS number to local or configured AS number\n"
|
||||
"Replace a specific AS number to local or configured AS number\n"
|
||||
"Replace AS number with a configured AS number\n"
|
||||
"Define the configured AS number\n")
|
||||
{
|
||||
const char *xpath =
|
||||
"./set-action[action='frr-bgp-route-map:as-path-replace']";
|
||||
|
@ -2105,10 +2105,11 @@ Using AS Path in Route Map
|
||||
Prepend the existing last AS number (the leftmost ASN) to the AS_PATH.
|
||||
The no form of this command removes this set operation from the route-map.
|
||||
|
||||
.. clicmd:: set as-path replace <any|ASN>
|
||||
.. clicmd:: set as-path replace <any|ASN> [<ASN>]
|
||||
|
||||
Replace a specific AS number to local AS number. ``any`` replaces each
|
||||
AS number in the AS-PATH with the local AS number.
|
||||
Replace a specific AS number to local AS number or a configured AS number.
|
||||
``any`` replaces each AS number in the AS-PATH with either the local AS
|
||||
number or the configured AS number.
|
||||
|
||||
.. clicmd:: set as-path exclude all
|
||||
|
||||
|
@ -9,6 +9,7 @@ router bgp 65001
|
||||
!
|
||||
ip prefix-list p1 seq 5 permit 172.16.255.31/32
|
||||
!
|
||||
bgp route-map delay-timer 1
|
||||
route-map r2 permit 10
|
||||
match ip address prefix-list p1
|
||||
set as-path replace 65003
|
||||
|
@ -24,6 +24,7 @@ sys.path.append(os.path.join(CWD, "../"))
|
||||
# pylint: disable=C0413
|
||||
from lib import topotest
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
from lib.topolog import logger
|
||||
|
||||
pytestmark = [pytest.mark.bgpd]
|
||||
|
||||
@ -63,7 +64,7 @@ def teardown_module(mod):
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def test_bgp_maximum_prefix_out():
|
||||
def test_bgp_set_aspath_replace_test1():
|
||||
tgen = get_topogen()
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
@ -85,6 +86,40 @@ def test_bgp_maximum_prefix_out():
|
||||
assert result is None, "Failed overriding incoming AS-PATH with route-map"
|
||||
|
||||
|
||||
def test_bgp_set_aspath_replace_test2():
|
||||
tgen = get_topogen()
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
logger.info("Configuring r1 to replace the matching AS with a configured ASN")
|
||||
router = tgen.gears["r1"]
|
||||
router.vtysh_cmd(
|
||||
"configure terminal\nroute-map r2 permit 10\nset as-path replace 65003 65500\n",
|
||||
isjson=False,
|
||||
)
|
||||
router.vtysh_cmd(
|
||||
"configure terminal\nroute-map r2 permit 20\nset as-path replace any 65501\n",
|
||||
isjson=False,
|
||||
)
|
||||
|
||||
def _bgp_converge(router):
|
||||
output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast json"))
|
||||
expected = {
|
||||
"routes": {
|
||||
"172.16.255.31/32": [{"path": "65002 65500"}],
|
||||
"172.16.255.32/32": [{"path": "65501 65501"}],
|
||||
}
|
||||
}
|
||||
return topotest.json_cmp(output, expected)
|
||||
|
||||
test_func = functools.partial(_bgp_converge, router)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=30, wait=0.5)
|
||||
|
||||
assert (
|
||||
result is None
|
||||
), "Failed overriding incoming AS-PATH with route-map replace with configured ASN"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
||||
|
Loading…
Reference in New Issue
Block a user