]> git.puffer.fish Git - mirror/frr.git/commitdiff
bgpd: Prevent IPv6 routes received via a ibgp session with own ip as nexthop 4192/head
authorBiswajit Sadhu <sadhub@vmware.com>
Wed, 24 Apr 2019 07:40:01 +0000 (00:40 -0700)
committerBiswajit Sadhu <sadhub@vmware.com>
Wed, 24 Apr 2019 07:40:01 +0000 (00:40 -0700)
Prevent IPv6 routes received via a ibgp session with one of its own interface
ip as nexthop from getting installed in the BGP table.

Implemented IPV6 HASH table, where we need to add any ipv6 address as they
gets configured and delete them from the HASH table as the ipv6 addresses
get unconfigured. The above hash table is used to verify if any route learned
via BGP has nexthop which is equal to one of its its connected ipv6 interface.

Signed-off-by: Biswajit Sadhu sadhub@vmware.com
bgpd/bgp_nexthop.c
bgpd/bgp_nexthop.h
bgpd/bgp_route.c
bgpd/bgpd.c
bgpd/bgpd.h
lib/jhash.c
lib/jhash.h

index de97b73c7210ab41d1b534d4e33b4af72c1130b0..cf67a3623844ace27e57d9a9436cd65db4109209 100644 (file)
 
 DEFINE_MTYPE_STATIC(BGPD, MARTIAN_STRING, "BGP Martian Address Intf String");
 
+static void bgp_ipv6_address_add(struct bgp *bgp, struct connected *ifc,
+                                       struct prefix *p);
+static void bgp_ipv6_address_del(struct bgp *bgp, struct connected *ifc,
+                               struct prefix *p);
+
 char *bnc_str(struct bgp_nexthop_cache *bnc, char *buf, int size)
 {
        prefix2str(&(bnc->node->p), buf, size);
@@ -379,6 +384,8 @@ void bgp_connected_add(struct bgp *bgp, struct connected *ifc)
                if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
                        return;
 
+               bgp_ipv6_address_add(bgp, ifc, addr);
+
                rn = bgp_node_get(bgp->connected_table[AFI_IP6],
                                  (struct prefix *)&p);
 
@@ -419,6 +426,8 @@ void bgp_connected_delete(struct bgp *bgp, struct connected *ifc)
                if (IN6_IS_ADDR_LINKLOCAL(&p.u.prefix6))
                        return;
 
+               bgp_ipv6_address_del(bgp, ifc, addr);
+
                rn = bgp_node_lookup(bgp->connected_table[AFI_IP6],
                                     (struct prefix *)&p);
        }
@@ -772,3 +781,127 @@ void bgp_scan_finish(struct bgp *bgp)
                bgp->import_check_table[afi] = NULL;
        }
 }
+
+static void *bgp_ipv6_address_hash_alloc(void *p)
+{
+       const struct in6_addr *v6addr = (const struct in6_addr *)p;
+       struct bgp_addrv6 *addr;
+
+       addr = XMALLOC(MTYPE_BGP_ADDR, sizeof(struct bgp_addrv6));
+       addr->addrv6 = *v6addr;
+
+       addr->ifp_name_list = list_new();
+       addr->ifp_name_list->del = bgp_address_hash_string_del;
+
+       return addr;
+}
+
+static void bgp_ipv6_address_hash_free(void *data)
+{
+       struct bgp_addrv6 *v6addr = data;
+
+       list_delete(&v6addr->ifp_name_list);
+       XFREE(MTYPE_BGP_ADDR, v6addr);
+}
+
+static unsigned int bgp_ipv6_address_hash_key_make(void *p)
+{
+       const struct bgp_addrv6 *v6 = p;
+
+       return __ipv6_addr_jhash(&v6->addrv6, 0);
+}
+
+static bool bgp_ipv6_address_hash_cmp(const void *p1,
+                                       const void *p2)
+{
+       const struct bgp_addrv6 *addr1 = p1;
+       const struct bgp_addrv6 *addr2 = p2;
+
+       return(!memcmp(&addr1->addrv6, &addr2->addrv6,
+                               sizeof(struct in6_addr)));
+}
+
+void bgp_ipv6_address_init(struct bgp *bgp)
+{
+       bgp->ipv6_address_hash = hash_create(bgp_ipv6_address_hash_key_make,
+                                               bgp_ipv6_address_hash_cmp,
+                                               "BGP IPV6 Address Hash");
+}
+
+void bgp_ipv6_address_destroy(struct bgp *bgp)
+{
+       if (bgp->ipv6_address_hash == NULL)
+               return;
+       hash_clean(bgp->ipv6_address_hash,
+                       bgp_ipv6_address_hash_free);
+
+       hash_free(bgp->ipv6_address_hash);
+                       bgp->ipv6_address_hash = NULL;
+}
+
+static void bgp_ipv6_address_add(struct bgp *bgp, struct connected *ifc,
+                                       struct prefix *p)
+{
+       struct bgp_addrv6 tmp = {0};
+       struct bgp_addrv6 *addr = NULL;
+       struct listnode *node = NULL;
+       char *name = 0;
+
+       tmp.addrv6 = p->u.prefix6;
+
+       addr = hash_get(bgp->ipv6_address_hash, &tmp,
+                       bgp_ipv6_address_hash_alloc);
+       if (!addr)
+               return;
+
+       for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) {
+               if (strcmp(ifc->ifp->name, name) == 0)
+                       break;
+       }
+
+       if (!node) {
+               name = XSTRDUP(MTYPE_MARTIAN_STRING, ifc->ifp->name);
+               listnode_add(addr->ifp_name_list, name);
+       }
+}
+
+
+static void bgp_ipv6_address_del(struct bgp *bgp, struct connected *ifc,
+                               struct prefix *p)
+{
+       struct bgp_addrv6 tmp;
+       struct bgp_addrv6 *addr;
+       struct listnode *node;
+       char *name;
+
+
+       tmp.addrv6 = p->u.prefix6;
+
+       addr = hash_lookup(bgp->ipv6_address_hash, &tmp);
+       /* may have been deleted earlier by bgp_interface_down() */
+       if (addr == NULL)
+               return;
+
+       for (ALL_LIST_ELEMENTS_RO(addr->ifp_name_list, node, name)) {
+               if (strcmp(ifc->ifp->name, name) == 0)
+                       break;
+       }
+
+       if (node) {
+               list_delete_node(addr->ifp_name_list, node);
+               XFREE(MTYPE_MARTIAN_STRING, name);
+       }
+
+       if (addr->ifp_name_list->count == 0) {
+               hash_release(bgp->ipv6_address_hash, addr);
+               list_delete(&addr->ifp_name_list);
+               XFREE(MTYPE_BGP_ADDR, addr);
+       }
+}
+int bgp_nexthop_self_ipv6(struct bgp *bgp, struct in6_addr *addr)
+{
+       struct bgp_addrv6 tmp;
+
+       tmp.addrv6 = *addr;
+       return (!!hash_lookup(bgp->ipv6_address_hash, &tmp));
+}
index f06fae5706a9203a61f6b0e59946d1f016e5e461..c26295f810ae3b783be3efaab968bb8634febcfc 100644 (file)
@@ -74,6 +74,12 @@ struct tip_addr {
        int refcnt;
 };
 
+/* ipv6 connected address info structure */
+struct bgp_addrv6 {
+       struct in6_addr addrv6;
+       struct list *ifp_name_list;
+};
+
 extern void bgp_connected_add(struct bgp *bgp, struct connected *c);
 extern void bgp_connected_delete(struct bgp *bgp, struct connected *c);
 extern int bgp_subgrp_multiaccess_check_v4(struct in_addr nexthop,
@@ -96,4 +102,8 @@ extern void bgp_tip_hash_init(struct bgp *bgp);
 extern void bgp_tip_hash_destroy(struct bgp *bgp);
 
 extern void bgp_nexthop_show_address_hash(struct vty *vty, struct bgp *bgp);
+extern void bgp_ipv6_address_init(struct bgp *bgp);
+extern void bgp_ipv6_address_destroy(struct bgp *bgp);
+extern int bgp_nexthop_self_ipv6(struct bgp *bgp,
+       struct in6_addr *addr);
 #endif /* _QUAGGA_BGP_NEXTHOP_H */
index 7850666085cc74e5d1cb651efc4867d4680ef473..5fb6d70119da6700a883528d0ce61ffb5d491d1d 100644 (file)
@@ -2932,7 +2932,9 @@ static int bgp_update_martian_nexthop(struct bgp *bgp, afi_t afi, safi_t safi,
                        ret = (IN6_IS_ADDR_UNSPECIFIED(&attr->mp_nexthop_global)
                               || IN6_IS_ADDR_LOOPBACK(&attr->mp_nexthop_global)
                               || IN6_IS_ADDR_MULTICAST(
-                                         &attr->mp_nexthop_global));
+                                         &attr->mp_nexthop_global)
+                               || bgp_nexthop_self_ipv6(bgp,
+                                               &attr->mp_nexthop_global));
                        break;
 
                default:
index b2925cd5122849f17318af7fbca8ef1ae4f40254..730cc8bde7505beab672c7028b833b6c87c2de96 100644 (file)
@@ -3213,6 +3213,7 @@ int bgp_get(struct bgp **bgp_val, as_t *as, const char *name,
                bgp->vrf_id = vrf_generate_id();
        bgp_router_id_set(bgp, &bgp->router_id_zebra);
        bgp_address_init(bgp);
+       bgp_ipv6_address_init(bgp);
        bgp_tip_hash_init(bgp);
        bgp_scan_init(bgp);
        *bgp_val = bgp;
index b0f65675342d3d82896ea87f1bded9833e443592..cf03328f8c99613dd1b1d315c4ee8e9325541fd5 100644 (file)
@@ -393,6 +393,9 @@ struct bgp {
 
        struct hash *address_hash;
 
+       /* ipv6 connected address hash table pointer */
+       struct hash *ipv6_address_hash;
+
        /* DB for all local tunnel-ips - used mainly for martian checks
           Currently it only has all VxLan tunnel IPs*/
        struct hash *tip_hash;
index 0d561ef3a4f25db2b60725e9fdb63a0ff2b6af45..d0aff57d87873e1472e470bb4e4b4ef077fa4f11 100644 (file)
@@ -185,3 +185,18 @@ uint32_t jhash_1word(uint32_t a, uint32_t initval)
 {
        return jhash_3words(a, 0, 0, initval);
 }
+
+/* ipv6 hash function */
+uint32_t __ipv6_addr_jhash(const struct in6_addr *a, const uint32_t initval)
+{
+       uint32_t v = 0;
+       uint32_t y[4] = {0};
+
+       /* Since s6_addr32 is not available is few os like FreeBSD, NetBDS,
+        *  OMIBDS & OpenBDS. So recreating in uint32_t format.
+        */
+       memcpy(y, a->s6_addr, sizeof(struct in6_addr));
+       v = y[0] ^ y[1];
+
+       return jhash_3words(v, y[2], y[3], initval);
+}
index 977421495cefaf111461a588107f81529e3961f3..1b6f879369c203807cc0153fb83fc710aeec773d 100644 (file)
@@ -45,6 +45,8 @@ extern uint32_t jhash_3words(uint32_t a, uint32_t b, uint32_t c,
                             uint32_t initval);
 extern uint32_t jhash_2words(uint32_t a, uint32_t b, uint32_t initval);
 extern uint32_t jhash_1word(uint32_t a, uint32_t initval);
+extern uint32_t __ipv6_addr_jhash(const struct in6_addr *a,
+                               const uint32_t initval);
 
 #ifdef __cplusplus
 }