diff options
| author | Donatas Abraitis <donatas@opensourcerouting.org> | 2022-08-31 23:00:26 +0300 |
|---|---|---|
| committer | Donatas Abraitis <donatas@opensourcerouting.org> | 2022-09-04 21:54:47 +0300 |
| commit | 324e8b1f79ccd00f75cdb8ba95ba0c0ee5e82b4d (patch) | |
| tree | 8bdf9184e44c469d672a0e2864fa7ae931f05b40 | |
| parent | 7b27cf7bbdf24521ddb780298d998a167226c684 (diff) | |
bgpd: Handle Origin Validation State extended community via route-map match
Add an ability to match via route-maps. An additional route-map command
`match rpki-extcommunity <invalid|notfound|valid>` added.
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
| -rw-r--r-- | bgpd/bgp_ecommunity.h | 4 | ||||
| -rw-r--r-- | bgpd/bgp_routemap.c | 97 | ||||
| -rw-r--r-- | bgpd/bgp_routemap_nb.c | 7 | ||||
| -rw-r--r-- | bgpd/bgp_routemap_nb.h | 4 | ||||
| -rw-r--r-- | bgpd/bgp_routemap_nb_config.c | 54 | ||||
| -rw-r--r-- | doc/user/rpki.rst | 6 | ||||
| -rw-r--r-- | lib/routemap.h | 2 | ||||
| -rw-r--r-- | lib/routemap_cli.c | 5 | ||||
| -rw-r--r-- | yang/frr-bgp-route-map.yang | 29 |
9 files changed, 206 insertions, 2 deletions
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h index 3d8ef947d5..4d7d4234a2 100644 --- a/bgpd/bgp_ecommunity.h +++ b/bgpd/bgp_ecommunity.h @@ -104,10 +104,10 @@ /* Extended Community Origin Validation State */ enum ecommunity_origin_validation_states { - ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED = -1, ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID, ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND, - ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID + ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID, + ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED }; /* Extended Communities type flag. */ diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c index 33f68c9e88..45ceb6bfde 100644 --- a/bgpd/bgp_routemap.c +++ b/bgpd/bgp_routemap.c @@ -3738,6 +3738,73 @@ static const struct route_map_rule_cmd route_set_originator_id_cmd = { route_set_originator_id_free, }; +static enum route_map_cmd_result_t +route_match_rpki_extcommunity(void *rule, const struct prefix *prefix, + void *object) +{ + struct bgp_path_info *path; + struct ecommunity *ecomm; + struct ecommunity_val *ecomm_val; + enum rpki_states *rpki_status = rule; + enum rpki_states ecomm_rpki_status = RPKI_NOT_BEING_USED; + + path = object; + + ecomm = bgp_attr_get_ecommunity(path->attr); + if (!ecomm) + return RMAP_NOMATCH; + + ecomm_val = ecommunity_lookup(ecomm, ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS, + ECOMMUNITY_ORIGIN_VALIDATION_STATE); + if (!ecomm_val) + return RMAP_NOMATCH; + + /* The Origin Validation State is encoded in the last octet of + * the extended community. + */ + switch (ecomm_val->val[7]) { + case ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID: + ecomm_rpki_status = RPKI_VALID; + break; + case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND: + ecomm_rpki_status = RPKI_NOTFOUND; + break; + case ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID: + ecomm_rpki_status = RPKI_INVALID; + break; + case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED: + break; + } + + if (ecomm_rpki_status == *rpki_status) + return RMAP_MATCH; + + return RMAP_NOMATCH; +} + +static void *route_match_extcommunity_compile(const char *arg) +{ + int *rpki_status; + + rpki_status = XMALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(int)); + + if (strcmp(arg, "valid") == 0) + *rpki_status = RPKI_VALID; + else if (strcmp(arg, "invalid") == 0) + *rpki_status = RPKI_INVALID; + else + *rpki_status = RPKI_NOTFOUND; + + return rpki_status; +} + +static const struct route_map_rule_cmd route_match_rpki_extcommunity_cmd = { + "rpki-extcommunity", + route_match_rpki_extcommunity, + route_match_extcommunity_compile, + route_value_free +}; + /* * This is the workhorse routine for processing in/out routemap * modifications. @@ -6713,6 +6780,34 @@ DEFUN_YANG (no_set_originator_id, return nb_cli_apply_changes(vty, NULL); } +DEFPY_YANG (match_rpki_extcommunity, + match_rpki_extcommunity_cmd, + "[no$no] match rpki-extcommunity <valid|invalid|notfound>", + NO_STR + MATCH_STR + "BGP RPKI (Origin Validation State) extended community attribute\n" + "Valid prefix\n" + "Invalid prefix\n" + "Prefix not found\n") +{ + const char *xpath = + "./match-condition[condition='frr-bgp-route-map:rpki-extcommunity']"; + char xpath_value[XPATH_MAXLEN]; + + nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL); + + if (!no) { + snprintf( + xpath_value, sizeof(xpath_value), + "%s/rmap-match-condition/frr-bgp-route-map:rpki-extcommunity", + xpath); + nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, + argv[2]->arg); + } + + return nb_cli_apply_changes(vty, NULL); +} + /* Initialization of route map. */ void bgp_route_map_init(void) { @@ -6949,6 +7044,7 @@ void bgp_route_map_init(void) route_map_install_set(&route_set_ipv6_nexthop_prefer_global_cmd); route_map_install_set(&route_set_ipv6_nexthop_local_cmd); route_map_install_set(&route_set_ipv6_nexthop_peer_cmd); + route_map_install_match(&route_match_rpki_extcommunity_cmd); install_element(RMAP_NODE, &match_ipv6_next_hop_cmd); install_element(RMAP_NODE, &match_ipv6_next_hop_address_cmd); @@ -6966,6 +7062,7 @@ void bgp_route_map_init(void) install_element(RMAP_NODE, &no_set_ipv6_nexthop_prefer_global_cmd); 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); #ifdef HAVE_SCRIPTING install_element(RMAP_NODE, &match_script_cmd); #endif diff --git a/bgpd/bgp_routemap_nb.c b/bgpd/bgp_routemap_nb.c index 585596e1aa..21517d66d7 100644 --- a/bgpd/bgp_routemap_nb.c +++ b/bgpd/bgp_routemap_nb.c @@ -67,6 +67,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = { } }, { + .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:rpki-extcommunity", + .cbs = { + .modify = lib_route_map_entry_match_condition_rmap_match_condition_rpki_extcommunity_modify, + .destroy = lib_route_map_entry_match_condition_rmap_match_condition_rpki_extcommunity_destroy, + } + }, + { .xpath = "/frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:probability", .cbs = { .modify = lib_route_map_entry_match_condition_rmap_match_condition_probability_modify, diff --git a/bgpd/bgp_routemap_nb.h b/bgpd/bgp_routemap_nb.h index a01adf7d5d..6064d3ad1a 100644 --- a/bgpd/bgp_routemap_nb.h +++ b/bgpd/bgp_routemap_nb.h @@ -39,6 +39,10 @@ int lib_route_map_entry_match_condition_rmap_match_condition_origin_modify(struc int lib_route_map_entry_match_condition_rmap_match_condition_origin_destroy(struct nb_cb_destroy_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_rpki_modify(struct nb_cb_modify_args *args); int lib_route_map_entry_match_condition_rmap_match_condition_rpki_destroy(struct nb_cb_destroy_args *args); +int lib_route_map_entry_match_condition_rmap_match_condition_rpki_extcommunity_modify( + 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_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); diff --git a/bgpd/bgp_routemap_nb_config.c b/bgpd/bgp_routemap_nb_config.c index b87877b1e0..0b956b5943 100644 --- a/bgpd/bgp_routemap_nb_config.c +++ b/bgpd/bgp_routemap_nb_config.c @@ -381,6 +381,60 @@ lib_route_map_entry_match_condition_rmap_match_condition_rpki_destroy( } /* + * XPath: + * /frr-route-map:lib/route-map/entry/match-condition/rmap-match-condition/frr-bgp-route-map:rpki-extcommunity + */ +int lib_route_map_entry_match_condition_rmap_match_condition_rpki_extcommunity_modify( + struct nb_cb_modify_args *args) +{ + struct routemap_hook_context *rhc; + const char *rpki; + 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); + rpki = yang_dnode_get_string(args->dnode, NULL); + + /* Set destroy information. */ + rhc->rhc_mhook = bgp_route_match_delete; + rhc->rhc_rule = "rpki-extcommunity"; + rhc->rhc_event = RMAP_EVENT_MATCH_DELETED; + + ret = bgp_route_match_add(rhc->rhc_rmi, "rpki-extcommunity", + rpki, 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_rpki_extcommunity_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:probability */ int diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst index cc0e7f70c6..4053536247 100644 --- a/doc/user/rpki.rst +++ b/doc/user/rpki.rst @@ -178,6 +178,12 @@ Validating BGP Updates match rpki valid set local-preference 500 +.. clicmd:: match rpki-extcommunity notfound|invalid|valid + + Create a clause for a route map to match prefixes with the specified RPKI + state, that is derived from the Origin Validation State extended community + attribute (OVS). OVS extended community is non-transitive and is exchanged + only between iBGP peers. .. _debugging: diff --git a/lib/routemap.h b/lib/routemap.h index ad391981e0..1a8a94e375 100644 --- a/lib/routemap.h +++ b/lib/routemap.h @@ -280,6 +280,8 @@ DECLARE_QOBJ_TYPE(route_map); #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")) +#define IS_MATCH_RPKI_EXTCOMMUNITY(C) \ + (strmatch(C, "frr-bgp-route-map:rpki-extcommunity")) #define IS_MATCH_PROBABILITY(C) \ (strmatch(C, "frr-bgp-route-map:probability")) #define IS_MATCH_SRC_VRF(C) \ diff --git a/lib/routemap_cli.c b/lib/routemap_cli.c index ff98a14c41..59253942ad 100644 --- a/lib/routemap_cli.c +++ b/lib/routemap_cli.c @@ -650,6 +650,11 @@ void route_map_condition_show(struct vty *vty, const struct lyd_node *dnode, yang_dnode_get_string( dnode, "./rmap-match-condition/frr-bgp-route-map:rpki")); + } else if (IS_MATCH_RPKI_EXTCOMMUNITY(condition)) { + vty_out(vty, " match rpki-extcommunity %s\n", + yang_dnode_get_string( + dnode, + "./rmap-match-condition/frr-bgp-route-map:rpki-extcommunity")); } else if (IS_MATCH_PROBABILITY(condition)) { vty_out(vty, " match probability %s\n", yang_dnode_get_string( diff --git a/yang/frr-bgp-route-map.yang b/yang/frr-bgp-route-map.yang index eaa7891f0c..84d5b74ddc 100644 --- a/yang/frr-bgp-route-map.yang +++ b/yang/frr-bgp-route-map.yang @@ -66,6 +66,12 @@ module frr-bgp-route-map { "Control rpki specific settings"; } + identity rpki-extcommunity { + base frr-route-map:rmap-match-type; + description + "Control rpki specific settings derived from extended community"; + } + identity probability { base frr-route-map:rmap-match-type; description @@ -430,6 +436,29 @@ module frr-bgp-route-map { } } + case rpki-extcommunity { + 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:rpki-extcommunity')"; + leaf rpki-extcommunity { + type enumeration { + enum "valid" { + value 0; + description + "Valid prefix"; + } + enum "notfound" { + value 1; + description + "Prefix not found"; + } + enum "invalid" { + value 2; + description + "Invalid prefix"; + } + } + } + } + case probability { 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:probability')"; leaf probability { |
