]> git.proxmox.com Git - mirror_frr.git/blobdiff - bgpd/bgp_ecommunity.c
lib: hashing functions should take const arguments
[mirror_frr.git] / bgpd / bgp_ecommunity.c
index 20f5e15d6943243bede138153551d16d53f8f262..76bd0e815e6771cc81bfe8ea3c59b3b8da6efa2f 100644 (file)
@@ -48,8 +48,7 @@ static struct hash *ecomhash;
 /* Allocate a new ecommunities.  */
 struct ecommunity *ecommunity_new(void)
 {
-       return (struct ecommunity *)XCALLOC(MTYPE_ECOMMUNITY,
-                                           sizeof(struct ecommunity));
+       return XCALLOC(MTYPE_ECOMMUNITY, sizeof(struct ecommunity));
 }
 
 void ecommunity_strfree(char **s)
@@ -60,12 +59,9 @@ void ecommunity_strfree(char **s)
 /* Allocate ecommunities.  */
 void ecommunity_free(struct ecommunity **ecom)
 {
-       if ((*ecom)->val)
-               XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
-       if ((*ecom)->str)
-               XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
+       XFREE(MTYPE_ECOMMUNITY_VAL, (*ecom)->val);
+       XFREE(MTYPE_ECOMMUNITY_STR, (*ecom)->str);
        XFREE(MTYPE_ECOMMUNITY, *ecom);
-       ecom = NULL;
 }
 
 static void ecommunity_hash_free(struct ecommunity *ecom)
@@ -245,7 +241,7 @@ void ecommunity_unintern(struct ecommunity **ecom)
 }
 
 /* Utinity function to make hash key.  */
-unsigned int ecommunity_hash_make(void *arg)
+unsigned int ecommunity_hash_make(const void *arg)
 {
        const struct ecommunity *ecom = arg;
        int size = ecom->size * ECOMMUNITY_SIZE;
@@ -254,16 +250,16 @@ unsigned int ecommunity_hash_make(void *arg)
 }
 
 /* Compare two Extended Communities Attribute structure.  */
-int ecommunity_cmp(const void *arg1, const void *arg2)
+bool ecommunity_cmp(const void *arg1, const void *arg2)
 {
        const struct ecommunity *ecom1 = arg1;
        const struct ecommunity *ecom2 = arg2;
 
        if (ecom1 == NULL && ecom2 == NULL)
-               return 1;
+               return true;
 
        if (ecom1 == NULL || ecom2 == NULL)
-               return 0;
+               return false;
 
        return (ecom1->size == ecom2->size
                && memcmp(ecom1->val, ecom2->val, ecom1->size * ECOMMUNITY_SIZE)
@@ -689,9 +685,23 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                        /* Low-order octet of type. */
                        sub_type = *pnt++;
                        if (sub_type != ECOMMUNITY_ROUTE_TARGET
-                           && sub_type != ECOMMUNITY_SITE_ORIGIN)
-                               unk_ecom = 1;
-                       else
+                           && sub_type != ECOMMUNITY_SITE_ORIGIN) {
+                               if (sub_type ==
+                                   ECOMMUNITY_FLOWSPEC_REDIRECT_IPV4 &&
+                                   type == ECOMMUNITY_ENCODE_IP) {
+                                       struct in_addr *ipv4 =
+                                               (struct in_addr *)pnt;
+                                       char ipv4str[INET_ADDRSTRLEN];
+
+                                       inet_ntop(AF_INET, ipv4,
+                                                 ipv4str,
+                                                 INET_ADDRSTRLEN);
+                                       len = sprintf(str_buf + str_pnt,
+                                                     "NH:%s:%d",
+                                                     ipv4str, pnt[5]);
+                               } else
+                                       unk_ecom = 1;
+                       } else
                                len = ecommunity_rt_soo_str(str_buf + str_pnt,
                                                            pnt, type, sub_type,
                                                            format);
@@ -740,6 +750,13 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                else
                                        len = sprintf(str_buf + str_pnt,
                                                      "MM:%u", seqnum);
+                       } else if (*pnt == ECOMMUNITY_EVPN_SUBTYPE_ND) {
+                               uint8_t flags = *++pnt;
+
+                               if (flags
+                                   & ECOMMUNITY_EVPN_SUBTYPE_ND_ROUTER_FLAG)
+                                       len = sprintf(str_buf + str_pnt,
+                                                     "ND:Router Flag");
                        } else
                                unk_ecom = 1;
                } else if (type == ECOMMUNITY_ENCODE_REDIRECT_IP_NH) {
@@ -801,6 +818,21 @@ char *ecommunity_ecom2str(struct ecommunity *ecom, int format, int filter)
                                len = sprintf(
                                        str_buf + str_pnt,
                                        "FS:marking %u", *(pnt+5));
+                       } else if (*pnt
+                                  == ECOMMUNITY_EVPN_SUBTYPE_ES_IMPORT_RT) {
+                               struct ethaddr mac;
+
+                               pnt++;
+                               memcpy(&mac, pnt, ETH_ALEN);
+                               len = sprintf(
+                                       str_buf + str_pnt,
+                                       "ES-Import-Rt:%02x:%02x:%02x:%02x:%02x:%02x",
+                                       (uint8_t)mac.octet[0],
+                                       (uint8_t)mac.octet[1],
+                                       (uint8_t)mac.octet[2],
+                                       (uint8_t)mac.octet[3],
+                                       (uint8_t)mac.octet[4],
+                                       (uint8_t)mac.octet[5]);
                        } else
                                unk_ecom = 1;
                } else {
@@ -991,3 +1023,112 @@ int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
                return -1;
        return 0;
 }
+
+static struct ecommunity *bgp_aggr_ecommunity_lookup(
+                                               struct bgp_aggregate *aggregate,
+                                               struct ecommunity *ecommunity)
+{
+       return hash_lookup(aggregate->ecommunity_hash, ecommunity);
+}
+
+static void *bgp_aggr_ecommunty_hash_alloc(void *p)
+{
+       struct ecommunity *ref = (struct ecommunity *)p;
+       struct ecommunity *ecommunity = NULL;
+
+       ecommunity = ecommunity_dup(ref);
+       return ecommunity;
+}
+
+static void bgp_aggr_ecommunity_prepare(struct hash_backet *hb, void *arg)
+{
+       struct ecommunity *ecommerge = NULL;
+       struct ecommunity *hb_ecommunity = hb->data;
+       struct ecommunity **aggr_ecommunity = arg;
+
+       if (*aggr_ecommunity) {
+               ecommerge = ecommunity_merge(*aggr_ecommunity, hb_ecommunity);
+               *aggr_ecommunity = ecommunity_uniq_sort(ecommerge);
+               ecommunity_free(&ecommerge);
+       } else
+               *aggr_ecommunity = ecommunity_dup(hb_ecommunity);
+}
+
+void bgp_aggr_ecommunity_remove(void *arg)
+{
+       struct ecommunity *ecommunity = arg;
+
+       ecommunity_free(&ecommunity);
+}
+
+void bgp_compute_aggregate_ecommunity(struct bgp_aggregate *aggregate,
+                                     struct ecommunity *ecommunity)
+{
+       struct ecommunity *aggr_ecommunity = NULL;
+
+       if ((aggregate == NULL) || (ecommunity == NULL))
+               return;
+
+       /* Create hash if not already created.
+        */
+       if (aggregate->ecommunity_hash == NULL)
+               aggregate->ecommunity_hash = hash_create(
+                                       ecommunity_hash_make, ecommunity_cmp,
+                                       "BGP Aggregator ecommunity hash");
+
+       aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
+       if (aggr_ecommunity == NULL) {
+               /* Insert ecommunity into hash.
+                */
+               aggr_ecommunity = hash_get(aggregate->ecommunity_hash,
+                                          ecommunity,
+                                          bgp_aggr_ecommunty_hash_alloc);
+
+               /* Re-compute aggregate's ecommunity.
+                */
+               if (aggregate->ecommunity)
+                       ecommunity_free(&aggregate->ecommunity);
+
+               hash_iterate(aggregate->ecommunity_hash,
+                            bgp_aggr_ecommunity_prepare,
+                            &aggregate->ecommunity);
+       }
+
+       /* Increment refernce counter.
+        */
+       aggr_ecommunity->refcnt++;
+}
+
+void bgp_remove_ecommunity_from_aggregate(struct bgp_aggregate *aggregate,
+                                         struct ecommunity *ecommunity)
+{
+       struct ecommunity *aggr_ecommunity = NULL;
+       struct ecommunity *ret_ecomm = NULL;
+
+       if ((aggregate == NULL) || (ecommunity == NULL))
+               return;
+
+       if (aggregate->ecommunity_hash == NULL)
+               return;
+
+       /* Look-up the ecommunity in the hash.
+        */
+       aggr_ecommunity = bgp_aggr_ecommunity_lookup(aggregate, ecommunity);
+       if (aggr_ecommunity) {
+               aggr_ecommunity->refcnt--;
+
+               if (aggr_ecommunity->refcnt == 0) {
+                       ret_ecomm = hash_release(aggregate->ecommunity_hash,
+                                                aggr_ecommunity);
+                       ecommunity_free(&ret_ecomm);
+
+                       ecommunity_free(&aggregate->ecommunity);
+
+                       /* Compute aggregate's ecommunity.
+                        */
+                       hash_iterate(aggregate->ecommunity_hash,
+                                    bgp_aggr_ecommunity_prepare,
+                                    &aggregate->ecommunity);
+               }
+       }
+}