]> git.proxmox.com Git - mirror_frr.git/commitdiff
bgpd: Ability to add/update unique extended communities
authorvivek <vivek@cumulusnetworks.com>
Tue, 24 Mar 2020 20:50:20 +0000 (13:50 -0700)
committervivek <vivek@cumulusnetworks.com>
Tue, 31 Mar 2020 03:12:31 +0000 (20:12 -0700)
Certain extended communities cannot be repeated. An example is the
BGP link bandwidth extended community. Enhance the extended community
add function to ensure uniqueness, if requested.

Note: This commit does not change the lack of uniqueness for any of
the already-supported extended communities. Many of them such as the
BGP route target can obviously be present multiple times. Others like
the Router's MAC should most probably be present only once. The portions
of the code which add these may already be structured such that duplicates
do not arise.

Signed-off-by: Vivek Venkatraman <vivek@cumulusnetworks.com>
bgpd/bgp_attr_evpn.c
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h
bgpd/bgp_evpn.c
bgpd/bgp_pbr.c
bgpd/rfapi/rfapi.c
bgpd/rfapi/rfapi_import.c
bgpd/rfapi/vnc_export_bgp.c
bgpd/rfapi/vnc_import_bgp.c

index 7239ddef93686db0d65884aec9c5ec08a4d3bb24..65072088aeb92f42be3f979e8d2e4ef0a7b59b6e 100644 (file)
@@ -45,7 +45,7 @@ void bgp_add_routermac_ecom(struct attr *attr, struct ethaddr *routermac)
        memcpy(&routermac_ecom.val[2], routermac->octet, ETH_ALEN);
        if (!attr->ecommunity)
                attr->ecommunity = ecommunity_new();
-       ecommunity_add_val(attr->ecommunity, &routermac_ecom);
+       ecommunity_add_val(attr->ecommunity, &routermac_ecom, false, false);
        ecommunity_str(attr->ecommunity);
 }
 
index dd97a3d21377be997dceb0aa7c838c63e922fb55..0fbbc885b964d9029679e34da7c99e6cdbec26d7 100644 (file)
@@ -74,10 +74,16 @@ static void ecommunity_hash_free(struct ecommunity *ecom)
    Attribute structure.  When the value is already exists in the
    structure, we don't add the value.  Newly added value is sorted by
    numerical order.  When the value is added to the structure return 1
-   else return 0.  */
-bool ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval)
+   else return 0.
+   The additional parameters 'unique' and 'overwrite' ensure a particular
+   extended community (based on type and sub-type) is present only
+   once and whether the new value should replace what is existing or
+   not.
+*/
+bool ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval,
+                       bool unique, bool overwrite)
 {
-       int c;
+       int c, ins_idx;
 
        /* When this is fist value, just add it. */
        if (ecom->val == NULL) {
@@ -88,25 +94,45 @@ bool ecommunity_add_val(struct ecommunity *ecom, struct ecommunity_val *eval)
        }
 
        /* If the value already exists in the structure return 0.  */
+       /* check also if the extended community itself exists. */
        c = 0;
+       ins_idx = -1;
        for (uint8_t *p = ecom->val; c < ecom->size;
             p += ECOMMUNITY_SIZE, c++) {
+               if (unique) {
+                       if (p[0] == eval->val[0] &&
+                           p[1] == eval->val[1]) {
+                               if (overwrite) {
+                                       memcpy(p, eval->val, ECOMMUNITY_SIZE);
+                                       return 1;
+                               }
+                               return 0;
+                       }
+               }
                int ret = memcmp(p, eval->val, ECOMMUNITY_SIZE);
                if (ret == 0)
-                       return false;
-               else if (ret > 0)
-                       break;
+                       return 0;
+               if (ret > 0) {
+                       if (!unique)
+                               break;
+                       if (ins_idx == -1)
+                               ins_idx = c;
+               }
        }
 
+       if (ins_idx == -1)
+               ins_idx = c;
+
        /* Add the value to the structure with numerical sorting.  */
        ecom->size++;
        ecom->val = XREALLOC(MTYPE_ECOMMUNITY_VAL, ecom->val,
                             ecom->size * ECOMMUNITY_SIZE);
 
-       memmove(ecom->val + ((c + 1) * ECOMMUNITY_SIZE),
-               ecom->val + (c * ECOMMUNITY_SIZE),
-               (ecom->size - 1 - c) * ECOMMUNITY_SIZE);
-       memcpy(ecom->val + (c * ECOMMUNITY_SIZE), eval->val, ECOMMUNITY_SIZE);
+       memmove(ecom->val + ((ins_idx + 1) * ECOMMUNITY_SIZE),
+               ecom->val + (ins_idx * ECOMMUNITY_SIZE),
+               (ecom->size - 1 - ins_idx) * ECOMMUNITY_SIZE);
+       memcpy(ecom->val + (ins_idx * ECOMMUNITY_SIZE),
+              eval->val, ECOMMUNITY_SIZE);
 
        return true;
 }
@@ -128,7 +154,7 @@ struct ecommunity *ecommunity_uniq_sort(struct ecommunity *ecom)
        for (i = 0; i < ecom->size; i++) {
                eval = (struct ecommunity_val *)(ecom->val
                                                 + (i * ECOMMUNITY_SIZE));
-               ecommunity_add_val(new, eval);
+               ecommunity_add_val(new, eval, false, false);
        }
        return new;
 }
@@ -543,7 +569,7 @@ struct ecommunity *ecommunity_str2com(const char *str, int type,
                        if (ecom == NULL)
                                ecom = ecommunity_new();
                        eval.val[1] = type;
-                       ecommunity_add_val(ecom, &eval);
+                       ecommunity_add_val(ecom, &eval, false, false);
                        break;
                case ecommunity_token_unknown:
                default:
@@ -927,8 +953,8 @@ extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *ecom,
 /* remove ext. community matching type and subtype
  * return 1 on success ( removed ), 0 otherwise (not present)
  */
-extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
-                            uint8_t subtype)
+bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
+                     uint8_t subtype)
 {
        uint8_t *p, *q, *new;
        int c, found = 0;
index 3aeafb75eaf65352666d17812a4c3c9a2c304bf3..094c677ff98231d3c4540c556f32a4559af7dbd8 100644 (file)
@@ -206,11 +206,11 @@ extern char *ecommunity_str(struct ecommunity *);
 extern struct ecommunity_val *ecommunity_lookup(const struct ecommunity *,
                                                uint8_t, uint8_t);
 extern bool ecommunity_add_val(struct ecommunity *ecom,
-                              struct ecommunity_val *eval);
+                              struct ecommunity_val *eval,
+                              bool unique, bool overwrite);
 
 /* for vpn */
 extern struct ecommunity *ecommunity_new(void);
-extern bool ecommunity_add_val(struct ecommunity *, struct ecommunity_val *);
 extern bool ecommunity_strip(struct ecommunity *ecom, uint8_t type,
                             uint8_t subtype);
 extern struct ecommunity *ecommunity_new(void);
index a77a1e912e11b7588a694b39c14cad07b65ec00d..ed2b3c9235879c8707b64b03c2e2d417f0135040 100644 (file)
@@ -548,7 +548,7 @@ static void form_auto_rt(struct bgp *bgp, vni_t vni, struct list *rtl)
        encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
 
        ecomadd = ecommunity_new();
-       ecommunity_add_val(ecomadd, &eval);
+       ecommunity_add_val(ecomadd, &eval, false, false);
        for (ALL_LIST_ELEMENTS_RO(rtl, node, ecom))
                if (ecommunity_cmp(ecomadd, ecom))
                        ecom_found = true;
@@ -4633,7 +4633,7 @@ void evpn_rt_delete_auto(struct bgp *bgp, vni_t vni, struct list *rtl)
        encode_route_target_as((bgp->as & 0xFFFF), vni, &eval);
 
        ecom_auto = ecommunity_new();
-       ecommunity_add_val(ecom_auto, &eval);
+       ecommunity_add_val(ecom_auto, &eval, false, false);
        node_to_del = NULL;
 
        for (ALL_LIST_ELEMENTS(rtl, node, nnode, ecom)) {
index fd3fad63f51627aedfc24b915efb7db4df6d63b5..ab134b15c4694af314ceeb67ffac70f2c121fd6e 100644 (file)
@@ -738,7 +738,8 @@ int bgp_pbr_build_and_validate_entry(const struct prefix *p,
                                ecom_copy.val[0] &=
                                        ~ECOMMUNITY_ENCODE_TRANS_EXP;
                                ecom_copy.val[1] = ECOMMUNITY_ROUTE_TARGET;
-                               ecommunity_add_val(eckey, &ecom_copy);
+                               ecommunity_add_val(eckey, &ecom_copy,
+                                                  false, false);
 
                                api_action->action = ACTION_REDIRECT;
                                api_action->u.redirect_vrf =
index 435b61edf0c633eb3d8eed75b92e83a9d941bf2e..a0d8995a0f73134598031db447a9709c3b686553 100644 (file)
@@ -838,7 +838,7 @@ void add_vnc_route(struct rfapi_descriptor *rfd, /* cookie, VPN UN addr, peer */
                beec.val[1] = ECOMMUNITY_OPAQUE_SUBTYPE_ENCAP;
                beec.val[6] = ((TunnelType) >> 8) & 0xff;
                beec.val[7] = (TunnelType)&0xff;
-               ecommunity_add_val(attr.ecommunity, &beec);
+               ecommunity_add_val(attr.ecommunity, &beec, false, false);
        }
 
        /*
@@ -2650,7 +2650,8 @@ int rfapi_register(void *handle, struct rfapi_ip_prefix *prefix,
                                ecom_value.val[7] =
                                        (l2o->logical_net_id >> 0) & 0xff;
                                rtlist = ecommunity_new();
-                               ecommunity_add_val(rtlist, &ecom_value);
+                               ecommunity_add_val(rtlist, &ecom_value,
+                                                  false, false);
                        }
                        if (l2o->tag_id) {
                                as_t as = bgp->as;
@@ -2675,7 +2676,8 @@ int rfapi_register(void *handle, struct rfapi_ip_prefix *prefix,
                                ecom_value.val[7] = val & 0xff;
                                if (rtlist == NULL)
                                        rtlist = ecommunity_new();
-                               ecommunity_add_val(rtlist, &ecom_value);
+                               ecommunity_add_val(rtlist, &ecom_value,
+                                                  false, false);
                        }
                }
 
index d058fe3b28dd3575bbd45f1a734faaf6e22163d3..d261a3ee8836c6bb26a2788e2769902b760c69d1 100644 (file)
@@ -573,7 +573,7 @@ struct rfapi_import_table *rfapiMacImportTableGet(struct bgp *bgp, uint32_t lni)
                eval.val[7] = (lni >> 0) & 0xff;
 
                enew = ecommunity_new();
-               ecommunity_add_val(enew, &eval);
+               ecommunity_add_val(enew, &eval, false, false);
                it->rt_import_list = enew;
 
                for (afi = AFI_IP; afi < AFI_MAX; ++afi) {
index a7aa4c66fa3037b6753766d241038548382e51e1..bd3395b49f73e3bc84bfc3a18dceffd5c54608c6 100644 (file)
@@ -532,7 +532,7 @@ static struct ecommunity *vnc_route_origin_ecom(struct agg_node *rn)
                               &bpi->attr->mp_nexthop_global_in.s_addr, 4);
                        roec.val[6] = 0;
                        roec.val[7] = 0;
-                       ecommunity_add_val(new, &roec);
+                       ecommunity_add_val(new, &roec, false, false);
                        break;
                case AF_INET6:
                        /* No support for IPv6 addresses in extended communities
@@ -563,7 +563,7 @@ static struct ecommunity *vnc_route_origin_ecom_single(struct in_addr *origin)
 
        new = ecommunity_new();
        assert(new);
-       ecommunity_add_val(new, &roec);
+       ecommunity_add_val(new, &roec, false, false);
 
        if (!new->size) {
                ecommunity_free(&new);
index 915dfaabf2a553eaebe381ff1c5dc82511c853a4..ac5beed0e31abc25344211f192c4785a032acc22 100644 (file)
@@ -415,7 +415,7 @@ static int process_unicast_route(struct bgp *bgp,            /* in */
                localadmin = htons(hc->resolve_nve_roo_local_admin);
                memcpy(vnc_gateway_magic.val + 6, (char *)&localadmin, 2);
 
-               ecommunity_add_val(*ecom, &vnc_gateway_magic);
+               ecommunity_add_val(*ecom, &vnc_gateway_magic, false, false);
        }
 
        return 0;