3 * Copyright (C) 2018 Cumulus Networks, Inc.
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)
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
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
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"
36 DEFINE_MTYPE_STATIC(BGPD
, BSM
, "Mac Hash Entry");
37 DEFINE_MTYPE_STATIC(BGPD
, BSM_STRING
, "Mac Hash Entry Intf String");
40 struct ethaddr macaddr
;
41 struct list
*ifp_list
;
44 static unsigned int bgp_mac_hash_key_make(const void *data
)
46 const struct bgp_self_mac
*bsm
= data
;
48 return jhash(&bsm
->macaddr
, ETH_ALEN
, 0xa5a5dead);
51 static bool bgp_mac_hash_cmp(const void *d1
, const void *d2
)
53 const struct bgp_self_mac
*bsm1
= d1
;
54 const struct bgp_self_mac
*bsm2
= d2
;
56 if (memcmp(&bsm1
->macaddr
, &bsm2
->macaddr
, ETH_ALEN
) == 0)
62 void bgp_mac_init(void)
64 bm
->self_mac_hash
= hash_create(bgp_mac_hash_key_make
, bgp_mac_hash_cmp
,
68 static void bgp_mac_hash_free(void *data
)
70 struct bgp_self_mac
*bsm
= data
;
73 list_delete(&bsm
->ifp_list
);
75 XFREE(MTYPE_BSM
, bsm
);
78 void bgp_mac_finish(void)
80 hash_clean(bm
->self_mac_hash
, bgp_mac_hash_free
);
81 hash_free(bm
->self_mac_hash
);
84 static void bgp_mac_hash_interface_string_del(void *val
)
88 XFREE(MTYPE_BSM_STRING
, data
);
91 static void *bgp_mac_hash_alloc(void *p
)
93 const struct bgp_self_mac
*orig
= p
;
94 struct bgp_self_mac
*bsm
;
96 bsm
= XCALLOC(MTYPE_BSM
, sizeof(struct bgp_self_mac
));
97 memcpy(&bsm
->macaddr
, &orig
->macaddr
, ETH_ALEN
);
99 bsm
->ifp_list
= list_new();
100 bsm
->ifp_list
->del
= bgp_mac_hash_interface_string_del
;
105 struct bgp_mac_find_internal
{
106 struct bgp_self_mac
*bsm
;
110 static void bgp_mac_find_ifp_internal(struct hash_bucket
*bucket
, void *arg
)
112 struct bgp_mac_find_internal
*bmfi
= arg
;
113 struct bgp_self_mac
*bsm
= bucket
->data
;
114 struct listnode
*node
;
117 for (ALL_LIST_ELEMENTS_RO(bsm
->ifp_list
, node
, name
)) {
118 if (strcmp(name
, bmfi
->ifname
) == 0) {
125 static struct bgp_self_mac
*bgp_mac_find_interface_name(const char *ifname
)
127 struct bgp_mac_find_internal bmfi
;
130 bmfi
.ifname
= ifname
;
131 hash_iterate(bm
->self_mac_hash
, bgp_mac_find_ifp_internal
, &bmfi
);
136 static void bgp_process_mac_rescan_table(struct bgp
*bgp
, struct peer
*peer
,
137 struct bgp_table
*table
,
138 struct ethaddr
*macaddr
)
140 struct bgp_dest
*pdest
, *dest
;
141 struct bgp_path_info
*pi
;
143 for (pdest
= bgp_table_top(table
); pdest
;
144 pdest
= bgp_route_next(pdest
)) {
145 struct bgp_table
*sub
= pdest
->info
;
146 const struct prefix
*pdest_p
= bgp_dest_get_prefix(pdest
);
151 for (dest
= bgp_table_top(sub
); dest
;
152 dest
= bgp_route_next(dest
)) {
154 const struct prefix
*p
= bgp_dest_get_prefix(dest
);
155 struct prefix_evpn
*pevpn
= (struct prefix_evpn
*)dest
;
156 struct prefix_rd prd
;
157 uint32_t num_labels
= 0;
158 mpls_label_t
*label_pnt
= NULL
;
159 struct bgp_route_evpn
*evpn
;
161 if (pevpn
->family
== AF_EVPN
162 && pevpn
->prefix
.route_type
== BGP_EVPN_MAC_IP_ROUTE
163 && memcmp(&p
->u
.prefix_evpn
.macip_addr
.mac
, macaddr
,
166 dest_affected
= true;
168 dest_affected
= false;
170 for (pi
= dest
->info
; pi
; pi
= pi
->next
) {
171 if (pi
->peer
== peer
)
179 * If the mac address is not the same then
180 * we don't care and since we are looking
182 if ((memcmp(&pi
->attr
->rmac
, macaddr
, ETH_ALEN
) != 0)
187 num_labels
= pi
->extra
->num_labels
;
189 label_pnt
= &pi
->extra
->label
[0];
191 prd
.family
= AF_UNSPEC
;
193 memcpy(&prd
.val
, pdest_p
->u
.val
, 8);
195 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
196 if (bgp_debug_update(peer
, p
, NULL
, 1)) {
197 char pfx_buf
[BGP_PRD_PATH_STRLEN
];
199 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
));
206 "%s skip update of %s marked as removed",
207 peer
->host
, pfx_buf
);
212 memcpy(&evpn
, bgp_attr_get_evpn_overlay(pi
->attr
),
214 int32_t ret
= bgp_update(peer
, p
,
216 pi
->attr
, AFI_L2VPN
, SAFI_EVPN
,
218 BGP_ROUTE_NORMAL
, &prd
,
219 label_pnt
, num_labels
,
223 bgp_dest_unlock_node(dest
);
228 static void bgp_mac_rescan_evpn_table(struct bgp
*bgp
, struct ethaddr
*macaddr
)
230 struct listnode
*node
;
237 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
239 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
))
242 if (!peer_established(peer
))
245 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
246 PEER_FLAG_SOFT_RECONFIG
)) {
247 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
248 zlog_debug("Processing EVPN MAC interface change on peer %s (inbound, soft-reconfig)",
251 bgp_soft_reconfig_in(peer
, afi
, safi
);
253 struct bgp_table
*table
= bgp
->rib
[afi
][safi
];
255 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
256 zlog_debug("Processing EVPN MAC interface change on peer %s",
258 bgp_process_mac_rescan_table(bgp
, peer
, table
, macaddr
);
263 static void bgp_mac_rescan_all_evpn_tables(struct ethaddr
*macaddr
)
265 struct listnode
*node
;
268 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, node
, bgp
)) {
269 struct bgp_table
*table
= bgp
->rib
[AFI_L2VPN
][SAFI_EVPN
];
272 bgp_mac_rescan_evpn_table(bgp
, macaddr
);
276 static void bgp_mac_remove_ifp_internal(struct bgp_self_mac
*bsm
, char *ifname
,
277 struct ethaddr
*macaddr
)
279 struct listnode
*node
= NULL
;
282 for (ALL_LIST_ELEMENTS_RO(bsm
->ifp_list
, node
, name
)) {
283 if (strcmp(name
, ifname
) == 0)
288 list_delete_node(bsm
->ifp_list
, node
);
289 XFREE(MTYPE_BSM_STRING
, name
);
292 if (bsm
->ifp_list
->count
== 0) {
293 struct ethaddr mac
= *macaddr
;
295 hash_release(bm
->self_mac_hash
, bsm
);
296 list_delete(&bsm
->ifp_list
);
297 XFREE(MTYPE_BSM
, bsm
);
299 bgp_mac_rescan_all_evpn_tables(&mac
);
303 void bgp_mac_add_mac_entry(struct interface
*ifp
)
305 struct bgp_self_mac lookup
;
306 struct bgp_self_mac
*bsm
;
307 struct bgp_self_mac
*old_bsm
;
310 memcpy(&lookup
.macaddr
, &ifp
->hw_addr
, ETH_ALEN
);
311 bsm
= hash_get(bm
->self_mac_hash
, &lookup
, bgp_mac_hash_alloc
);
314 * Does this happen to be a move
316 old_bsm
= bgp_mac_find_interface_name(ifp
->name
);
317 ifname
= XSTRDUP(MTYPE_BSM_STRING
, ifp
->name
);
319 if (bsm
->ifp_list
->count
== 0) {
321 listnode_add(bsm
->ifp_list
, ifname
);
323 bgp_mac_remove_ifp_internal(old_bsm
, ifname
,
327 * If old mac address is the same as the new,
328 * then there is nothing to do here
330 if (old_bsm
== bsm
) {
331 XFREE(MTYPE_BSM_STRING
, ifname
);
336 bgp_mac_remove_ifp_internal(old_bsm
, ifp
->name
,
339 listnode_add(bsm
->ifp_list
, ifname
);
342 bgp_mac_rescan_all_evpn_tables(&bsm
->macaddr
);
345 void bgp_mac_del_mac_entry(struct interface
*ifp
)
347 struct bgp_self_mac lookup
;
348 struct bgp_self_mac
*bsm
;
350 memcpy(&lookup
.macaddr
, &ifp
->hw_addr
, ETH_ALEN
);
351 bsm
= hash_lookup(bm
->self_mac_hash
, &lookup
);
356 * Write code to allow old mac address to no-longer
357 * win if we happen to have received it from a peer.
359 bgp_mac_remove_ifp_internal(bsm
, ifp
->name
, &bsm
->macaddr
);
362 /* This API checks MAC address against any of local
363 * assigned (SVIs) MAC address.
364 * An example: router-mac attribute in any of evpn update
365 * requires to compare against local mac.
367 bool bgp_mac_exist(const struct ethaddr
*mac
)
369 struct bgp_self_mac lookup
;
370 struct bgp_self_mac
*bsm
;
371 static uint8_t tmp
[ETHER_ADDR_STRLEN
] = {0};
373 if (memcmp(mac
, &tmp
, ETH_ALEN
) == 0)
376 memcpy(&lookup
.macaddr
, mac
, ETH_ALEN
);
377 bsm
= hash_lookup(bm
->self_mac_hash
, &lookup
);
384 /* This API checks EVPN type-2 prefix and comapares
385 * mac against any of local assigned (SVIs) MAC
388 bool bgp_mac_entry_exists(const struct prefix
*p
)
390 const struct prefix_evpn
*pevpn
= (const struct prefix_evpn
*)p
;
392 if (pevpn
->family
!= AF_EVPN
)
395 if (pevpn
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
398 return bgp_mac_exist(&p
->u
.prefix_evpn
.macip_addr
.mac
);
403 static void bgp_mac_show_mac_entry(struct hash_bucket
*bucket
, void *arg
)
405 struct vty
*vty
= arg
;
406 struct bgp_self_mac
*bsm
= bucket
->data
;
407 struct listnode
*node
;
409 char buf_mac
[ETHER_ADDR_STRLEN
];
411 vty_out(vty
, "Mac Address: %s ",
412 prefix_mac2str(&bsm
->macaddr
, buf_mac
, sizeof(buf_mac
)));
414 for (ALL_LIST_ELEMENTS_RO(bsm
->ifp_list
, node
, name
))
415 vty_out(vty
, "%s ", name
);
420 void bgp_mac_dump_table(struct vty
*vty
)
422 hash_iterate(bm
->self_mac_hash
, bgp_mac_show_mac_entry
, vty
);