/* `set extcommunity rt COMMUNITY' */
+struct rmap_ecom_set {
+ struct ecommunity *ecom;
+ bool none;
+};
+
/* For community set mechanism. Used by _rt and _soo. */
static enum route_map_cmd_result_t
route_set_ecommunity(void *rule, const struct prefix *prefix, void *object)
{
- struct ecommunity *ecom;
+ struct rmap_ecom_set *rcs;
struct ecommunity *new_ecom;
struct ecommunity *old_ecom;
struct bgp_path_info *path;
+ struct attr *attr;
- ecom = rule;
+ rcs = rule;
path = object;
+ attr = path->attr;
- if (!ecom)
+ if (rcs->none) {
+ attr->flag &= ~(ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES));
+ attr->ecommunity = NULL;
+ return RMAP_OKAY;
+ }
+
+ if (!rcs->ecom)
return RMAP_OKAY;
/* We assume additive for Extended Community. */
old_ecom = path->attr->ecommunity;
if (old_ecom) {
- new_ecom = ecommunity_merge(ecommunity_dup(old_ecom), ecom);
+ new_ecom =
+ ecommunity_merge(ecommunity_dup(old_ecom), rcs->ecom);
/* old_ecom->refcnt = 1 => owned elsewhere, e.g.
* bgp_update_receive()
if (!old_ecom->refcnt)
ecommunity_free(&old_ecom);
} else
- new_ecom = ecommunity_dup(ecom);
+ new_ecom = ecommunity_dup(rcs->ecom);
/* will be intern()'d or attr_flush()'d by bgp_update_main() */
path->attr->ecommunity = new_ecom;
return RMAP_OKAY;
}
-/* Compile function for set community. */
+static void *route_set_ecommunity_none_compile(const char *arg)
+{
+ struct rmap_ecom_set *rcs;
+ bool none = false;
+
+ if (strncmp(arg, "none", 4) == 0)
+ none = true;
+
+ rcs = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_ecom_set));
+ rcs->ecom = NULL;
+ rcs->none = none;
+
+ return rcs;
+}
+
static void *route_set_ecommunity_rt_compile(const char *arg)
{
+ struct rmap_ecom_set *rcs;
struct ecommunity *ecom;
ecom = ecommunity_str2com(arg, ECOMMUNITY_ROUTE_TARGET, 0);
if (!ecom)
return NULL;
- return ecommunity_intern(ecom);
+
+ rcs = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_ecom_set));
+ rcs->ecom = ecommunity_intern(ecom);
+ rcs->none = false;
+
+ return rcs;
}
/* Free function for set community. Used by _rt and _soo */
static void route_set_ecommunity_free(void *rule)
{
- struct ecommunity *ecom = rule;
- ecommunity_unintern(&ecom);
+ struct rmap_ecom_set *rcs = rule;
+
+ if (rcs->ecom)
+ ecommunity_unintern(&rcs->ecom);
+
+ XFREE(MTYPE_ROUTE_MAP_COMPILED, rcs);
}
+static const struct route_map_rule_cmd route_set_ecommunity_none_cmd = {
+ "extcommunity",
+ route_set_ecommunity,
+ route_set_ecommunity_none_compile,
+ route_set_ecommunity_free,
+};
+
/* Set community rule structure. */
static const struct route_map_rule_cmd route_set_ecommunity_rt_cmd = {
"extcommunity rt",
/* Compile function for set community. */
static void *route_set_ecommunity_soo_compile(const char *arg)
{
+ struct rmap_ecom_set *rcs;
struct ecommunity *ecom;
ecom = ecommunity_str2com(arg, ECOMMUNITY_SITE_ORIGIN, 0);
if (!ecom)
return NULL;
- return ecommunity_intern(ecom);
+ rcs = XCALLOC(MTYPE_ROUTE_MAP_COMPILED, sizeof(struct rmap_ecom_set));
+ rcs->ecom = ecommunity_intern(ecom);
+ rcs->none = false;
+
+ return rcs;
}
/* Set community rule structure. */
"GP extended community attribute\n"
"Site-of-Origin extended community\n")
+DEFUN_YANG(set_ecommunity_none, set_ecommunity_none_cmd,
+ "set extcommunity none",
+ SET_STR
+ "BGP extended community attribute\n"
+ "No extended community attribute\n")
+{
+ const char *xpath =
+ "./set-action[action='frr-bgp-route-map:set-extcommunity-none']";
+ char xpath_value[XPATH_MAXLEN];
+
+ nb_cli_enqueue_change(vty, xpath, NB_OP_CREATE, NULL);
+
+ snprintf(xpath_value, sizeof(xpath_value),
+ "%s/rmap-set-action/frr-bgp-route-map:extcommunity-none",
+ xpath);
+ nb_cli_enqueue_change(vty, xpath_value, NB_OP_MODIFY, "true");
+ return nb_cli_apply_changes(vty, NULL);
+}
+
+DEFUN_YANG(no_set_ecommunity_none, no_set_ecommunity_none_cmd,
+ "no set extcommunity none",
+ NO_STR SET_STR
+ "BGP extended community attribute\n"
+ "No extended community attribute\n")
+{
+ const char *xpath =
+ "./set-action[action='frr-bgp-route-map:set-extcommunity-none']";
+ nb_cli_enqueue_change(vty, xpath, NB_OP_DESTROY, NULL);
+ return nb_cli_apply_changes(vty, NULL);
+}
+
DEFUN_YANG (set_ecommunity_lb,
set_ecommunity_lb_cmd,
"set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]",
route_map_install_set(&route_set_ecommunity_rt_cmd);
route_map_install_set(&route_set_ecommunity_soo_cmd);
route_map_install_set(&route_set_ecommunity_lb_cmd);
+ route_map_install_set(&route_set_ecommunity_none_cmd);
route_map_install_set(&route_set_tag_cmd);
route_map_install_set(&route_set_label_index_cmd);
install_element(RMAP_NODE, &set_ecommunity_lb_cmd);
install_element(RMAP_NODE, &no_set_ecommunity_lb_cmd);
install_element(RMAP_NODE, &no_set_ecommunity_lb_short_cmd);
+ install_element(RMAP_NODE, &set_ecommunity_none_cmd);
+ install_element(RMAP_NODE, &no_set_ecommunity_none_cmd);
#ifdef KEEP_OLD_VPN_COMMANDS
install_element(RMAP_NODE, &set_vpn_nexthop_cmd);
install_element(RMAP_NODE, &no_set_vpn_nexthop_cmd);
return lib_route_map_entry_set_destroy(args);
}
+/*
+ * XPath:
+ * /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-none
+ */
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_modify(
+ struct nb_cb_modify_args *args)
+{
+ struct routemap_hook_context *rhc;
+ bool none = false;
+ int rv;
+
+ 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);
+ none = yang_dnode_get_bool(args->dnode, NULL);
+
+ /* Set destroy information. */
+ rhc->rhc_shook = generic_set_delete;
+ rhc->rhc_rule = "extcommunity";
+ rhc->rhc_event = RMAP_EVENT_SET_DELETED;
+
+ if (none) {
+ rv = generic_set_add(rhc->rhc_rmi, "extcommunity",
+ "none", args->errmsg,
+ args->errmsg_len);
+ if (rv != CMD_SUCCESS) {
+ rhc->rhc_shook = NULL;
+ return NB_ERR_INCONSISTENCY;
+ }
+ return NB_OK;
+ }
+
+ return NB_ERR_INCONSISTENCY;
+ }
+
+ return NB_OK;
+}
+
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_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_set_destroy(args);
+ }
+
+ return NB_OK;
+}
+
/*
* XPath:
* /frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:evpn-gateway-ip-ipv4