summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvivek <vivek@cumulusnetworks.com>2020-03-24 11:50:44 -0700
committervivek <vivek@cumulusnetworks.com>2020-03-30 20:12:31 -0700
commitca9ac3effc47dd93352de9f98cab5c016fbfe512 (patch)
tree702a4049c2fb0373bfbfdb8a1555b8e90eb56873
parent650b05119d2f14f146ccb46b504b48b6dc580f9f (diff)
bgpd: Add link bandwidth route-map commands
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>
-rw-r--r--bgpd/bgp_ecommunity.h20
-rw-r--r--bgpd/bgp_routemap.c151
2 files changed, 171 insertions, 0 deletions
diff --git a/bgpd/bgp_ecommunity.h b/bgpd/bgp_ecommunity.h
index 7d6745e912..d4f75d4a08 100644
--- a/bgpd/bgp_ecommunity.h
+++ b/bgpd/bgp_ecommunity.h
@@ -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 **);
diff --git a/bgpd/bgp_routemap.c b/bgpd/bgp_routemap.c
index 2d92136450..2be49bbc00 100644
--- a/bgpd/bgp_routemap.c
+++ b/bgpd/bgp_routemap.c
@@ -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);