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 Interface 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_node
*prn
, *rn
;
141 struct bgp_path_info
*pi
;
143 for (prn
= bgp_table_top(table
); prn
; prn
= bgp_route_next(prn
)) {
144 struct bgp_table
*sub
= prn
->info
;
145 const struct prefix
*prn_p
= bgp_node_get_prefix(prn
);
150 for (rn
= bgp_table_top(sub
); rn
; rn
= bgp_route_next(rn
)) {
152 const struct prefix
*p
= bgp_node_get_prefix(rn
);
153 const struct prefix_evpn
*pevpn
= (const struct prefix_evpn
*)p
;
154 struct prefix_rd prd
;
155 uint32_t num_labels
= 0;
156 mpls_label_t
*label_pnt
= NULL
;
157 struct bgp_route_evpn evpn
;
159 if (pevpn
->family
== AF_EVPN
&&
160 pevpn
->prefix
.route_type
== BGP_EVPN_MAC_IP_ROUTE
&&
161 memcmp(&p
->u
.prefix_evpn
.macip_addr
.mac
,
162 macaddr
, ETH_ALEN
) == 0)
167 for (pi
= rn
->info
; pi
; pi
= pi
->next
) {
168 if (pi
->peer
== peer
)
176 * If the mac address is not the same then
177 * we don't care and since we are looking
179 if ((memcmp(&pi
->attr
->rmac
, macaddr
, ETH_ALEN
) != 0) &&
184 num_labels
= pi
->extra
->num_labels
;
186 label_pnt
= &pi
->extra
->label
[0];
188 prd
.family
= AF_UNSPEC
;
190 memcpy(&prd
.val
, prn_p
->u
.val
, 8);
192 if (CHECK_FLAG(pi
->flags
, BGP_PATH_REMOVED
)) {
193 if (bgp_debug_update(peer
, p
, NULL
, 1)) {
194 char pfx_buf
[BGP_PRD_PATH_STRLEN
];
196 bgp_debug_rdpfxpath2str(
197 AFI_L2VPN
, SAFI_EVPN
, &prd
,
198 p
, label_pnt
, num_labels
,
199 pi
->addpath_rx_id
? 1 : 0,
200 pi
->addpath_rx_id
, pfx_buf
,
203 "%s skip update of %s marked as removed",
204 peer
->host
, pfx_buf
);
209 memcpy(&evpn
, &pi
->attr
->evpn_overlay
, sizeof(evpn
));
210 int32_t ret
= bgp_update(peer
, p
,
212 pi
->attr
, AFI_L2VPN
, SAFI_EVPN
,
214 BGP_ROUTE_NORMAL
, &prd
,
215 label_pnt
, num_labels
,
224 static void bgp_mac_rescan_evpn_table(struct bgp
*bgp
, struct ethaddr
*macaddr
)
226 struct listnode
*node
;
233 for (ALL_LIST_ELEMENTS_RO(bgp
->peer
, node
, peer
)) {
235 if (CHECK_FLAG(peer
->sflags
, PEER_STATUS_GROUP
))
238 if (peer
->status
!= Established
)
241 if (CHECK_FLAG(peer
->af_flags
[afi
][safi
],
242 PEER_FLAG_SOFT_RECONFIG
)) {
243 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
244 zlog_debug("Processing EVPN MAC interface change on peer %s (inbound, soft-reconfig)",
247 bgp_soft_reconfig_in(peer
, afi
, safi
);
249 struct bgp_table
*table
= bgp
->rib
[afi
][safi
];
251 if (bgp_debug_update(peer
, NULL
, NULL
, 1))
252 zlog_debug("Processing EVPN MAC interface change on peer %s",
254 bgp_process_mac_rescan_table(bgp
, peer
, table
, macaddr
);
259 static void bgp_mac_rescan_all_evpn_tables(struct ethaddr
*macaddr
)
261 struct listnode
*node
;
264 for (ALL_LIST_ELEMENTS_RO(bm
->bgp
, node
, bgp
)) {
265 struct bgp_table
*table
= bgp
->rib
[AFI_L2VPN
][SAFI_EVPN
];
268 bgp_mac_rescan_evpn_table(bgp
, macaddr
);
272 static void bgp_mac_remove_ifp_internal(struct bgp_self_mac
*bsm
, char *ifname
,
273 struct ethaddr
*macaddr
)
275 struct listnode
*node
= NULL
;
278 for (ALL_LIST_ELEMENTS_RO(bsm
->ifp_list
, node
, name
)) {
279 if (strcmp(name
, ifname
) == 0)
284 list_delete_node(bsm
->ifp_list
, node
);
285 XFREE(MTYPE_BSM_STRING
, name
);
288 if (bsm
->ifp_list
->count
== 0) {
289 struct ethaddr mac
= *macaddr
;
291 hash_release(bm
->self_mac_hash
, bsm
);
292 list_delete(&bsm
->ifp_list
);
293 XFREE(MTYPE_BSM
, bsm
);
295 bgp_mac_rescan_all_evpn_tables(&mac
);
299 void bgp_mac_add_mac_entry(struct interface
*ifp
)
301 struct bgp_self_mac lookup
;
302 struct bgp_self_mac
*bsm
;
303 struct bgp_self_mac
*old_bsm
;
306 memcpy(&lookup
.macaddr
, &ifp
->hw_addr
, ETH_ALEN
);
307 bsm
= hash_get(bm
->self_mac_hash
, &lookup
, bgp_mac_hash_alloc
);
310 * Does this happen to be a move
312 old_bsm
= bgp_mac_find_interface_name(ifp
->name
);
313 ifname
= XSTRDUP(MTYPE_BSM_STRING
, ifp
->name
);
315 if (bsm
->ifp_list
->count
== 0) {
317 listnode_add(bsm
->ifp_list
, ifname
);
319 bgp_mac_remove_ifp_internal(old_bsm
, ifname
,
323 * If old mac address is the same as the new,
324 * then there is nothing to do here
326 if (old_bsm
== bsm
) {
327 XFREE(MTYPE_BSM_STRING
, ifname
);
332 bgp_mac_remove_ifp_internal(old_bsm
, ifp
->name
,
335 listnode_add(bsm
->ifp_list
, ifname
);
338 bgp_mac_rescan_all_evpn_tables(&bsm
->macaddr
);
341 void bgp_mac_del_mac_entry(struct interface
*ifp
)
343 struct bgp_self_mac lookup
;
344 struct bgp_self_mac
*bsm
;
346 memcpy(&lookup
.macaddr
, &ifp
->hw_addr
, ETH_ALEN
);
347 bsm
= hash_lookup(bm
->self_mac_hash
, &lookup
);
352 * Write code to allow old mac address to no-longer
353 * win if we happen to have received it from a peer.
355 bgp_mac_remove_ifp_internal(bsm
, ifp
->name
, &bsm
->macaddr
);
358 /* This API checks MAC address against any of local
359 * assigned (SVIs) MAC address.
360 * An example: router-mac attribute in any of evpn update
361 * requires to compare against local mac.
363 bool bgp_mac_exist(const struct ethaddr
*mac
)
365 struct bgp_self_mac lookup
;
366 struct bgp_self_mac
*bsm
;
367 static uint8_t tmp
[ETHER_ADDR_STRLEN
] = {0};
369 if (memcmp(mac
, &tmp
, ETH_ALEN
) == 0)
372 memcpy(&lookup
.macaddr
, mac
, ETH_ALEN
);
373 bsm
= hash_lookup(bm
->self_mac_hash
, &lookup
);
380 /* This API checks EVPN type-2 prefix and comapares
381 * mac against any of local assigned (SVIs) MAC
384 bool bgp_mac_entry_exists(const struct prefix
*p
)
386 const struct prefix_evpn
*pevpn
= (const struct prefix_evpn
*)p
;
388 if (pevpn
->family
!= AF_EVPN
)
391 if (pevpn
->prefix
.route_type
!= BGP_EVPN_MAC_IP_ROUTE
)
394 return bgp_mac_exist(&p
->u
.prefix_evpn
.macip_addr
.mac
);
399 static void bgp_mac_show_mac_entry(struct hash_bucket
*bucket
, void *arg
)
401 struct vty
*vty
= arg
;
402 struct bgp_self_mac
*bsm
= bucket
->data
;
403 struct listnode
*node
;
405 char buf_mac
[ETHER_ADDR_STRLEN
];
407 vty_out(vty
, "Mac Address: %s ",
408 prefix_mac2str(&bsm
->macaddr
, buf_mac
, sizeof(buf_mac
)));
410 for (ALL_LIST_ELEMENTS_RO(bsm
->ifp_list
, node
, name
))
411 vty_out(vty
, "%s ", name
);
416 void bgp_mac_dump_table(struct vty
*vty
)
418 hash_iterate(bm
->self_mac_hash
, bgp_mac_show_mac_entry
, vty
);