]> git.puffer.fish Git - matthieu/frr.git/commitdiff
bgpd: Add link bandwidth route-map commands
authorvivek <vivek@cumulusnetworks.com>
Tue, 24 Mar 2020 18:50:44 +0000 (11:50 -0700)
committervivek <vivek@cumulusnetworks.com>
Tue, 31 Mar 2020 03:12:31 +0000 (20:12 -0700)
Implement route-map option to set the link-bandwidth extended
community. The command is of the form:

set extcommunity bandwidth <(1-26214400)|cumulative|num-multipaths>
[non-transitive]

The options available are to specify the actual bandwidth value in
Mbps, base it on the cumulative downstream bandwidth or base it on
the number of multipaths. The last option is based on
https://tools.ietf.org/html/draft-mohanty-bess-ebgp-dmz. Further,
in alignment with the use case described in this IETF draft, the
extended community is encoded as transitive by default. There is an
option available to specify that it should be non-transitive.

The link-bandwidth itself is carried in bytes per second as specifed in
https://tools.ietf.org/html/draft-ietf-idr-link-bandwidth

Note: This commit only handles the processing for bandwidth specifed
as a value; subsequent commits will handle the processing of the other
options.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
Reviewed-by: Donald Sharp <sharpd@cumulusnetworks.com>
Reviewed-by: Don Slice <dslice@cumulusnetworks.com>
bgpd/bgp_ecommunity.h
bgpd/bgp_routemap.c

index 7d6745e912f32e343ea113e4a10e7cebb97a305b..d4f75d4a083146d700ba19b8b7efc947a70863f9 100644 (file)
@@ -151,6 +151,26 @@ static inline void encode_route_target_as4(as_t as, uint16_t val,
        eval->val[7] = val & 0xff;
 }
 
+/*
+ * Encode BGP Link Bandwidth extended community
+ *  bandwidth (bw) is in bytes-per-sec
+ */
+static inline void encode_lb_extcomm(as_t as, uint32_t bw, bool non_trans,
+                                    struct ecommunity_val *eval)
+{
+       memset(eval, 0, sizeof(*eval));
+       eval->val[0] = ECOMMUNITY_ENCODE_AS;
+       if (non_trans)
+               eval->val[0] |= ECOMMUNITY_FLAG_NON_TRANSITIVE;
+       eval->val[1] = ECOMMUNITY_LINK_BANDWIDTH;
+       eval->val[2] = (as >> 8) & 0xff;
+       eval->val[3] = as & 0xff;
+       eval->val[4] = (bw >> 24) & 0xff;
+       eval->val[5] = (bw >> 16) & 0xff;
+       eval->val[6] = (bw >> 8) & 0xff;
+       eval->val[7] = bw & 0xff;
+}
+
 extern void ecommunity_init(void);
 extern void ecommunity_finish(void);
 extern void ecommunity_free(struct ecommunity **);
index 2d92136450d9299d1e72ab97f797e9838133a153..2be49bbc00da7a987a3da77818365173f0022cea 100644 (file)
@@ -2531,6 +2531,106 @@ static const struct route_map_rule_cmd route_set_ecommunity_soo_cmd = {
        route_set_ecommunity_free,
 };
 
+/* `set extcommunity bandwidth' */
+
+struct rmap_ecomm_lb_set {
+       uint8_t lb_type;
+#define RMAP_ECOMM_LB_SET_VALUE 1
+#define RMAP_ECOMM_LB_SET_CUMUL 2
+#define RMAP_ECOMM_LB_SET_NUM_MPATH 3
+       bool non_trans;
+       uint32_t bw;
+};
+
+static enum route_map_cmd_result_t
+route_set_ecommunity_lb(void *rule, const struct prefix *prefix,
+                       route_map_object_t type, void *object)
+{
+       struct rmap_ecomm_lb_set *rels = rule;
+       struct bgp_path_info *path;
+       struct peer *peer;
+       struct ecommunity ecom_lb = {0};
+       struct ecommunity_val lb_eval;
+       uint32_t bw_bytes = 0;
+       struct ecommunity *new_ecom;
+       struct ecommunity *old_ecom;
+       as_t as;
+
+       if (type != RMAP_BGP)
+               return RMAP_OKAY;
+
+       path = object;
+       peer = path->peer;
+       if (!peer || !peer->bgp)
+               return RMAP_ERROR;
+
+       /* Build link bandwidth extended community */
+       as = (peer->bgp->as > BGP_AS_MAX) ? BGP_AS_TRANS : peer->bgp->as;
+       if (rels->lb_type == RMAP_ECOMM_LB_SET_VALUE)
+               bw_bytes = ((uint64_t)(rels->bw * 1000 * 1000))/8;
+
+       encode_lb_extcomm(as, bw_bytes, rels->non_trans, &lb_eval);
+       ecom_lb.size = 1;
+       ecom_lb.val = (uint8_t *)lb_eval.val;
+
+       /* add to route or merge with existing */
+       old_ecom = path->attr->ecommunity;
+       if (old_ecom) {
+               new_ecom = ecommunity_merge(ecommunity_dup(old_ecom), &ecom_lb);
+               if (!old_ecom->refcnt)
+                       ecommunity_free(&old_ecom);
+       } else
+               new_ecom = ecommunity_dup(&ecom_lb);
+
+       /* new_ecom will be intern()'d or attr_flush()'d in call stack */
+       path->attr->ecommunity = new_ecom;
+       path->attr->flag |= ATTR_FLAG_BIT(BGP_ATTR_EXT_COMMUNITIES);
+
+
+       return RMAP_OKAY;
+}
+
+static void *route_set_ecommunity_lb_compile(const char *arg)
+{
+       struct rmap_ecomm_lb_set *rels;
+       uint8_t lb_type;
+       uint32_t bw = 0;
+
+       if (strcmp(arg, "cumulative") == 0)
+               lb_type = RMAP_ECOMM_LB_SET_CUMUL;
+       else if (strcmp(arg, "num-multipaths") == 0)
+               lb_type = RMAP_ECOMM_LB_SET_NUM_MPATH;
+       else {
+               char *end = NULL;
+
+               bw = strtoul(arg, &end, 10);
+               if (*end != '\0')
+                       return NULL;
+               lb_type = RMAP_ECOMM_LB_SET_VALUE;
+       }
+
+       rels = XCALLOC(MTYPE_ROUTE_MAP_COMPILED,
+                      sizeof(struct rmap_ecomm_lb_set));
+       rels->lb_type = lb_type;
+       rels->bw = bw;
+       rels->non_trans = false;
+
+       return rels;
+}
+
+static void route_set_ecommunity_lb_free(void *rule)
+{
+       XFREE(MTYPE_ROUTE_MAP_COMPILED, rule);
+}
+
+/* Set community rule structure. */
+struct route_map_rule_cmd route_set_ecommunity_lb_cmd = {
+       "extcommunity bandwidth",
+       route_set_ecommunity_lb,
+       route_set_ecommunity_lb_compile,
+       route_set_ecommunity_lb_free,
+};
+
 /* `set origin ORIGIN' */
 
 /* For origin set. */
@@ -5004,6 +5104,53 @@ ALIAS (no_set_ecommunity_soo,
        "GP extended community attribute\n"
        "Site-of-Origin extended community\n")
 
+DEFUN (set_ecommunity_lb,
+       set_ecommunity_lb_cmd,
+       "set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]",
+       SET_STR
+       "BGP extended community attribute\n"
+       "Link bandwidth extended community\n"
+       "Bandwidth value in Mbps\n"
+       "Cumulative bandwidth of all multipaths (outbound-only)\n"
+       "Internally computed bandwidth based on number of multipaths (outbound-only)\n"
+       "Attribute is set as non-transitive\n")
+{
+       int idx_lb = 3;
+       int ret;
+       char *str;
+
+       str = argv_concat(argv, argc, idx_lb);
+       ret = generic_set_add(vty, VTY_GET_CONTEXT(route_map_index),
+                             "extcommunity bandwidth", str);
+       XFREE(MTYPE_TMP, str);
+       return ret;
+}
+
+
+DEFUN (no_set_ecommunity_lb,
+       no_set_ecommunity_lb_cmd,
+       "no set extcommunity bandwidth <(1-25600)|cumulative|num-multipaths> [non-transitive]",
+       NO_STR
+       SET_STR
+       "BGP extended community attribute\n"
+       "Link bandwidth extended community\n"
+       "Bandwidth value in Mbps\n"
+       "Cumulative bandwidth of all multipaths (outbound-only)\n"
+       "Internally computed bandwidth based on number of multipaths (outbound-only)\n"
+       "Attribute is set as non-transitive\n")
+{
+       return generic_set_delete(vty, VTY_GET_CONTEXT(route_map_index),
+                                 "extcommunity bandwidth", NULL);
+}
+
+ALIAS (no_set_ecommunity_lb,
+       no_set_ecommunity_lb_short_cmd,
+       "no set extcommunity bandwidth",
+       NO_STR
+       SET_STR
+       "BGP extended community attribute\n"
+       "Link bandwidth extended community\n")
+
 DEFUN (set_origin,
        set_origin_cmd,
        "set origin <egp|igp|incomplete>",
@@ -5549,6 +5696,7 @@ void bgp_route_map_init(void)
        route_map_install_set(&route_set_originator_id_cmd);
        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_tag_cmd);
        route_map_install_set(&route_set_label_index_cmd);
 
@@ -5632,6 +5780,9 @@ void bgp_route_map_init(void)
        install_element(RMAP_NODE, &set_ecommunity_soo_cmd);
        install_element(RMAP_NODE, &no_set_ecommunity_soo_cmd);
        install_element(RMAP_NODE, &no_set_ecommunity_soo_short_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);
 #ifdef KEEP_OLD_VPN_COMMANDS
        install_element(RMAP_NODE, &set_vpn_nexthop_cmd);
        install_element(RMAP_NODE, &no_set_vpn_nexthop_cmd);