From 6a69ac51380d1ae71ef92b5ac4772f7eeae22ff3 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 12 Oct 2018 10:08:28 -0400 Subject: [PATCH] bgpd: Add code to track the addition/removal of mac addresses When a mac address is added/changed/deleted track it. Signed-off-by: Donald Sharp --- bgpd/bgp_mac.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++ bgpd/bgp_mac.h | 8 +++ bgpd/bgp_zebra.c | 9 ++++ 3 files changed, 149 insertions(+) diff --git a/bgpd/bgp_mac.c b/bgpd/bgp_mac.c index c5d5d20fc5..2af03e2166 100644 --- a/bgpd/bgp_mac.c +++ b/bgpd/bgp_mac.c @@ -32,6 +32,7 @@ #include "bgpd/bgp_debug.h" DEFINE_MTYPE_STATIC(BGPD, BSM, "Mac Hash Entry"); +DEFINE_MTYPE_STATIC(BGPD, BSM_STRING, "Mac Hash Entry Interface String"); struct bgp_self_mac { struct ethaddr macaddr; @@ -76,6 +77,137 @@ void bgp_mac_finish(void) hash_free(bm->self_mac_hash); } +static void bgp_mac_hash_interface_string_del(void *val) +{ + char *data = val; + + XFREE(MTYPE_BSM_STRING, data); +} + +static void *bgp_mac_hash_alloc(void *p) +{ + const struct bgp_self_mac *orig = p; + struct bgp_self_mac *bsm; + + bsm = XCALLOC(MTYPE_BSM, sizeof(struct bgp_self_mac)); + memcpy(&bsm->macaddr, &orig->macaddr, ETH_ALEN); + + bsm->ifp_list = list_new(); + bsm->ifp_list->del = bgp_mac_hash_interface_string_del; + + return bsm; +} + +struct bgp_mac_find_internal { + struct bgp_self_mac *bsm; + const char *ifname; +}; + +static void bgp_mac_find_ifp_internal(struct hash_backet *backet, void *arg) +{ + struct bgp_mac_find_internal *bmfi = arg; + struct bgp_self_mac *bsm = backet->data; + struct listnode *node; + char *name; + + for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name)) { + if (strcmp(name, bmfi->ifname) == 0) { + bmfi->bsm = bsm; + return; + } + } +} + +static struct bgp_self_mac *bgp_mac_find_interface_name(const char *ifname) +{ + struct bgp_mac_find_internal bmfi; + + bmfi.bsm = NULL; + bmfi.ifname = ifname; + hash_iterate(bm->self_mac_hash, bgp_mac_find_ifp_internal, &bmfi); + + return bmfi.bsm; +} + +static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname) +{ + struct listnode *node; + char *name; + + for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name)) { + if (strcmp(name, ifname) == 0) + break; + } + + if (node) { + list_delete_node(bsm->ifp_list, node); + XFREE(MTYPE_BSM_STRING, name); + } + + if (bsm->ifp_list->count == 0) { + hash_release(bm->self_mac_hash, bsm); + list_delete(&bsm->ifp_list); + XFREE(MTYPE_BSM, bsm); + + /* Code to rescan tables */ + } +} + +void bgp_mac_add_mac_entry(struct interface *ifp) +{ + struct bgp_self_mac lookup; + struct bgp_self_mac *bsm; + struct bgp_self_mac *old_bsm; + char *ifname; + + memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN); + bsm = hash_get(bm->self_mac_hash, &lookup, bgp_mac_hash_alloc); + + /* + * Does this happen to be a move + */ + old_bsm = bgp_mac_find_interface_name(ifp->name); + ifname = XSTRDUP(MTYPE_BSM_STRING, ifp->name); + + if (bsm->ifp_list->count == 0) { + + listnode_add(bsm->ifp_list, ifname); + if (old_bsm) + bgp_mac_remove_ifp_internal(old_bsm, ifname); + } else { + /* + * If old mac address is the same as the new, + * then there is nothing to do here + */ + if (old_bsm == bsm) + return; + + if (old_bsm) + bgp_mac_remove_ifp_internal(old_bsm, ifp->name); + + listnode_add(bsm->ifp_list, ifname); + } + + /* Code to rescan */ +} + +void bgp_mac_del_mac_entry(struct interface *ifp) +{ + struct bgp_self_mac lookup; + struct bgp_self_mac *bsm; + + memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN); + bsm = hash_lookup(bm->self_mac_hash, &lookup); + if (!bsm) + return; + + /* + * Write code to allow old mac address to no-longer + * win if we happen to have received it from a peer. + */ + bgp_mac_remove_ifp_internal(bsm, ifp->name); +} + static void bgp_mac_show_mac_entry(struct hash_backet *backet, void *arg) { struct vty *vty = arg; diff --git a/bgpd/bgp_mac.h b/bgpd/bgp_mac.h index 42a4c7fea1..31a8ef9913 100644 --- a/bgpd/bgp_mac.h +++ b/bgpd/bgp_mac.h @@ -23,5 +23,13 @@ void bgp_mac_init(void); void bgp_mac_finish(void); +/* + * Functions to add/delete the mac entry from the appropriate + * bgp hash's. Additionally to do some additional processing + * to allow the win/loss to be processed. + */ +void bgp_mac_add_mac_entry(struct interface *ifp); +void bgp_mac_del_mac_entry(struct interface *ifp); + void bgp_mac_dump_table(struct vty *vty); #endif diff --git a/bgpd/bgp_zebra.c b/bgpd/bgp_zebra.c index 66d3333739..3c4b219466 100644 --- a/bgpd/bgp_zebra.c +++ b/bgpd/bgp_zebra.c @@ -59,6 +59,7 @@ #include "bgpd/bgp_labelpool.h" #include "bgpd/bgp_pbr.h" #include "bgpd/bgp_evpn_private.h" +#include "bgpd/bgp_mac.h" /* All information about zebra. */ struct zclient *zclient = NULL; @@ -221,6 +222,8 @@ static int bgp_interface_add(int command, struct zclient *zclient, if (!bgp) return 0; + bgp_mac_add_mac_entry(ifp); + bgp_update_interface_nbrs(bgp, ifp, ifp); return 0; } @@ -245,6 +248,8 @@ static int bgp_interface_delete(int command, struct zclient *zclient, if (bgp) bgp_update_interface_nbrs(bgp, ifp, NULL); + bgp_mac_del_mac_entry(ifp); + if_set_index(ifp, IFINDEX_INTERNAL); return 0; } @@ -267,6 +272,8 @@ static int bgp_interface_up(int command, struct zclient *zclient, if (!ifp) return 0; + bgp_mac_add_mac_entry(ifp); + if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Rx Intf up VRF %u IF %s", vrf_id, ifp->name); @@ -300,6 +307,8 @@ static int bgp_interface_down(int command, struct zclient *zclient, if (!ifp) return 0; + bgp_mac_del_mac_entry(ifp); + if (BGP_DEBUG(zebra, ZEBRA)) zlog_debug("Rx Intf down VRF %u IF %s", vrf_id, ifp->name);