back to topotato report
topotato coverage report
Current view: top level - bgpd - bgp_mac.c (source / functions) Hit Total Coverage
Test: test_bgp_minimum_holdtime.py::TestBGPMinimumHoldtime Lines: 109 192 56.8 %
Date: 2023-02-24 18:37:25 Functions: 18 23 78.3 %

          Line data    Source code
       1             : /*
       2             :  * BGPd - Mac hash code
       3             :  * Copyright (C) 2018 Cumulus Networks, Inc.
       4             :  *               Donald Sharp
       5             :  *
       6             :  * This program is free software; you can redistribute it and/or modify it
       7             :  * under the terms of the GNU General Public License as published by the Free
       8             :  * Software Foundation; either version 2 of the License, or (at your option)
       9             :  * any later version.
      10             :  *
      11             :  * This program is distributed in the hope that it will be useful, but WITHOUT
      12             :  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
      13             :  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
      14             :  * more details.
      15             :  *
      16             :  * You should have received a copy of the GNU General Public License along
      17             :  * with this program; see the file COPYING; if not, write to the Free Software
      18             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      19             :  */
      20             : #include <zebra.h>
      21             : 
      22             : #include <jhash.h>
      23             : #include <hash.h>
      24             : #include <prefix.h>
      25             : #include <memory.h>
      26             : 
      27             : #include "bgpd/bgpd.h"
      28             : #include "bgpd/bgp_mac.h"
      29             : #include "bgpd/bgp_memory.h"
      30             : #include "bgpd/bgp_route.h"
      31             : #include "bgpd/bgp_packet.h"
      32             : #include "bgpd/bgp_rd.h"
      33             : #include "bgpd/bgp_debug.h"
      34             : #include "bgpd/bgp_evpn_private.h"
      35             : 
      36           6 : DEFINE_MTYPE_STATIC(BGPD, BSM, "Mac Hash Entry");
      37           6 : DEFINE_MTYPE_STATIC(BGPD, BSM_STRING, "Mac Hash Entry Intf String");
      38             : 
      39             : struct bgp_self_mac {
      40             :         struct ethaddr macaddr;
      41             :         struct list *ifp_list;
      42             : };
      43             : 
      44          19 : static unsigned int bgp_mac_hash_key_make(const void *data)
      45             : {
      46          19 :         const struct bgp_self_mac *bsm = data;
      47             : 
      48          19 :         return jhash(&bsm->macaddr, ETH_ALEN, 0xa5a5dead);
      49             : }
      50             : 
      51          13 : static bool bgp_mac_hash_cmp(const void *d1, const void *d2)
      52             : {
      53          13 :         const struct bgp_self_mac *bsm1 = d1;
      54          13 :         const struct bgp_self_mac *bsm2 = d2;
      55             : 
      56          13 :         if (memcmp(&bsm1->macaddr, &bsm2->macaddr, ETH_ALEN) == 0)
      57          13 :                 return true;
      58             : 
      59             :         return false;
      60             : }
      61             : 
      62           2 : void bgp_mac_init(void)
      63             : {
      64           2 :         bm->self_mac_hash = hash_create(bgp_mac_hash_key_make, bgp_mac_hash_cmp,
      65             :                                         "BGP MAC Hash");
      66           2 : }
      67             : 
      68           4 : static void bgp_mac_hash_free(void *data)
      69             : {
      70           4 :         struct bgp_self_mac *bsm = data;
      71             : 
      72           4 :         if (bsm->ifp_list)
      73           4 :                 list_delete(&bsm->ifp_list);
      74             : 
      75           4 :         XFREE(MTYPE_BSM, bsm);
      76           4 : }
      77             : 
      78           2 : void bgp_mac_finish(void)
      79             : {
      80           2 :         hash_clean(bm->self_mac_hash, bgp_mac_hash_free);
      81           2 :         hash_free(bm->self_mac_hash);
      82           2 : }
      83             : 
      84           4 : static void bgp_mac_hash_interface_string_del(void *val)
      85             : {
      86           4 :         char *data = val;
      87             : 
      88           4 :         XFREE(MTYPE_BSM_STRING, data);
      89           4 : }
      90             : 
      91           5 : static void *bgp_mac_hash_alloc(void *p)
      92             : {
      93           5 :         const struct bgp_self_mac *orig = p;
      94           5 :         struct bgp_self_mac *bsm;
      95             : 
      96           5 :         bsm = XCALLOC(MTYPE_BSM, sizeof(struct bgp_self_mac));
      97           5 :         memcpy(&bsm->macaddr, &orig->macaddr, ETH_ALEN);
      98             : 
      99           5 :         bsm->ifp_list = list_new();
     100           5 :         bsm->ifp_list->del = bgp_mac_hash_interface_string_del;
     101             : 
     102           5 :         return bsm;
     103             : }
     104             : 
     105             : struct bgp_mac_find_internal {
     106             :         struct bgp_self_mac *bsm;
     107             :         const char *ifname;
     108             : };
     109             : 
     110          28 : static void bgp_mac_find_ifp_internal(struct hash_bucket *bucket, void *arg)
     111             : {
     112          28 :         struct bgp_mac_find_internal *bmfi = arg;
     113          28 :         struct bgp_self_mac *bsm = bucket->data;
     114          28 :         struct listnode *node;
     115          28 :         char *name;
     116             : 
     117          68 :         for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name)) {
     118          23 :                 if (strcmp(name, bmfi->ifname) == 0) {
     119          11 :                         bmfi->bsm = bsm;
     120          11 :                         return;
     121             :                 }
     122             :         }
     123             : }
     124             : 
     125          16 : static struct bgp_self_mac *bgp_mac_find_interface_name(const char *ifname)
     126             : {
     127          16 :         struct bgp_mac_find_internal bmfi;
     128             : 
     129          16 :         bmfi.bsm = NULL;
     130          16 :         bmfi.ifname = ifname;
     131          16 :         hash_iterate(bm->self_mac_hash, bgp_mac_find_ifp_internal, &bmfi);
     132             : 
     133          16 :         return bmfi.bsm;
     134             : }
     135             : 
     136           0 : static void bgp_process_mac_rescan_table(struct bgp *bgp, struct peer *peer,
     137             :                                          struct bgp_table *table,
     138             :                                          struct ethaddr *macaddr)
     139             : {
     140           0 :         struct bgp_dest *pdest, *dest;
     141           0 :         struct bgp_path_info *pi;
     142             : 
     143           0 :         for (pdest = bgp_table_top(table); pdest;
     144           0 :              pdest = bgp_route_next(pdest)) {
     145           0 :                 struct bgp_table *sub = pdest->info;
     146           0 :                 const struct prefix *pdest_p = bgp_dest_get_prefix(pdest);
     147             : 
     148           0 :                 if (!sub)
     149           0 :                         continue;
     150             : 
     151           0 :                 for (dest = bgp_table_top(sub); dest;
     152           0 :                      dest = bgp_route_next(dest)) {
     153           0 :                         bool dest_affected;
     154           0 :                         const struct prefix *p = bgp_dest_get_prefix(dest);
     155           0 :                         struct prefix_evpn *pevpn = (struct prefix_evpn *)dest;
     156           0 :                         struct prefix_rd prd;
     157           0 :                         uint32_t num_labels = 0;
     158           0 :                         mpls_label_t *label_pnt = NULL;
     159           0 :                         struct bgp_route_evpn *evpn;
     160             : 
     161           0 :                         if (pevpn->family == AF_EVPN
     162           0 :                             && pevpn->prefix.route_type == BGP_EVPN_MAC_IP_ROUTE
     163           0 :                             && memcmp(&p->u.prefix_evpn.macip_addr.mac, macaddr,
     164             :                                       ETH_ALEN)
     165             :                                        == 0)
     166             :                                 dest_affected = true;
     167             :                         else
     168           0 :                                 dest_affected = false;
     169             : 
     170           0 :                         for (pi = dest->info; pi; pi = pi->next) {
     171           0 :                                 if (pi->peer == peer)
     172             :                                         break;
     173             :                         }
     174             : 
     175           0 :                         if (!pi)
     176           0 :                                 continue;
     177             : 
     178             :                         /*
     179             :                          * If the mac address is not the same then
     180             :                          * we don't care and since we are looking
     181             :                          */
     182           0 :                         if ((memcmp(&pi->attr->rmac, macaddr, ETH_ALEN) != 0)
     183           0 :                             && !dest_affected)
     184           0 :                                 continue;
     185             : 
     186           0 :                         if (pi->extra)
     187           0 :                                 num_labels = pi->extra->num_labels;
     188           0 :                         if (num_labels)
     189           0 :                                 label_pnt = &pi->extra->label[0];
     190             : 
     191           0 :                         prd.family = AF_UNSPEC;
     192           0 :                         prd.prefixlen = 64;
     193           0 :                         memcpy(&prd.val, pdest_p->u.val, 8);
     194             : 
     195           0 :                         if (CHECK_FLAG(pi->flags, BGP_PATH_REMOVED)) {
     196           0 :                                 if (bgp_debug_update(peer, p, NULL, 1)) {
     197           0 :                                         char pfx_buf[BGP_PRD_PATH_STRLEN];
     198             : 
     199           0 :                                         bgp_debug_rdpfxpath2str(
     200             :                                                 AFI_L2VPN, SAFI_EVPN, &prd,
     201             :                                                 p, label_pnt, num_labels,
     202             :                                                 pi->addpath_rx_id ? 1 : 0,
     203             :                                                 pi->addpath_rx_id, NULL,
     204             :                                                 pfx_buf, sizeof(pfx_buf));
     205           0 :                                         zlog_debug(
     206             :                                                    "%s skip update of %s marked as removed",
     207             :                                                    peer->host, pfx_buf);
     208             :                                 }
     209           0 :                                 continue;
     210             :                         }
     211             : 
     212           0 :                         memcpy(&evpn, bgp_attr_get_evpn_overlay(pi->attr),
     213             :                                sizeof(evpn));
     214           0 :                         bgp_update(peer, p, pi->addpath_rx_id, pi->attr,
     215             :                                    AFI_L2VPN, SAFI_EVPN, ZEBRA_ROUTE_BGP,
     216             :                                    BGP_ROUTE_NORMAL, &prd, label_pnt,
     217             :                                    num_labels, 1, evpn);
     218             :                 }
     219             :         }
     220           0 : }
     221             : 
     222           6 : static void bgp_mac_rescan_evpn_table(struct bgp *bgp, struct ethaddr *macaddr)
     223             : {
     224           6 :         struct listnode *node;
     225           6 :         struct peer *peer;
     226           6 :         safi_t safi;
     227           6 :         afi_t afi;
     228             : 
     229           6 :         afi = AFI_L2VPN;
     230           6 :         safi = SAFI_EVPN;
     231          18 :         for (ALL_LIST_ELEMENTS_RO(bgp->peer, node, peer)) {
     232             : 
     233           6 :                 if (CHECK_FLAG(peer->sflags, PEER_STATUS_GROUP))
     234           0 :                         continue;
     235             : 
     236           6 :                 if (!peer_established(peer))
     237           6 :                         continue;
     238             : 
     239           0 :                 if (bgp_debug_update(peer, NULL, NULL, 1))
     240           0 :                         zlog_debug(
     241             :                                 "Processing EVPN MAC interface change on peer %s %s",
     242             :                                 peer->host,
     243             :                                 CHECK_FLAG(peer->af_flags[afi][safi],
     244             :                                            PEER_FLAG_SOFT_RECONFIG)
     245             :                                         ? "(inbound, soft-reconfig)"
     246             :                                         : "");
     247             : 
     248           0 :                 if (!bgp_soft_reconfig_in(peer, afi, safi)) {
     249           0 :                         struct bgp_table *table = bgp->rib[afi][safi];
     250             : 
     251           0 :                         bgp_process_mac_rescan_table(bgp, peer, table, macaddr);
     252             :                 }
     253             :         }
     254           6 : }
     255             : 
     256           6 : static void bgp_mac_rescan_all_evpn_tables(struct ethaddr *macaddr)
     257             : {
     258           6 :         struct listnode *node;
     259           6 :         struct bgp *bgp;
     260             : 
     261          18 :         for (ALL_LIST_ELEMENTS_RO(bm->bgp, node, bgp)) {
     262           6 :                 struct bgp_table *table = bgp->rib[AFI_L2VPN][SAFI_EVPN];
     263             : 
     264           6 :                 if (table)
     265           6 :                         bgp_mac_rescan_evpn_table(bgp, macaddr);
     266             :         }
     267           6 : }
     268             : 
     269           1 : static void bgp_mac_remove_ifp_internal(struct bgp_self_mac *bsm, char *ifname,
     270             :                                         struct ethaddr *macaddr)
     271             : {
     272           1 :         struct listnode *node = NULL;
     273           1 :         char *name;
     274             : 
     275           2 :         for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name)) {
     276           1 :                 if (strcmp(name, ifname) == 0)
     277             :                         break;
     278             :         }
     279             : 
     280           1 :         if (node) {
     281           1 :                 list_delete_node(bsm->ifp_list, node);
     282           1 :                 XFREE(MTYPE_BSM_STRING, name);
     283             :         }
     284             : 
     285           1 :         if (bsm->ifp_list->count == 0) {
     286           1 :                 struct ethaddr mac = *macaddr;
     287             : 
     288           1 :                 hash_release(bm->self_mac_hash, bsm);
     289           1 :                 list_delete(&bsm->ifp_list);
     290           1 :                 XFREE(MTYPE_BSM, bsm);
     291             : 
     292           1 :                 bgp_mac_rescan_all_evpn_tables(&mac);
     293             :         }
     294           1 : }
     295             : 
     296          16 : void bgp_mac_add_mac_entry(struct interface *ifp)
     297             : {
     298          16 :         struct bgp_self_mac lookup;
     299          16 :         struct bgp_self_mac *bsm;
     300          16 :         struct bgp_self_mac *old_bsm;
     301          16 :         char *ifname;
     302             : 
     303          16 :         memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN);
     304          16 :         bsm = hash_get(bm->self_mac_hash, &lookup, bgp_mac_hash_alloc);
     305             : 
     306             :         /*
     307             :          * Does this happen to be a move
     308             :          */
     309          16 :         old_bsm = bgp_mac_find_interface_name(ifp->name);
     310          16 :         ifname = XSTRDUP(MTYPE_BSM_STRING, ifp->name);
     311             : 
     312          16 :         if (bsm->ifp_list->count == 0) {
     313             : 
     314           5 :                 listnode_add(bsm->ifp_list, ifname);
     315           5 :                 if (old_bsm)
     316           0 :                         bgp_mac_remove_ifp_internal(old_bsm, ifname,
     317             :                                                     &old_bsm->macaddr);
     318             :         } else {
     319             :                 /*
     320             :                  * If old mac address is the same as the new,
     321             :                  * then there is nothing to do here
     322             :                  */
     323          11 :                 if (old_bsm == bsm) {
     324          11 :                         XFREE(MTYPE_BSM_STRING, ifname);
     325          11 :                         return;
     326             :                 }
     327             : 
     328           0 :                 if (old_bsm)
     329           0 :                         bgp_mac_remove_ifp_internal(old_bsm, ifp->name,
     330             :                                                     &old_bsm->macaddr);
     331             : 
     332           0 :                 listnode_add(bsm->ifp_list, ifname);
     333             :         }
     334             : 
     335           5 :         bgp_mac_rescan_all_evpn_tables(&bsm->macaddr);
     336             : }
     337             : 
     338           2 : void bgp_mac_del_mac_entry(struct interface *ifp)
     339             : {
     340           2 :         struct bgp_self_mac lookup;
     341           2 :         struct bgp_self_mac *bsm;
     342             : 
     343           2 :         memcpy(&lookup.macaddr, &ifp->hw_addr, ETH_ALEN);
     344           2 :         bsm = hash_lookup(bm->self_mac_hash, &lookup);
     345           2 :         if (!bsm)
     346           1 :                 return;
     347             : 
     348             :         /*
     349             :          * Write code to allow old mac address to no-longer
     350             :          * win if we happen to have received it from a peer.
     351             :          */
     352           1 :         bgp_mac_remove_ifp_internal(bsm, ifp->name, &bsm->macaddr);
     353             : }
     354             : 
     355             : /* This API checks MAC address against any of local
     356             :  * assigned (SVIs) MAC address.
     357             :  * An example: router-mac attribute in any of evpn update
     358             :  * requires to compare against local mac.
     359             :  */
     360           0 : bool bgp_mac_exist(const struct ethaddr *mac)
     361             : {
     362           0 :         struct bgp_self_mac lookup;
     363           0 :         struct bgp_self_mac *bsm;
     364           0 :         static uint8_t tmp [ETHER_ADDR_STRLEN] = {0};
     365             : 
     366           0 :         if (memcmp(mac, &tmp, ETH_ALEN) == 0)
     367             :                 return false;
     368             : 
     369           0 :         memcpy(&lookup.macaddr, mac, ETH_ALEN);
     370           0 :         bsm = hash_lookup(bm->self_mac_hash, &lookup);
     371           0 :         if (!bsm)
     372             :                 return false;
     373             : 
     374             :         return true;
     375             : }
     376             : 
     377             : /* This API checks EVPN type-2 prefix and comapares
     378             :  * mac against any of local assigned (SVIs) MAC
     379             :  * address.
     380             :  */
     381           0 : bool bgp_mac_entry_exists(const struct prefix *p)
     382             : {
     383           0 :         const struct prefix_evpn *pevpn = (const struct prefix_evpn *)p;
     384             : 
     385           0 :         if (pevpn->family != AF_EVPN)
     386             :                 return false;
     387             : 
     388           0 :         if (pevpn->prefix.route_type != BGP_EVPN_MAC_IP_ROUTE)
     389             :                 return false;
     390             : 
     391           0 :         return bgp_mac_exist(&p->u.prefix_evpn.macip_addr.mac);
     392             : 
     393             :         return true;
     394             : }
     395             : 
     396           0 : static void bgp_mac_show_mac_entry(struct hash_bucket *bucket, void *arg)
     397             : {
     398           0 :         struct vty *vty = arg;
     399           0 :         struct bgp_self_mac *bsm = bucket->data;
     400           0 :         struct listnode *node;
     401           0 :         char *name;
     402           0 :         char buf_mac[ETHER_ADDR_STRLEN];
     403             : 
     404           0 :         vty_out(vty, "Mac Address: %s ",
     405           0 :                 prefix_mac2str(&bsm->macaddr, buf_mac, sizeof(buf_mac)));
     406             : 
     407           0 :         for (ALL_LIST_ELEMENTS_RO(bsm->ifp_list, node, name))
     408           0 :                 vty_out(vty, "%s ", name);
     409             : 
     410           0 :         vty_out(vty, "\n");
     411           0 : }
     412             : 
     413           0 : void bgp_mac_dump_table(struct vty *vty)
     414             : {
     415           0 :         hash_iterate(bm->self_mac_hash, bgp_mac_show_mac_entry, vty);
     416           0 : }

Generated by: LCOV version v1.16-topotato