bgpd: Implement match source-protocol for route-maps

The main idea is to filter routes by matching source (originating) protocol
for outgoing direction. For instance, filter outgoing routes to an arbitrary
router that are static only. Or filter out only routes learned from RIP.

Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
This commit is contained in:
Donatas Abraitis 2023-05-10 23:37:47 +03:00
parent 052fa79dd2
commit 1c035c8c2c
7 changed files with 168 additions and 2 deletions

View File

@ -872,6 +872,46 @@ static const struct route_map_rule_cmd
route_match_ip_next_hop_type_free
};
/* `match source-protocol` */
static enum route_map_cmd_result_t
route_match_source_protocol(void *rule, const struct prefix *prefix,
void *object)
{
struct bgp_path_info *path = object;
int *protocol = rule;
if (!path)
return RMAP_NOMATCH;
if (path->type == *protocol)
return RMAP_MATCH;
return RMAP_NOMATCH;
}
static void *route_match_source_protocol_compile(const char *arg)
{
int *protocol;
protocol = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(*protocol));
*protocol = proto_name2num(arg);
return protocol;
}
static void route_match_source_protocol_free(void *rule)
{
XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
}
static const struct route_map_rule_cmd route_match_source_protocol_cmd = {
"source-protocol",
route_match_source_protocol,
route_match_source_protocol_compile,
route_match_source_protocol_free
};
/* `match ip route-source prefix-list PREFIX_LIST' */
static enum route_map_cmd_result_t
@ -7177,6 +7217,42 @@ DEFPY_YANG (match_rpki_extcommunity,
return nb_cli_apply_changes(vty, NULL);
}
DEFPY_YANG (match_source_protocol,
match_source_protocol_cmd,
"match source-protocol " FRR_REDIST_STR_ZEBRA "$proto",
MATCH_STR
"Match protocol via which the route was learnt\n"
FRR_REDIST_HELP_STR_ZEBRA)
{
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:source-protocol']";
char xpath_value[XPATH_MAXLEN];
nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
snprintf(xpath_value, sizeof(xpath_value),
"%s/rmap-match-condition/frr-bgp-route-map:source-protocol",
xpath);
nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, proto);
return nb_cli_apply_changes(vty, NULL);
}
DEFPY_YANG (no_match_source_protocol,
no_match_source_protocol_cmd,
"no match source-protocol [" FRR_REDIST_STR_ZEBRA "]",
NO_STR
MATCH_STR
"Match protocol via which the route was learnt\n"
FRR_REDIST_HELP_STR_ZEBRA)
{
const char *xpath =
"./match-condition[condition='frr-bgp-route-map:source-protocol']";
nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
return nb_cli_apply_changes(vty, NULL);
}
/* Initialization of route map. */
void bgp_route_map_init(void)
{
@ -7252,6 +7328,7 @@ void bgp_route_map_init(void)
route_map_install_match(&route_match_ip_address_prefix_list_cmd);
route_map_install_match(&route_match_ip_next_hop_prefix_list_cmd);
route_map_install_match(&route_match_ip_next_hop_type_cmd);
route_map_install_match(&route_match_source_protocol_cmd);
route_map_install_match(&route_match_ip_route_source_prefix_list_cmd);
route_map_install_match(&route_match_aspath_cmd);
route_map_install_match(&route_match_community_cmd);
@ -7441,6 +7518,8 @@ void bgp_route_map_init(void)
install_element(RMAP_NODE, &set_ipv6_nexthop_peer_cmd);
install_element(RMAP_NODE, &no_set_ipv6_nexthop_peer_cmd);
install_element(RMAP_NODE, &match_rpki_extcommunity_cmd);
install_element(RMAP_NODE, &match_source_protocol_cmd);
install_element(RMAP_NODE, &no_match_source_protocol_cmd);
#ifdef HAVE_SCRIPTING
install_element(RMAP_NODE, &match_script_cmd);
#endif

View File

@ -74,6 +74,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
.destroy = lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_destroy,
}
},
{
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:source-protocol",
.cbs = {
.modify = lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_modify,
.destroy = lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_destroy,
}
},
{
.xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:peer-ipv4-address",
.cbs = {

View File

@ -30,6 +30,10 @@ int lib_route_map_entry_match_condition_rmap_match_condition_rpki_extcommunity_m
struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_rpki_extcommunity_destroy(
struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_modify(
struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_destroy(
struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_probability_modify(struct nb_cb_modify_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_probability_destroy(struct nb_cb_destroy_args *args);
int lib_route_map_entry_match_condition_rmap_match_condition_source_vrf_modify(struct nb_cb_modify_args *args);

View File

@ -367,6 +367,60 @@ lib_route_map_entry_match_condition_rmap_match_condition_rpki_destroy(
return NB_OK;
}
/*
* XPath:
* /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:source-protocol
*/
int lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_modify(
struct nb_cb_modify_args *args)
{
struct routemap_hook_context *rhc;
enum rmap_compile_rets ret;
const char *proto;
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);
proto = yang_dnode_get_string(args->dnode, NULL);
/* Set destroy information. */
rhc->rhc_mhook = bgp_route_match_delete;
rhc->rhc_rule = "source-protocol";
rhc->rhc_event = RMAP_EVENT_MATCH_DELETED;
ret = bgp_route_match_add(rhc->rhc_rmi, "source-protocol",
proto, RMAP_EVENT_MATCH_ADDED,
args->errmsg, args->errmsg_len);
if (ret != RMAP_COMPILE_SUCCESS) {
rhc->rhc_mhook = NULL;
return NB_ERR_INCONSISTENCY;
}
}
return NB_OK;
}
int lib_route_map_entry_match_condition_rmap_match_condition_source_protocol_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:rpki-extcommunity

View File

@ -259,6 +259,8 @@ DECLARE_QOBJ_TYPE(route_map);
(strmatch(C, "frr-zebra-route-map:ipv4-next-hop-prefix-length"))
#define IS_MATCH_SRC_PROTO(C) \
(strmatch(C, "frr-zebra-route-map:source-protocol"))
#define IS_MATCH_BGP_SRC_PROTO(C) \
(strmatch(C, "frr-bgp-route-map:source-protocol"))
#define IS_MATCH_SRC_INSTANCE(C) \
(strmatch(C, "frr-zebra-route-map:source-instance"))
/* BGP route-map match conditions */

View File

@ -599,11 +599,14 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode,
yang_dnode_get_string(
dnode,
"./rmap-match-condition/frr-zebra-route-map:ipv4-prefix-length"));
} else if (IS_MATCH_SRC_PROTO(condition)) {
} else if (IS_MATCH_SRC_PROTO(condition) ||
IS_MATCH_BGP_SRC_PROTO(condition)) {
vty_out(vty, " match source-protocol %s\n",
yang_dnode_get_string(
dnode,
"./rmap-match-condition/frr-zebra-route-map:source-protocol"));
IS_MATCH_SRC_PROTO(condition)
? "./rmap-match-condition/frr-zebra-route-map:source-protocol"
: "./rmap-match-condition/frr-bgp-route-map:source-protocol"));
} else if (IS_MATCH_SRC_INSTANCE(condition)) {
vty_out(vty, " match source-instance %s\n",
yang_dnode_get_string(

View File

@ -23,6 +23,10 @@ module frr-bgp-route-map {
prefix rt-types;
}
import frr-route-types {
prefix frr-route-types;
}
organization
"Free Range Routing";
contact
@ -168,6 +172,12 @@ module frr-bgp-route-map {
"Match IPv6 next hop address";
}
identity source-protocol {
base frr-route-map:rmap-match-type;
description
"Match protocol via which the route was learnt";
}
identity distance {
base frr-route-map:rmap-set-type;
description
@ -759,6 +769,13 @@ module frr-bgp-route-map {
"IPv6 address";
}
}
case source-protocol {
when "derived-from-or-self(../frr-route-map:condition, 'frr-bgp-route-map:source-protocol')";
leaf source-protocol {
type frr-route-types:frr-route-types;
}
}
}
augment "/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:rmap-set-action/frr-route-map:set-action" {