From 2690f18cc85fd3e93bb4aa7330643ea8f7f30267 Mon Sep 17 00:00:00 2001 From: Donatas Abraitis Date: Sun, 18 Jul 2021 12:14:24 +0300 Subject: [PATCH] bgpd: Add route-map `match alias` command Will be handy to filter BGP prefixes by using BGP community alias instead of numerical community values. Signed-off-by: Donatas Abraitis --- bgpd/bgp_routemap.c | 105 ++++++++++++++++++++++++++++++++++ bgpd/bgp_routemap_nb.c | 7 +++ bgpd/bgp_routemap_nb.h | 4 ++ bgpd/bgp_routemap_nb_config.c | 56 ++++++++++++++++++ lib/routemap.h | 1 + lib/routemap_cli.c | 5 ++ yang/frr-bgp-route-map.yang | 15 ++++- 7 files changed, 192 insertions(+), 1 deletion(-) diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 529abcbea0..5b1044754e 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -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); diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index 1254591b87..9216426968 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -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 = { diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index f0e492eb61..069345b1a4 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -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); diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index 88e3f6438f..45f5c8f4bc 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -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 */ diff --git a/lib/routemap.h b/lib/routemap.h index 4a40ec08b9..8af3b2c3c0 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -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")) diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index bf982cfa2b..ec9033b3aa 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -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( diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index 1c990b5ed9..e11883a803 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -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; -- 2.39.5