]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: Add an ability to set extcommunity to none in route-maps
authorDonatas Abraitis <donatas.abraitis@gmail.com>
Mon, 2 Aug 2021 19:27:55 +0000 (22:27 +0300)
committerDonatas Abraitis <donatas.abraitis@gmail.com>
Wed, 18 Aug 2021 11:14:52 +0000 (14:14 +0300)
Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
bgpd/bgp_routemap.c
bgpd/bgp_routemap_nb.c
bgpd/bgp_routemap_nb.h
bgpd/bgp_routemap_nb_config.c
lib/routemap.h
lib/routemap_cli.c
yang/frr-bgp-route-map.yang

index 5e566f360ae9eef57ec9cc5e2d2a705bc3957632..4d23abc71aaccfd2c32b5159730a57e3d87d7691 100644 (file)
@@ -2518,26 +2518,40 @@ static const struct route_map_rule_cmd route_set_community_delete_cmd = {
 
 /* `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()
@@ -2546,7 +2560,7 @@ route_set_ecommunity(void *rule, const struct prefix *prefix, void *object)
                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;
@@ -2556,24 +2570,55 @@ route_set_ecommunity(void *rule, const struct prefix *prefix, void *object)
        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",
@@ -2587,13 +2632,18 @@ static const struct route_map_rule_cmd route_set_ecommunity_rt_cmd = {
 /* 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. */
@@ -5749,6 +5799,37 @@ ALIAS_YANG (no_set_ecommunity_soo,
             "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]",
@@ -6453,6 +6534,7 @@ void bgp_route_map_init(void)
        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);
 
@@ -6545,6 +6627,8 @@ void bgp_route_map_init(void)
        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);
index 92164269682aa3f2e4fcbfe357bb31ff7c512c75..caf1553ec135e68537beafecf71d325105b7eb03 100644 (file)
@@ -351,6 +351,13 @@ const struct frr_yang_module_info frr_bgp_route_map_info = {
                                .destroy = lib_route_map_entry_set_action_rmap_set_action_comm_list_name_destroy,
                        }
                },
+               {
+                       .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-none",
+                       .cbs = {
+                               .modify = lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_modify,
+                               .destroy = lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_destroy,
+                       }
+               },
                {
                        .xpath = "/frr-route-map:lib/route-map/entry/set-action/rmap-set-action/frr-bgp-route-map:extcommunity-lb",
                        .cbs = {
index 069345b1a48d9d6f6ebf1e6481a0acb4f154e63c..e0b3a6926f77e2ab74bebc4d1fbe509f6097cf7d 100644 (file)
@@ -134,6 +134,10 @@ int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_mod
 int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_bandwidth_destroy(struct nb_cb_destroy_args *args);
 int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_modify(struct nb_cb_modify_args *args);
 int lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_specific_destroy(struct nb_cb_destroy_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_modify(
+       struct nb_cb_modify_args *args);
+int lib_route_map_entry_set_action_rmap_set_action_extcommunity_none_destroy(
+       struct nb_cb_destroy_args *args);
 int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_modify(
        struct nb_cb_modify_args *args);
 int lib_route_map_entry_set_action_rmap_set_action_evpn_gateway_ip_ipv4_destroy(
index 398e7323db8b4f9598f66dc0ad5aa13216bffebd..a62dc1dfc3d1b4fdb5b7bf28414cab45b75983ac 100644 (file)
@@ -2689,6 +2689,64 @@ lib_route_map_entry_set_action_rmap_set_action_extcommunity_lb_two_octet_as_spec
        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
index 444508500160d0ee81302c2b706b00155cb2a0ac..4c7e46a6c7f552f6c65dac01a9c4008d8d5b6528 100644 (file)
@@ -350,6 +350,8 @@ DECLARE_QOBJ_TYPE(route_map);
        (strmatch(A, "frr-bgp-route-map:set-large-community"))
 #define IS_SET_COMMUNITY(A)                                                    \
        (strmatch(A, "frr-bgp-route-map:set-community"))
+#define IS_SET_EXTCOMMUNITY_NONE(A)                                            \
+       (strmatch(A, "frr-bgp-route-map:set-extcommunity-none"))
 #define IS_SET_EXTCOMMUNITY_RT(A)                                              \
        (strmatch(A, "frr-bgp-route-map:set-extcommunity-rt"))
 #define IS_SET_EXTCOMMUNITY_SOO(A)                                             \
index 77455d991ab98aad7857fdfe93ed1a91d6d072bb..b9939c34c5f725ff32d1c443c8cad3dade8a7857 100644 (file)
@@ -1223,6 +1223,11 @@ void route_map_action_show(struct vty *vty, struct lyd_node *dnode,
                        strlcat(str, " non-transitive", sizeof(str));
 
                vty_out(vty, " set extcommunity bandwidth %s\n", str);
+       } else if (IS_SET_EXTCOMMUNITY_NONE(action)) {
+               if (yang_dnode_get_bool(
+                           dnode,
+                           "./rmap-set-action/frr-bgp-route-map:extcommunity-none"))
+                       vty_out(vty, " set extcommunity none\n");
        } else if (IS_SET_AGGREGATOR(action)) {
                vty_out(vty, " set aggregator as %s %s\n",
                        yang_dnode_get_string(
index e11883a803470e3a1d05a58ed0da45dc31fecb6f..9bd26043a7e95b4951758731d67df69bd710d60f 100644 (file)
@@ -168,6 +168,12 @@ module frr-bgp-route-map {
       "Set BGP administrative distance to use";
   }
 
+  identity set-extcommunity-none {
+    base frr-route-map:rmap-set-type;
+    description
+      "Set BGP extended community attribute";
+  }
+
   identity set-extcommunity-rt {
     base frr-route-map:rmap-set-type;
     description
@@ -585,6 +591,16 @@ module frr-bgp-route-map {
       }
     }
 
+    case extcommunity-none {
+      when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-none')";
+      description
+        "Value of the BGP extended community attribute";
+      leaf extcommunity-none {
+        type boolean;
+        description "No extended community attribute";
+      }
+    }
+
     case extcommunity-rt {
       when "derived-from-or-self(/frr-route-map:lib/frr-route-map:route-map/frr-route-map:entry/frr-route-map:set-action/frr-route-map:action, 'frr-bgp-route-map:set-extcommunity-rt')";
       description