]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: Code to handle BGP aggregate's e-communities.
authorNaveen Thanikachalam <nthanikachal@vmware.com>
Wed, 6 Feb 2019 14:31:37 +0000 (06:31 -0800)
committerNaveen Thanikachalam <nthanikachal@vmware.com>
Fri, 1 Mar 2019 04:22:41 +0000 (20:22 -0800)
With this commit:
1) The code to manage the extended-communities attribute of the routes that are
   aggregatable under a configured aggregate-address is introduced.
2) The code to compute the aggregate-route's extended-communities attribute is
   introduced.

Signed-off-by: NaveenThanikachalam <nthanikachal@vmware.com>
bgpd/bgp_ecommunity.c
bgpd/bgp_ecommunity.h

index ed0900a7218c93b14df79672bc6f52541631d6e7..fcfaa388d91d031c7b3bd47fdb721f75dd93f4db 100644 (file)
@@ -1026,3 +1026,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);
+               }
+       }
+}
index 519991da5a3ad55991c69400ed9ba140796647f8..62b213775391f64f599c94567a97423cacde894c 100644 (file)
@@ -21,6 +21,8 @@
 #ifndef _QUAGGA_BGP_ECOMMUNITY_H
 #define _QUAGGA_BGP_ECOMMUNITY_H
 
+#include "bgpd/bgp_route.h"
+
 /* High-order octet of the Extended Communities type field.  */
 #define ECOMMUNITY_ENCODE_AS                0x00
 #define ECOMMUNITY_ENCODE_IP                0x01
@@ -184,4 +186,12 @@ struct bgp_pbr_entry_action;
 extern int ecommunity_fill_pbr_action(struct ecommunity_val *ecom_eval,
                               struct bgp_pbr_entry_action *api);
 
+extern void bgp_compute_aggregate_ecommunity(
+                                       struct bgp_aggregate *aggregate,
+                                       struct ecommunity *ecommunity);
+extern void bgp_remove_ecommunity_from_aggregate(
+                                       struct bgp_aggregate *aggregate,
+                                       struct ecommunity *ecommunity);
+extern void bgp_aggr_ecommunity_remove(void *arg);
+
 #endif /* _QUAGGA_BGP_ECOMMUNITY_H */