summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_ecommunity.c70
-rw-r--r--bgpd/bgp_ecommunity.h39
-rw-r--r--bgpd/bgp_route.c15
-rw-r--r--bgpd/bgp_routemap.c97
-rw-r--r--bgpd/bgp_routemap_nb.c7
-rw-r--r--bgpd/bgp_routemap_nb.h4
-rw-r--r--bgpd/bgp_routemap_nb_config.c54
-rw-r--r--doc/user/overview.rst4
-rw-r--r--doc/user/rpki.rst6
-rw-r--r--lib/routemap.h2
-rw-r--r--lib/routemap_cli.c5
-rw-r--r--yang/frr-bgp-route-map.yang29
12 files changed, 332 insertions, 0 deletions
diff --git a/bgpd/bgp_ecommunity.c b/bgpd/bgp_ecommunity.c
index 3f627521e..f57e9ae88 100644
--- a/bgpd/bgp_ecommunity.c
+++ b/bgpd/bgp_ecommunity.c
@@ -394,6 +394,44 @@ enum ecommunity_token {
ecommunity_token_val6,
};
+static const char *ecommunity_origin_validation_state2str(
+ enum ecommunity_origin_validation_states state)
+{
+ switch (state) {
+ case ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID:
+ return "valid";
+ case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND:
+ return "not-found";
+ case ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID:
+ return "invalid";
+ case ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED:
+ return "not-used";
+ }
+
+ return "ERROR";
+}
+
+static void ecommunity_origin_validation_state_str(char *buf, size_t bufsz,
+ uint8_t *ptr)
+{
+ /* Origin Validation State is encoded in the last octet
+ *
+ * 0 1 2 3
+ * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | 0x43 | 0x00 | Reserved |
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ * | Reserved |validationstate|
+ * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ */
+ uint8_t state = *(ptr + ECOMMUNITY_SIZE - 3);
+
+ snprintf(buf, bufsz, "OVS:%s",
+ ecommunity_origin_validation_state2str(state));
+
+ (void)ptr; /* consume value */
+}
+
static int ecommunity_encode_internal(uint8_t type, uint8_t sub_type,
int trans, as_t as,
struct in_addr *ip,
@@ -1172,6 +1210,13 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
ecom->disable_ieee_floating);
else
unk_ecom = 1;
+ } else if (type == ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS) {
+ sub_type = *pnt++;
+ if (sub_type == ECOMMUNITY_ORIGIN_VALIDATION_STATE)
+ ecommunity_origin_validation_state_str(
+ encbuf, sizeof(encbuf), pnt);
+ else
+ unk_ecom = 1;
} else {
sub_type = *pnt++;
unk_ecom = 1;
@@ -1541,6 +1586,31 @@ void bgp_remove_ecomm_from_aggregate_hash(struct bgp_aggregate *aggregate,
}
}
+struct ecommunity *
+ecommunity_add_origin_validation_state(enum rpki_states rpki_state,
+ struct ecommunity *old)
+{
+ struct ecommunity *new = NULL;
+ struct ecommunity ovs_ecomm = {0};
+ struct ecommunity_val ovs_eval;
+
+ encode_origin_validation_state(rpki_state, &ovs_eval);
+
+ if (old) {
+ new = ecommunity_dup(old);
+ ecommunity_add_val(new, &ovs_eval, true, true);
+ if (!old->refcnt)
+ ecommunity_free(&old);
+ } else {
+ ovs_ecomm.size = 1;
+ ovs_ecomm.unit_size = ECOMMUNITY_SIZE;
+ ovs_ecomm.val = (uint8_t *)&ovs_eval.val;
+ new = ecommunity_dup(&ovs_ecomm);
+ }
+
+ return new;
+}
+
/*
* return the BGP link bandwidth extended community, if present;
* the actual bandwidth is returned via param
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 84e310c3f..4d7d4234a 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -22,6 +22,7 @@
#define _QUAGGA_BGP_ECOMMUNITY_H
#include "bgpd/bgp_route.h"
+#include "bgpd/bgp_rpki.h"
#include "bgpd/bgpd.h"
/* Refer to rfc7153 for the IANA registry definitions. These are
@@ -51,6 +52,7 @@
/* Note: This really depends on the high-order octet. This means that
* multiple definitions for the same value are possible.
*/
+#define ECOMMUNITY_ORIGIN_VALIDATION_STATE 0x00
#define ECOMMUNITY_ROUTE_TARGET 0x02
#define ECOMMUNITY_SITE_ORIGIN 0x03
#define ECOMMUNITY_LINK_BANDWIDTH 0x04
@@ -100,6 +102,14 @@
#define ECOMMUNITY_SIZE 8
#define IPV6_ECOMMUNITY_SIZE 20
+/* Extended Community Origin Validation State */
+enum ecommunity_origin_validation_states {
+ ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID,
+ ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND,
+ ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID,
+ ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED
+};
+
/* Extended Communities type flag. */
#define ECOMMUNITY_FLAG_NON_TRANSITIVE 0x40
@@ -236,6 +246,32 @@ static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
eval->val[7] = bandwidth & 0xff;
}
+static inline void encode_origin_validation_state(enum rpki_states state,
+ struct ecommunity_val *eval)
+{
+ enum ecommunity_origin_validation_states ovs_state =
+ ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTUSED;
+
+ switch (state) {
+ case RPKI_VALID:
+ ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_VALID;
+ break;
+ case RPKI_NOTFOUND:
+ ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_NOTFOUND;
+ break;
+ case RPKI_INVALID:
+ ovs_state = ECOMMUNITY_ORIGIN_VALIDATION_STATE_INVALID;
+ break;
+ case RPKI_NOT_BEING_USED:
+ break;
+ }
+
+ memset(eval, 0, sizeof(*eval));
+ eval->val[0] = ECOMMUNITY_ENCODE_OPAQUE_NON_TRANS;
+ eval->val[1] = ECOMMUNITY_ORIGIN_VALIDATION_STATE;
+ eval->val[7] = ovs_state;
+}
+
extern void ecommunity_init(void);
extern void ecommunity_finish(void);
extern void ecommunity_free(struct ecommunity **);
@@ -314,4 +350,7 @@ static inline void ecommunity_strip_rts(struct ecommunity *ecom)
ecommunity_strip(ecom, ECOMMUNITY_ENCODE_IP, subtype);
ecommunity_strip(ecom, ECOMMUNITY_ENCODE_AS4, subtype);
}
+extern struct ecommunity *
+ecommunity_add_origin_validation_state(enum rpki_states rpki_state,
+ struct ecommunity *ecom);
#endif /* _QUAGGA_BGP_ECOMMUNITY_H */
diff --git a/bgpd/bgp_route.c b/bgpd/bgp_route.c
index 9eb7407af..162a7ed88 100644
--- a/bgpd/bgp_route.c
+++ b/bgpd/bgp_route.c
@@ -2486,6 +2486,21 @@ bool subgroup_announce_check(struct bgp_dest *dest, struct bgp_path_info *pi,
}
}
+ /* If this is an iBGP, send Origin Validation State (OVS)
+ * extended community (rfc8097).
+ */
+ if (peer->sort == BGP_PEER_IBGP) {
+ enum rpki_states rpki_state = RPKI_NOT_BEING_USED;
+
+ rpki_state = hook_call(bgp_rpki_prefix_status, peer, attr, p);
+
+ if (rpki_state != RPKI_NOT_BEING_USED)
+ bgp_attr_set_ecommunity(
+ attr, ecommunity_add_origin_validation_state(
+ rpki_state,
+ bgp_attr_get_ecommunity(attr)));
+ }
+
/*
* When the next hop is set to ourselves, if all multipaths have
* link-bandwidth announce the cumulative bandwidth as that makes
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 64c867f98..ded47028a 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -3791,6 +3791,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.
@@ -6792,6 +6859,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)
{
@@ -7030,6 +7125,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);
@@ -7047,6 +7143,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 2117334f7..c47c37dc6 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 cd7a70dbc..163e3b55c 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 585c2a3ff..b18cf9d4d 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/overview.rst b/doc/user/overview.rst
index 91ca1b89f..70bfee283 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -341,6 +341,8 @@ BGP
:t:`The Generalized TTL Security Mechanism (GTSM). V. Gill, J. Heasley, D. Meyer, P. Savola, C. Pingnataro. October 2007.`
- :rfc:`5575`
:t:`Dissemination of Flow Specification Rules. P. Marques, N. Sheth, R. Raszuk, B. Greene, J. Mauch, D. McPherson. August 2009`
+- :rfc:`5668`
+ :t:`4-Octet AS Specific BGP Extended Community. Y. Rekhter, S. Sangli, D. Tappan October 2009`
- :rfc:`6286`
:t:`Autonomous-System-Wide Unique BGP Identifier for BGP-4. E. Chen, J. Yuan, June 2011.`
- :rfc:`6608`
@@ -367,6 +369,8 @@ BGP
:t:`BLACKHOLE Community. T. King, C. Dietzel, J. Snijders, G. Doering, G. Hankins. Oct 2016.`
- :rfc:`8092`
:t:`BGP Large Communities Attribute. J. Heitz, Ed., J. Snijders, Ed, K. Patel, I. Bagdonas, N. Hilliard. February 2017`
+- :rfc:`8097`
+ :t:`BGP Prefix Origin Validation State Extended Community. P. Mohapatra, K. Patel, J. Scudder, D. Ward, R. Bush. March 2017`
- :rfc:`8195`
:t:`Use of BGP Large Communities. J. Snijders, J. Heasley, M. Schmidt, June 2017`
- :rfc:`8203`
diff --git a/doc/user/rpki.rst b/doc/user/rpki.rst
index cc0e7f70c..405353624 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 0152e820d..a36592585 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 42c7a05d1..6be5d15ec 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 fcfd14e4f..3f3d82921 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
@@ -436,6 +442,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 {