Merge pull request #9082 from ton31337/feature/bgp_alias_route-map_match

bgpd: `match alias` for route-map
This commit is contained in:
Donald Sharp 2021-07-22 08:30:15 -04:00 committed by GitHub
commit 0775caa958
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 246 additions and 14 deletions

View File

@ -52,6 +52,7 @@
#include "bgpd/bgp_zebra.h"
#include "bgpd/bgp_regex.h"
#include "bgpd/bgp_community.h"
#include "bgpd/bgp_community_alias.h"
#include "bgpd/bgp_clist.h"
#include "bgpd/bgp_filter.h"
#include "bgpd/bgp_mplsvpn.h"
@ -1179,6 +1180,55 @@ static const struct route_map_rule_cmd route_match_vrl_source_vrf_cmd = {
route_match_vrl_source_vrf_free
};
/* `match alias` */
static enum route_map_cmd_result_t
route_match_alias(void *rule, const struct prefix *prefix, void *object)
{
char *alias = rule;
struct bgp_path_info *path = object;
char **communities;
int num;
if (path->attr->community) {
frrstr_split(path->attr->community->str, " ", &communities,
&num);
for (int i = 0; i < num; i++) {
const char *com2alias =
bgp_community2alias(communities[i]);
if (strncmp(alias, com2alias, strlen(com2alias)) == 0)
return RMAP_MATCH;
}
}
if (path->attr->lcommunity) {
frrstr_split(path->attr->lcommunity->str, " ", &communities,
&num);
for (int i = 0; i < num; i++) {
const char *com2alias =
bgp_community2alias(communities[i]);
if (strncmp(alias, com2alias, strlen(com2alias)) == 0)
return RMAP_MATCH;
}
}
return RMAP_NOMATCH;
}
static void *route_match_alias_compile(const char *arg)
{
return XSTRDUP(MTYPE_ROUTE_MAP_COMPILED, arg);
}
static void route_match_alias_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
static const struct route_map_rule_cmd route_match_alias_cmd = {
"alias", route_match_alias, route_match_alias_compile,
route_match_alias_free};
/* `match local-preference LOCAL-PREF' */
/* Match function return 1 if match is success else return zero. */
@ -4597,6 +4647,58 @@ DEFUN_YANG (no_match_local_pref,
return nb_cli_apply_changes(vty, NULL);
}
DEFUN_YANG(match_alias, match_alias_cmd, "match alias ALIAS_NAME",
MATCH_STR
"Match BGP community alias name\n"
"BGP community alias name\n")
{
const char *alias = argv[2]->arg;
struct community_alias ca1;
struct community_alias *lookup_alias;
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:match-alias']";
char xpath_value[XPATH_MAXLEN];
memset(&ca1, 0, sizeof(ca1));
strlcpy(ca1.alias, alias, sizeof(ca1.alias));
lookup_alias = bgp_ca_alias_lookup(&ca1);
if (!lookup_alias) {
vty_out(vty, "%% BGP alias name '%s' does not exist\n", alias);
return CMD_WARNING_CONFIG_FAILED;
}
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_value, sizeof(xpath_value),
"%s/rmap-match-condition/frr-bgp-route-map:alias", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, alias);
return nb_cli_apply_changes(vty, NULL);
}
DEFUN_YANG(no_match_alias, no_match_alias_cmd, "no match alias [ALIAS_NAME]",
NO_STR MATCH_STR
"Match BGP community alias name\n"
"BGP community alias name\n")
{
int idx_alias = 3;
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:match-alias']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
if (argc <= idx_alias)
return nb_cli_apply_changes(vty, NULL);
snprintf(xpath_value, sizeof(xpath_value),
"%s/rmap-match-condition/frr-bgp-route-map:alias", xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_DESTROY,
argv[idx_alias]->arg);
return nb_cli_apply_changes(vty, NULL);
}
DEFPY_YANG (match_community,
match_community_cmd,
@ -6286,6 +6388,7 @@ void bgp_route_map_init(void)
route_map_no_set_tag_hook(generic_set_delete);
route_map_install_match(&route_match_peer_cmd);
route_map_install_match(&route_match_alias_cmd);
route_map_install_match(&route_match_local_pref_cmd);
#ifdef HAVE_SCRIPTING
route_map_install_match(&route_match_script_cmd);
@ -6370,6 +6473,8 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &no_match_aspath_cmd);
install_element(RMAP_NODE, &match_local_pref_cmd);
install_element(RMAP_NODE, &no_match_local_pref_cmd);
install_element(RMAP_NODE, &match_alias_cmd);
install_element(RMAP_NODE, &no_match_alias_cmd);
install_element(RMAP_NODE, &match_community_cmd);
install_element(RMAP_NODE, &no_match_community_cmd);
install_element(RMAP_NODE, &match_lcommunity_cmd);

View File

@ -38,6 +38,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.destroy = lib_route_map_entry_match_condition_rmap_match_condition_local_preference_destroy,
}
},
{
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:alias",
.cbs = {
.modify = lib_route_map_entry_match_condition_rmap_match_condition_alias_modify,
.destroy = lib_route_map_entry_match_condition_rmap_match_condition_alias_destroy,
}
},
{
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:script",
.cbs = {

View File

@ -29,6 +29,10 @@ extern const struct frr_yang_module_info frr_bgp_route_map_info;
/* prototypes */
int lib_route_map_entry_match_condition_rmap_match_condition_local_preference_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_local_preference_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_alias_modify(
struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_alias_destroy(
struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_script_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_script_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_origin_modify(struct nb_cb_modify_args *args);

View File

@ -159,6 +159,62 @@ lib_route_map_entry_match_condition_rmap_match_condition_local_preference_destro
return NB_OK;
}
/*
* XPath:
* /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:alias
*/
int lib_route_map_entry_match_condition_rmap_match_condition_alias_modify(
struct nb_cb_modify_args *args)
{
struct routemap_hook_context *rhc;
const char *alias;
enum rmap_compile_rets ret;
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
/* Add configuration. */
rhc = nb_running_get_entry(args->dnode, NULL, true);
alias = yang_dnode_get_string(args->dnode, NULL);
/* Set destroy information. */
rhc->rhc_mhook = bgp_route_match_delete;
rhc->rhc_rule = "alias";
rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
ret = bgp_route_match_add(rhc->rhc_rmi, "alias", alias,
RMAP_EVENT_MATCH_ADDED, args->errmsg,
args->errmsg_len);
if (ret != RMAP_COMPILE_SUCCESS) {
rhc->rhc_mhook = NULL;
return NB_ERR_VALIDATION;
}
break;
}
return NB_OK;
}
int lib_route_map_entry_match_condition_rmap_match_condition_alias_destroy(
struct nb_cb_destroy_args *args)
{
switch (args->event) {
case NB_EV_VALIDATE:
case NB_EV_PREPARE:
case NB_EV_ABORT:
break;
case NB_EV_APPLY:
return lib_route_map_entry_match_destroy(args);
}
return NB_OK;
}
/*
* XPath: /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:script
*/

View File

@ -2194,6 +2194,12 @@ communities attribute.
The following commands can be used in route maps:
.. clicmd:: match alias WORD
This command performs match to BGP updates using community alias WORD. When
the one of BGP communities value match to the one of community alias value in
community alias, it is match.
.. clicmd:: match community WORD exact-match [exact-match]
This command perform match to BGP updates using community list WORD. When

View File

@ -270,6 +270,7 @@ DECLARE_QOBJ_TYPE(route_map);
/* BGP route-map match conditions */
#define IS_MATCH_LOCAL_PREF(C) \
(strmatch(C, "frr-bgp-route-map:match-local-preference"))
#define IS_MATCH_ALIAS(C) (strmatch(C, "frr-bgp-route-map:match-alias"))
#define IS_MATCH_ORIGIN(C) \
(strmatch(C, "frr-bgp-route-map:match-origin"))
#define IS_MATCH_RPKI(C) (strmatch(C, "frr-bgp-route-map:rpki"))

View File

@ -634,6 +634,11 @@ void route_map_condition_show(struct vty *vty, struct lyd_node *dnode,
yang_dnode_get_string(
dnode,
"./rmap-match-condition/frr-bgp-route-map:local-preference"));
} else if (IS_MATCH_ALIAS(condition)) {
vty_out(vty, " match alias %s\n",
yang_dnode_get_string(
dnode,
"./rmap-match-condition/frr-bgp-route-map:alias"));
} else if (IS_MATCH_ORIGIN(condition)) {
vty_out(vty, " match origin %s\n",
yang_dnode_get_string(

View File

@ -6,4 +6,17 @@ bgp community alias 65001:1:1 large-community-r2-1
router bgp 65001
no bgp ebgp-requires-policy
neighbor 192.168.1.2 remote-as external
address-family ipv4 unicast
redistribute connected
neighbor 192.168.1.2 route-map r2 in
exit-address-family
!
route-map r2 permit 10
match alias community-r2-1
set tag 10
route-map r2 permit 20
match alias community-r2-2
set tag 20
route-map r2 permit 30
set tag 100
!

View File

@ -8,6 +8,7 @@ router bgp 65002
!
ip prefix-list p1 permit 172.16.16.1/32
ip prefix-list p2 permit 172.16.16.2/32
ip prefix-list p3 permit 172.16.16.3/32
!
route-map r1 permit 10
match ip address prefix-list p1
@ -16,4 +17,6 @@ route-map r1 permit 10
route-map r1 permit 20
match ip address prefix-list p2
set community 65002:1 65002:2
route-map r1 permit 30
match ip address prefix-list p3
!

View File

@ -2,6 +2,7 @@
int lo
ip address 172.16.16.1/32
ip address 172.16.16.2/32
ip address 172.16.16.3/32
!
int r2-eth0
ip address 192.168.1.2/24

View File

@ -84,39 +84,57 @@ def test_bgp_community_alias():
router = tgen.gears["r1"]
def _bgp_converge(router):
output = json.loads(
router.vtysh_cmd("show bgp ipv4 unicast 172.16.16.1/32 json")
)
output = json.loads(router.vtysh_cmd("show ip route json"))
expected = {
"paths": [
"172.16.16.1/32": [
{
"community": {"string": "community-r2-1 65001:2"},
"largeCommunity": {"string": "large-community-r2-1 65001:1:2"},
"tag": 10,
"communities": "community-r2-1 65001:2",
"largeCommunities": "large-community-r2-1 65001:1:2",
}
]
],
"172.16.16.2/32": [
{
"tag": 20,
"communities": "65002:1 community-r2-2",
"largeCommunities": "",
}
],
"172.16.16.3/32": [
{
"tag": 100,
"communities": "",
"largeCommunities": "",
}
],
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_converge, router)
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, 'Cannot see BGP community aliases "{}"'.format(router)
assert result is None, "Cannot see BGP community aliases at r1"
def _bgp_show_prefixes_by_alias(router):
output = json.loads(
router.vtysh_cmd("show bgp ipv4 unicast alias community-r2-2 json detail")
router.vtysh_cmd(
"show bgp ipv4 unicast alias large-community-r2-1 json detail"
)
)
expected = {
"routes": {
"172.16.16.2/32": [{"community": {"string": "65002:1 community-r2-2"}}]
"172.16.16.1/32": [
{
"community": {"string": "community-r2-1 65001:2"},
"largeCommunity": {"string": "large-community-r2-1 65001:1:2"},
}
]
}
}
return topotest.json_cmp(output, expected)
test_func = functools.partial(_bgp_show_prefixes_by_alias, router)
success, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
assert result is None, 'Cannot see BGP prefixes by community alias "{}"'.format(
router
)
assert result is None, "Cannot see BGP prefixes by community alias at r1"
if __name__ == "__main__":

View File

@ -36,6 +36,12 @@ module frr-bgp-route-map {
"Initial revision";
}
identity match-alias {
base frr-route-map:rmap-match-type;
description
"Match BGP community alias name";
}
identity match-local-preference {
base frr-route-map:rmap-match-type;
description
@ -352,7 +358,14 @@ module frr-bgp-route-map {
}
}
case script {
case alias {
when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-alias')";
leaf alias {
type string;
}
}
case script {
when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:match-condition/frr-route-map:condition, 'frr-bgp-route-map:match-script')";
leaf script {
type string;